2013-04-04 1 views
1

Я пытаюсь оптимизировать свой код, реализуя для циклов на потоках графического процессора. Я пытаюсь устранить два цикла, используя thrust :: transform. Код в C++ выглядит следующим образом:Замена for-loops using thrust :: transform

ka_index = 0; 
    for (int i = 0; i < N_gene; i++) 
    { 
     for (int j = 0; j < n_ka_d[i]; j++) 
     { 
      co0 = get_coeff0(ka_vec_d[ka_index]); 
      act[i] += (co0*ka_val_d[ka_index]); 
      ka_index++; 
     } 
     act[i] = pow(act[i],n); 
    } 

Я оценки со-efficients для обыкновенного дифференциального уравнения (ОДУ) в вышеуказанных петель и передали все данные на устройстве с помощью тяги. Рассмотрим случай, когда число генов представлено N_gene. Кулак для цикла должен запускать N_gene количество раз. Второе для цикла ограничено количеством активаторов (других дружественных генов в генофонде) каждого гена. Каждый ген имеет ряд активаторов (дружественные гены, присутствие которых увеличивает концентрацию гена i), представленное элементами вектора n_ka. Значение n_ka [i] может варьироваться от 0 до N_gene - 1. ka_val представляет собой показатель активации для каждого активатора ka. ka_vec_d имеет генный индекс, который активирует ген i.

Я пытаюсь представить эти циклы с помощью итераторов, но не смог этого сделать. Я знаком с использованием thrust :: for_each (thrust :: make_zip_iterator (thrust :: make_tuple)) для одиночного цикла цикла, но с трудным временем придумывает способ реализовать два цикла for, используя counting_iterator или преобразовывать итераторы. Любые указатели или помощь для преобразования этих двух циклов будут оценены. Спасибо за ваше время!

ответ

1

Это похоже на проблему с уменьшением. Я думаю, вы можете использовать thrust::transform с zip-итераторами и thrust::reduce_by_key. Эскиз этого решения является:

// generate indices 
std::vector<int> hindices; 
for(size_t i=0 ; i<N_gene ; ++i) 
    for(size_t j=0 ; j<n_ka_d[i] ; ++j) 
    hindices.push_back(i); 
thrust::device_vector<int> indices = hindices; 

// generate tmp 
// trafo1 implements get_coeff0(get<0>(t)) * get<1>(t); 
thrust::device_vector<double> tmp(N); 
thrust::transform(
    thrust::make_zip_iterator(
     thrust::make_tuple(ka_vec_d.begin() , ka_val_d.begin())) , 
    thrust::make_zip_iterator(
     thrust::make_tuple(ka_vec_d.end() , ka_val_d.end())) , 
    tmp.begin() , trafo1); 

// do the reduction for each ac[i] 
thrust::device_vector<int> indices_out(N); 
thrust::reduce_by_key(indices.begin() , indices.end() , tmp.begin() , 
    ac.begin() , indices_out.begin()); 

// do the pow transformation 
thrust::transform(ac.begin() , ac.end() , ac.begin() , pow_trafo); 

Я это это также может быть оптимизирован transform_iterators уменьшить количество вызовов thrust::transform и thrust::recuce_by_key.

+0

Спасибо headmyshouder, это, безусловно, помогает, и я уже реализовал его с помощью функции reduce_by_key, и мое приложение работает нормально. Я сделал небольшое изменение в смысле, используя thrust :: for_each вместо thrust :: transform и интегрировав tmp в кортеж, используемый для создания tmp. Есть ли какое-либо преимущество, использующее тягу :: transform over thrust :: for_each? Еще раз спасибо за ваш ответ! – rtmi

+0

Я думаю, что нет никакой реальной разницы. thrust :: transform - это немного более выразительная, поскольку он рассказывает вам, что происходит. Вы также можете попытаться измерить, равна ли производительность обоих способов. – headmyshoulder