Rから動的に呼び出されるコードをCで書いています。
このコードは、任意の時間 T までのランダムポアソンプロセスのパスを生成します。そのため、C 関数を呼び出すたびに、生成される乱数に応じて、返されるベクトルの長さが異なります。
どの R データ構造を作成する必要がありますか? LISTSXP ? もう一つ?
どうすればそれを作成でき、どのように追加できますか? 特にどうすればRに戻すことができますか?
手伝ってくれてありがとう。
Rから動的に呼び出されるコードをCで書いています。
このコードは、任意の時間 T までのランダムポアソンプロセスのパスを生成します。そのため、C 関数を呼び出すたびに、生成される乱数に応じて、返されるベクトルの長さが異なります。
どの R データ構造を作成する必要がありますか? LISTSXP ? もう一つ?
どうすればそれを作成でき、どのように追加できますか? 特にどうすればRに戻すことができますか?
手伝ってくれてありがとう。
一時的な構造として何を使用するかは、最終的に結果にベクトルを割り当てる必要があるため、実際にはあなた次第です。したがって、使用するものが何であれ、返されるものではありません。いくつかの可能性があります:
Calloc+ Realloc+を使用Freeすると、必要に応じて一時メモリを拡張できます。完全なセットを取得したら、結果ベクトルを割り当てて返します。SETLENGTH返す前に使用できます。ただし、後で複製されるまで結果が過剰に割り当てられたままになるため、これには問題があります。それぞれに欠点と利点があるため、アプリケーションによって最適なものを選択する必要があります。
編集:ペアリスト アプローチの使用例を追加しました。はるかに簡単なので、このアプローチをお勧めしますReallocが、それでも:
#define BLOCK_SIZE xxx /* some reasonable size for increments - could be adaptive, too */
SEXP block; /* last vector block */
SEXP root = PROTECT(list1(block = allocVector(REALSXP, BLOCK_SIZE)));
SEXP tail = root;
double *values = REAL(block);
int count = 0, total = 0;
do { /* your code to generate values - if you want to add one
first try to add it to the existing block, otherwise allocate new one */
if (count == BLOCK_SIZE) { /* add a new block when needed */
tail = SETCDR(tail, list1(block = allocVector(REALSXP, BLOCK_SIZE)));
values = REAL(block);
total += count;
count = 0;
}
values[count++] = next_value;
} while (...);
total += count;
/* when done, we need to create the result vector */
{
SEXP res = allocVector(REALSXP, total);
double *res_values = REAL(res);
while (root != R_NilValue) {
int size = (CDR(root) == R_NilValue) ? count : BLOCK_SIZE;
memcpy(res_values, REAL(CAR(root)), sizeof(double) * size);
res_values += size;
root = CDR(root);
}
UNPROTECT(1);
return res;
}
CからC++への切り替えを受け入れる場合は、Rcppの追加レイヤーを無料で入手できます。(まだかなり不完全な)RcppExampleパッケージのページからの例を次に示します。
#include <RcppClassic.h>
#include <cmath>
RcppExport SEXP newRcppVectorExample(SEXP vector) {
BEGIN_RCPP
Rcpp::NumericVector orig(vector); // keep a copy
Rcpp::NumericVector vec(orig.size()); // create vector same size
// we could query size via
// int n = vec.size();
// and loop over the vector, but using the STL is so much nicer
// so we use a STL transform() algorithm on each element
std::transform(orig.begin(), orig.end(), vec.begin(), ::sqrt);
return Rcpp::List::create(Rcpp::Named( "result" ) = vec,
Rcpp::Named( "original" ) = orig) ;
END_RCPP
}
ご覧のとおり、明示的なメモリ割り当てや解放PROTECT/UNPROTECTなどはなく、ファーストクラスのRリストオブジェクトが返されます。
このような他のSOの質問には、さらに多くの例が含まれています。
編集: そして、あなたはパスが何をするかを実際には言いませんでしたが、簡単な例として、Rcppの追加を使用し、Rの場合と同じように動作するC++コードを次に示しcumsum()ますrpois()。
R> library(inline)
R>
R> fun <- cxxfunction(signature(ns="integer", lambdas="numeric"),
+ plugin="Rcpp",
+ body='
+ int n = Rcpp::as<int>(ns);
+ double lambda = Rcpp::as<double>(lambdas);
+
+ Rcpp::RNGScope tmp; // make sure RNG behaves
+
+ Rcpp::NumericVector vec = cumsum( rpois( n, lambda ) );
+
+ return vec;
+ ')
R> set.seed(42)
R> fun(3, 0.3)
[1] 1 2 2
R> fun(4, 0.4)
[1] 1 1 1 2
そして証拠として、Rに戻って、シードを設定すると、まったく同じ数を生成できます。
R> set.seed(42)
R> cumsum(rpois(3, 0.3))
[1] 1 2 2
R> cumsum(rpois(4, 0.4))
[1] 1 1 1 2
R>