r — неопределенная ссылка на пользовательскую функцию в работнике (C ++ и RcppParallel)

Я новичок в программировании на C ++, пытаюсь поэкспериментировать с Rcpp через R.
Я создал функцию для получения всех возможных k-мер из строки. Хорошо работает в последовательной форме:

#include <Rcpp.h>
#include <string>
#include <iostream>
#include <ctime>
// using namespace Rcpp;

// [[Rcpp::export]]
std::vector< std::string > cpp_kmer( std::string s, int k ){
std::vector< std::string > kmers;
int seq_loop_size = s.length() - k+1;
for ( int z=0; z < seq_loop_size; z++ ) {
std::string  kmer;
kmer = s.substr( z, k );
kmers.push_back( kmer ) ;
}
return kmers;
}

Тем не менее, когда я пытаюсь использовать эту функцию в параллельной реализации (используя RcppParallel), с кодом ниже:

#include <Rcpp.h>
#include <string>
#include <iostream>
#include <ctime>
using namespace Rcpp;

// [[Rcpp::depends(RcppParallel)]]
#include <RcppParallel.h>
using namespace RcppParallel;

struct p_cpp_kmer : public Worker {
// input string
std::vector< std::string > seqs;
int k;
std::vector< std::string > cpp_kmer( std::string s, int k );
// destination list
List output;
std::string
sub_s;
// initialize with source and destination
p_cpp_kmer(std::vector< std::string > seqs, int k, List output)
: seqs(seqs), k(k), output(output) {}

// calculate k-mers for the range of sequences requested
void operator()(std::size_t begin, std::size_t end) {
for (std::size_t i = begin; i < end; i++)
sub_s = seqs[i];
cpp_kmer(sub_s, k);
}
};

// [[Rcpp::export]]
List par_cpp_kmer(std::vector< std::string > seqs, int k, bool v){
// allocate output list
List outpar(num_seqs);
int num_seqs = seqs.size();
// p_cpp_kmer functor (pass input and output matrixes)
p_cpp_kmer par_kmer(seqs, k, outpar);
parallelFor(0, num_seqs, par_kmer);
return wrap(outpar);
}

std::vector< std::string > cpp_kmer( std::string s, int k ){
std::vector< std::string > kmers;
int seq_loop_size = s.length() - k+1;
for ( int z=0; z < seq_loop_size; z++ ) {
std::string  kmer;
kmer = s.substr( z, k );
kmers.push_back( kmer ) ;
}
return kmers;
}

Он не компилируется, давая: неопределенная ссылка на p_cpp_kmer :: cpp_kmer (std :: string, int) ‘ ошибка.

Я знаю, что это связано с объявлением / ссылкой на cpp_kmer, но я просто не могу понять, где / как это сделать надлежащим образом (из-за недостатка знаний в C ++).

Заранее большое спасибо.

1

Решение

Что происходит, что ваш p_cpp_kmer структура объявляет cpp_kmer метод, но он никогда не определяется. Вместо этого то, что определено позже, является свободной функцией cpp_kmer,

Вы объявляете этот метод

std::vector< std::string > cpp_kmer( std::string s, int k );

Вы, кажется, хотите использовать это:

void operator()(std::size_t begin, std::size_t end) {
for (std::size_t i = begin; i < end; i++)
sub_s = seqs[i];
cpp_kmer(sub_s, k);
}

Но вместо этого вы определяете свободную функцию cpp_kmer Вот:

std::vector< std::string > cpp_kmer( std::string s, int k ){
std::vector< std::string > kmers;
int seq_loop_size = s.length() - k+1;
for ( int z=0; z < seq_loop_size; z++ ) {
std::string  kmer;
kmer = s.substr( z, k );
kmers.push_back( kmer ) ;
}
return kmers;
}

Вы можете удалить определение cpp_kmer метод в структуре, так что используется свободная функция, или фактически определить ее.

Есть дополнительные проблемы с кодом:

  • В вашем operator() Вы отбрасываете результат. Я думаю, вы хотите иметь это вместо output[i] = cpp_kmer(sub_s, k);

  • даже если вы делаете что-то подобное выше, код небезопасен, потому что output[i] = cpp_kmer(sub_s, k); выделяет объекты R (каждая отдельная строка R и вектор строки), что не может происходить в отдельном потоке.

Если вы действительно хотите сделать это параллельно, вам нужно убедиться, что вы не выделяете какой-либо объект R в рабочих.

Кроме того, написание параллельного кода намного проще, если рассмотреть возможность использования C ++ 11 и библиотеки tbb, лежащей в основе RcppParallel, Например:

#include <Rcpp.h>
#include <RcppParallel.h>

using namespace Rcpp;
using namespace RcppParallel;

// [[Rcpp::depends(RcppParallel)]]
// [[Rcpp::plugins(cpp11)]]

using string_vector = std::vector< std::string > ;
using list_string_vector = std::vector<string_vector> ;

// [[Rcpp::export]]
list_string_vector par_cpp_kmer( string_vector  seqs, int k, bool v){
int num_seqs = seqs.size() ;

list_string_vector out(num_seqs) ;

tbb::parallel_for( 0, num_seqs, 1, [&seqs,k,&out](int i){
std::string& s = seqs[i] ;
int seq_loop_size = s.length() - k+1;

std::vector<std::string> vec(seq_loop_size) ;
for ( int z=0; z < seq_loop_size; z++ ) {
vec[z] = s.substr( z, k );
}
out[i] = vec ;

}) ;
return out ;
}

Это при условии, что std::string можно выделить в отдельных потоках:

> par_cpp_kmer( c("foobar", "blabla"), 3 )
[[1]]
[1] "foo" "oob" "oba" "bar"
[[2]]
[1] "bla" "lab" "abl" "bla"
2

Другие решения

У вас, вероятно, есть реализация для cpp_kmer для другой структуры (или в общедоступном пространстве имен), но вам не хватает реализации функции-члена cpp_kmer в вашей структуре p_cpp_kmer, Вам нужно будет добавить реализацию вроде:

std::vector< std::string > p_cpp_kmer::cpp_kmer( std::string s, int k ) {
// your implementation goes here
}
0

По вопросам рекламы [email protected]