用户定义的不同大小向量的减少
User Defined Reduction on vector of varying size
我正在尝试为复数 的向量定义我自己的缩减,遵循this answer to the question Reducing on array in OpenMP。
但是我的向量的大小在编译时不是固定的,所以我不确定如何在 declare reduction
pragma 中定义向量的初始值设定项。也就是说,我不能只拥有
initializer( omp_priv=TComplexVector(10,0) )
但是向量需要初始化程序。
如何在 运行 时将我需要的向量大小传递给初始化子句?到目前为止我所拥有的如下:
typedef std::vector<complex<float>> TCmplxVec;
void ComplexAdd(TCmplxVec & x,TCmplxVec & y){
for (int i=0;i<x.size();i++)
{
x.real()+= y.real();
//... same for imaginary part and other operations
}
}
#pragma omp declare reduction(AddCmplx: TCmplxVec: \
ComplexAdd(&omp_out, &omp_in)) initializer( \
omp_priv={TCmplxVec(**here I want a variable length**,0} )
void DoSomeOperation ()
{
//TCmplxVec vec is empty and anotherVec not
//so each thread runs the inner loop serially
#pragma omp parallel for reduction(AddCmplx: vec)
for ( n=0 ; n<10 ; ++n )
{
for (m=0; m<=someLength; ++m){
vec[m] += anotherVec[m+someOffset dependend on n and else];
}
}
}
您现在必须深入挖掘才能在网上找到它,但是在 OpenMP Standard 的第 2.15 节中讨论了用户声明的减少,您会发现 "The special identifier omp_orig can also appear in the initializer-clause and it will refer to the storage of the original variable to be reduced."
因此您可以使用 initializer (omp_priv=TCmplxVec(omp_orig.size(),0))
,或者只是 initalizer ( omp_priv(omp_orig) )
来初始化缩减中的向量。
所以下面的工作(请注意,您不需要编写自己的例程;您可以使用 std::transform 和 std::plus 添加您的向量;您也可以使用 std::valarray 而不是向量,这取决于你如何使用它们,它已经定义了 operator+):
#include <complex>
#include <vector>
#include <algorithm>
#include <functional>
#include <iostream>
#include <omp.h>
typedef std::vector< std::complex<float> > TCmplxVec;
#pragma omp declare reduction( + : TCmplxVec : \
std::transform(omp_in.begin( ), omp_in.end( ), \
omp_out.begin( ), omp_out.begin( ), \
std::plus< std::complex<float> >( )) ) \
initializer (omp_priv(omp_orig))
int main(int argc, char *argv[]) {
int size;
if (argc < 2)
size = 10;
else
size = atoi(argv[1]);
TCmplxVec result(size,0);
#pragma omp parallel reduction( + : result )
{
int tid=omp_get_thread_num();
for (int i=0; i<std::min(tid+1,size); i++)
result[i] += tid;
}
for (int i=0; i<size; i++)
std::cout << i << "\t" << result[i] << std::endl;
return 0;
}
运行 这给出了
$ OMP_NUM_THREADS=1 ./reduction 8
0 (0,0)
1 (0,0)
2 (0,0)
3 (0,0)
4 (0,0)
5 (0,0)
6 (0,0)
7 (0,0)
$ OMP_NUM_THREADS=4 ./reduction 8
0 (6,0)
1 (6,0)
2 (5,0)
3 (3,0)
4 (0,0)
5 (0,0)
6 (0,0)
7 (0,0)
$ OMP_NUM_THREADS=8 ./reduction 8
0 (28,0)
1 (28,0)
2 (27,0)
3 (25,0)
4 (22,0)
5 (18,0)
6 (13,0)
7 (7,0)
我正在尝试为复数
但是我的向量的大小在编译时不是固定的,所以我不确定如何在 declare reduction
pragma 中定义向量的初始值设定项。也就是说,我不能只拥有
initializer( omp_priv=TComplexVector(10,0) )
但是向量需要初始化程序。
如何在 运行 时将我需要的向量大小传递给初始化子句?到目前为止我所拥有的如下:
typedef std::vector<complex<float>> TCmplxVec;
void ComplexAdd(TCmplxVec & x,TCmplxVec & y){
for (int i=0;i<x.size();i++)
{
x.real()+= y.real();
//... same for imaginary part and other operations
}
}
#pragma omp declare reduction(AddCmplx: TCmplxVec: \
ComplexAdd(&omp_out, &omp_in)) initializer( \
omp_priv={TCmplxVec(**here I want a variable length**,0} )
void DoSomeOperation ()
{
//TCmplxVec vec is empty and anotherVec not
//so each thread runs the inner loop serially
#pragma omp parallel for reduction(AddCmplx: vec)
for ( n=0 ; n<10 ; ++n )
{
for (m=0; m<=someLength; ++m){
vec[m] += anotherVec[m+someOffset dependend on n and else];
}
}
}
您现在必须深入挖掘才能在网上找到它,但是在 OpenMP Standard 的第 2.15 节中讨论了用户声明的减少,您会发现 "The special identifier omp_orig can also appear in the initializer-clause and it will refer to the storage of the original variable to be reduced."
因此您可以使用 initializer (omp_priv=TCmplxVec(omp_orig.size(),0))
,或者只是 initalizer ( omp_priv(omp_orig) )
来初始化缩减中的向量。
所以下面的工作(请注意,您不需要编写自己的例程;您可以使用 std::transform 和 std::plus 添加您的向量;您也可以使用 std::valarray 而不是向量,这取决于你如何使用它们,它已经定义了 operator+):
#include <complex>
#include <vector>
#include <algorithm>
#include <functional>
#include <iostream>
#include <omp.h>
typedef std::vector< std::complex<float> > TCmplxVec;
#pragma omp declare reduction( + : TCmplxVec : \
std::transform(omp_in.begin( ), omp_in.end( ), \
omp_out.begin( ), omp_out.begin( ), \
std::plus< std::complex<float> >( )) ) \
initializer (omp_priv(omp_orig))
int main(int argc, char *argv[]) {
int size;
if (argc < 2)
size = 10;
else
size = atoi(argv[1]);
TCmplxVec result(size,0);
#pragma omp parallel reduction( + : result )
{
int tid=omp_get_thread_num();
for (int i=0; i<std::min(tid+1,size); i++)
result[i] += tid;
}
for (int i=0; i<size; i++)
std::cout << i << "\t" << result[i] << std::endl;
return 0;
}
运行 这给出了
$ OMP_NUM_THREADS=1 ./reduction 8
0 (0,0)
1 (0,0)
2 (0,0)
3 (0,0)
4 (0,0)
5 (0,0)
6 (0,0)
7 (0,0)
$ OMP_NUM_THREADS=4 ./reduction 8
0 (6,0)
1 (6,0)
2 (5,0)
3 (3,0)
4 (0,0)
5 (0,0)
6 (0,0)
7 (0,0)
$ OMP_NUM_THREADS=8 ./reduction 8
0 (28,0)
1 (28,0)
2 (27,0)
3 (25,0)
4 (22,0)
5 (18,0)
6 (13,0)
7 (7,0)