Я пытаюсь определить собственное сокращение для векторов сложных , следуя этому ответу на вопрос Уменьшение массива в OpenMP.

Но размер моих векторов не фиксируется во время компиляции, поэтому я не уверен, как определить инициализатор для вектора в прагме declare reduction. То есть я просто не могу

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];
      }
    }
}
7
mbed_dev 14 Апр 2015 в 20:16
1
Ваши вопросы звучат так, будто я мог бы быть интересным, но я действительно не знаю, о чем вы спрашиваете. Вам нужно больше кода, меньше слов, и код должен быть общим и не должен содержать подробностей, о которых вы, вероятно, знаете.
 – 
Z boson
15 Апр 2015 в 10:45
Чтобы дать ему свою длину вместо int S_private[10] = {0};, сделайте int *S_private = new int[n](), а затем после критического участка сделайте delete[] S_private.
 – 
Z boson
15 Апр 2015 в 10:47
Также я получаю рубку по вектору, вы имеете в виду не динамический массив (std :: vector), а математический вектор. Вы выбрали вектор, который предназначен для динамических массивов. Вы действительно этого хотите? Мне непонятен ваш вопрос.
 – 
Z boson
15 Апр 2015 в 10:51
Здравствуйте, я добавил код. Надеюсь, это как-то легче понять. Я использую std :: vector для вычислений БПФ, а также неправильно использую их для функций fftw, потому что, поскольку последняя версия допускает перекрытие их типов собственными типами, как указано выше
 – 
mbed_dev
15 Апр 2015 в 19:08

1 ответ

Лучший ответ

Вам нужно немного покопаться, чтобы найти его в Интернете прямо сейчас, но в разделе 2.15 документа OpenMP Standard, где обсуждаются объявленные пользователем сокращения, вы обнаружите, что «специальный идентификатор omp_orig также может появиться в предложении инициализатора, и он будет относиться к хранилищу исходной переменной, которая будет уменьшена».

Таким образом, вы можете использовать initializer (omp_priv=TCmplxVec(omp_orig.size(),0)) или просто initalizer ( omp_priv(omp_orig) ) для инициализации вектора при редукции.

Итак, следующие работы (обратите внимание, что вам не нужно писать свою собственную процедуру; вы можете использовать std :: transform и std :: plus для добавления ваших векторов; вы также можете использовать std :: valarray, а не векторы, в зависимости от того, как вы используете их, для которых уже определен оператор +):

#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)
8
Jonathan Dursi 16 Апр 2015 в 14:12
Спасибо за отличный ответ и ссылку на стандарт OpenMP!
 – 
mbed_dev
16 Апр 2015 в 10:05