まず、免責事項: 私は常にRcppを使用しています。実際、(当時は Rcpp から名前が変更されていた) RcppTemplate がすでに孤立しており、2 年間更新されていなかったとき、私はそれを Rcpp という最初の名前で維持し始めました (この名前でRQuantLibに貢献していました)。それは約 1 年前のことで、ChangeLog に記録されているいくつかの段階的な変更を行いました。
現在、RcppTemplate は、まったく更新も修正もされていない状態で 35 か月が経過した後、ごく最近になって復活しました。興味深い新しいコードが含まれていますが、下位互換性がないように見えるため、既に Rcpp を使用していた場所では使用しません。
私がチェックしたときはいつでも、 rcppbindはあまり積極的に維持されていませんでした。Whit Armstrong には、rabstractionと呼ばれるテンプレート化されたインターフェイス パッケージもあります。
インラインはまったく異なるものです。プログラムを R 文字列として「埋め込む」ことにより、コンパイル/リンク サイクルを緩和し、コンパイル、リンク、およびロードを行います。私は、Rcpp をインラインでサポートすることについて Oleg と話しました。
Swigも面白い。Joe Wang はそこで素晴らしい仕事をし、R のすべての QuantLib をラップしました。Swig チームの誰かによると、Joe はまだそれに取り組んでいるかもしれません。とにかく、Swig の目標はより大きなライブラリです。このプロジェクトはおそらく復活する可能性がありますが、技術的な課題がないわけではありません。
もう 1 つの言及は、Rcppで動作し、R を C++ アプリケーション内に埋め込むことができる RInside に行く必要があります。
要約すると、Rcpp は私にとってはうまく機能します。特に、関数を 1 つまたは 2 つ追加するだけの小規模な探索的プロジェクトの場合は特にそうです。使いやすさに重点を置いており、R の内部構造の一部を「隠す」ことができます。私は、電子メールで何度も何度も助けてきた他の多くのユーザーを知っています。だから私はこれに行くと言うでしょう。
私の「R を使用した HPC の紹介」チュートリアルには、Rcpp、RInside、およびインラインの例がいくつかあります。
編集: それでは、具体的な例を見てみましょう (「HPC with R Intro」スライドから取得し、Venables と Ripley から取得した Stephen Milborrow から借用)。このタスクは、各位置に 1 桁のみを含む 2x2 行列の行列式のすべての可能な組み合わせを列挙することです。これは、巧妙なベクトル化された方法 (チュートリアルのスライドで説明したように) または次のような力ずくで行うことができます。
#include <Rcpp.h>
RcppExport SEXP dd_rcpp(SEXP v) {
SEXP rl = R_NilValue; // Use this when there is nothing to be returned.
char* exceptionMesg = NULL; // msg var in case of error
try {
RcppVector<int> vec(v); // vec parameter viewed as vector of ints
int n = vec.size(), i = 0;
if (n != 10000)
throw std::length_error("Wrong vector size");
for (int a = 0; a < 9; a++)
for (int b = 0; b < 9; b++)
for (int c = 0; c < 9; c++)
for (int d = 0; d < 9; d++)
vec(i++) = a*b - c*d;
RcppResultSet rs; // Build result set to be returned as list to R
rs.add("vec", vec); // vec as named element with name 'vec'
rl = rs.getReturnList(); // Get the list to be returned to R.
} catch(std::exception& ex) {
exceptionMesg = copyMessageToR(ex.what());
} catch(...) {
exceptionMesg = copyMessageToR("unknown reason");
}
if (exceptionMesg != NULL)
Rf_error(exceptionMesg);
return rl;
}
これをたとえば名前を付けて保存し、Rcppがインストールされdd.rcpp.cpp
ている場合は、単純に次のように使用します。
PKG_CPPFLAGS=`Rscript -e 'Rcpp:::CxxFlags()'` \
PKG_LIBS=`Rscript -e 'Rcpp:::LdFlags()'` \
R CMD SHLIB dd.rcpp.cpp
共有ライブラリを構築します。Rscript
(またはr
)を使用して、 Rcppにヘッダーとライブラリの場所を問い合わせます。ビルドしたら、次のように R からこれを読み込んで使用できます。
dyn.load("dd.rcpp.so")
dd.rcpp <- function() {
x <- integer(10000)
res <- .Call("dd_rcpp", x)
tabulate(res$vec)
}
同様に、さまざまな R および C++ データ型のベクトル、行列などを簡単にバックエンドで送信できます。これが多少役立つことを願っています。
編集2(5年以上後):
したがって、この回答は賛成票を獲得したため、私のキューにバブルアップしました。私がそれを書いてからかなりの時間が経過し、Rcpp はより機能が豊富になりました。だから私はこれを非常に急いで書いた
#include <Rcpp.h>
// [[Rcpp::export]]
Rcpp::IntegerVector dd2(Rcpp::IntegerVector vec) {
int n = vec.size(), i = 0;
if (n != 10000)
throw std::length_error("Wrong vector size");
for (int a = 0; a < 9; a++)
for (int b = 0; b < 9; b++)
for (int c = 0; c < 9; c++)
for (int d = 0; d < 9; d++)
vec(i++) = a*b - c*d;
return vec;
}
/*** R
x <- integer(10000)
tabulate( dd2(x) )
*/
ファイル内のコードで次のように使用できます/tmp/dd.cpp
R> Rcpp::sourceCpp("/tmp/dd.cpp") # on from any other file and path
R> x <- integer(10000)
R> tabulate( dd2(x) )
[1] 87 132 105 155 93 158 91 161 72 104 45 147 41 96
[15] 72 120 36 90 32 87 67 42 26 120 41 36 27 75
[29] 20 62 16 69 19 28 49 45 12 18 11 57 14 48
[43] 10 18 7 12 6 46 23 10 4 10 4 6 3 38
[57] 2 4 2 3 2 2 1 17
R>
主な違いは次のとおりです。
- よりシンプルなビルド:
sourceCpp()
それだけです。最後にRテストコードを実行する
- 本格的な
IntegerVector
タイプ
sourceCpp()
コード ジェネレーターによって自動的に追加される例外処理ラッパー