4. 1. 本発表の目標
将来こんな問題に直面するかも・・・
蓄積してきた R では遅い処理を
C/C++ のライブラリを C/C++ に任せて
活用したい 高速化したい
R C/C++
R と C/C++ の連携させる基本的な方法を学ぶ
Made with OpenOffice.org 4
5. 2.R からの C/C++ の利用
R から C/C++ を利用する方法として,
主に2種類の方法が用いられる.
.C() 関数を利用する方法
.Call() 関数を利用する方法
Made with OpenOffice.org 5
6. 考える問題
2 つの多項式
かけあわせる
この係数を求める
Made with OpenOffice.org 6
7. 2.1 .C() 関数を利用する方法
R
オブジェクト 共用
R オブジェクト C/C++
.C() 関数 ( または DLL )
R
オブジェクト
C/C++ SO(/DLL) の SO(/DLL) の R の SO 呼び出し R での
コードの作成 作成 R への読み込み 関数の作成 関数呼び出し
Made with OpenOffice.org 7
8. Step1) C/C++ コードの作成
引数はポインタ渡し
C++ コードでは ( 最後の引数が R に渡す値を
“extern C” をつける 格納する配列の先頭ポインタ )
1 extern "C" void convolve_c(double *a, int *na,
関数の返り値は double *b, int *nb, double *ab)
2 { void 型
3 int nab = *na + *nb -1;
4
5 for (int i = 0; i < nab; ++i) ab[i] = .0;
6 for (int i = 0; i < *na; ++i) {
7 for (int j = 0; j < *nb; ++j) {
8 ab[i+j] += a[i] * b[j];
9 }
10 }
11 }
Made with OpenOffice.org 8
9. Step2) SO(/DLL) の作成
[sfukushima@localhost test]$ R CMD SHLIB conv_c.cpp
Step3) SO(/DLL) の R への読み込み
> dyn.load("conv_c.so")
・第 1 引数は, C/C++ の関数名
Step4) R の SO(/DLL) 呼び出し関数の作成 ・引数の型は厳密に指定
・最後の引数に返り値の型と
サイズを指定
conv.c <-
function(a, b) .C("conv_c",
as.double(a), as.integer(length(a)),
as.double(b), as.integer(length(b)),
res = double(length(a)+length(b)-1))
Made with OpenOffice.org 9
11. 2.2 .Call() 関数を利用する方法
R
オブジェクト 共用
R オブジェクト C/C++
.Call() 関数 ( または DLL )
R
オブジェクト
C/C++ コード SO(/DLL) の SO(/DLL) の R の SO 呼び出し R での
の作成 作成 R への読み込み 関数の作成 関数呼び出し
Made with OpenOffice.org 11
12. Step1) C/C++ コードの作成
1 #include <Rdefines.h>
2 引数,返り値ともに
3 SEXP convolve_call(SEXP a, SEXP b) 型は” SEXP”
4 { (Symbolic EXPresion)
5 PROTECT(a = AS_NUMERIC(a));
6 PROTECT(b = AS_NUMERIC(b));
7 int na = length(a), nb = length(b), nab = na + nb -1;
8 SEXP ab; SEXP 型は R がメモリを
開放しないように
9 PROTECT(ab = NEW_NUMERIC(nab));
制御する
10
11 for (int i = 0; i < nab; ++i) REAL(ab)[i] = .0;
12 変数の型を陽に指定する
13 for (int i = 0; i < na; ++i) {
14 for (int j = 0; j < nb; ++j) {
15 REAL(ab)[i+j] += REAL(a)[i] * REAL(b)[j];
16 }
17 } R がメモリを
18 UNPROTECT(3); 開放できるようにする
19 return(ab);
20 }
Made with OpenOffice.org 12
13. Step2) SO(/DLL) の作成
[sfukushima@localhost test]$ R CMD SHLIB conv_call.cpp
Step3) SO(/DLL) の R への読み込み
> dyn.load("conv_call.so")
Step4) R の SO(/DLL) 呼び出し関数の作成
conv.call <- function(a, b) .Call("conv_call", a, b)
・第 1 引数は, C/C++ の関数名
・引数の型はしてしなくて良い!
Step5) R での関数呼び出し
> conv.call(1:10, 10:1)
[1] 10 29 56 90 130 175 224 276 330 385 330 276 224
175 130 90 56 29 10
Made with OpenOffice.org 13
15. 2.4 Rcpp パッケージ
.Call() 関数を用いて, C/C++ を呼び出す場合
の C/C++ コードをもっと楽に書けないか?
R
オブジェクト 共用
R .Call() 関数
オブジェクト C/C++
( または DLL )
R
オブジェクト
Rcpp パッケージ
C/C++ コード SO(/DLL) の SO(/DLL) の R の SO 呼び出し R での
の作成 作成 R への読み込み 関数の作成 関数呼び出し
Made with OpenOffice.org 15
16. Rcpp 使用 Rcpp 不使用
1 #include <R.h> #include <Rdefines.h>
2 #include <Rinternals.h>
3 #include "Rcpp.h" SEXP convolve_call(SEXP a, SEXP b) {
4 PROTECT(a = AS_NUMERIC(a));
5 RcppExport SEXP conv_rcpp(SEXP a, SEXP b) PROTECT(b = AS_NUMERIC(b));
6 { int na = length(a),
7 RcppVector<double> aa(a); nb = length(b),
8 RcppVector<double> bb(b); nab = na + nb -1;
9 int nab = aa.size() + bb.size() - 1; SEXP ab;
10 PROTECT(ab = NEW_NUMERIC(nab));
11 Rcpp::NumericVector ab(nab);
12 for (int i = 0; i < nab; ++i) ab(i) = .0; for (int i = 0; i < nab; ++i)
13 for (int i = 0; i < aa.size(); ++i) { REAL(ab)[i] = .0;
14 for (int j = 0; j < bb.size(); ++j) {
15 ab(i + j) += aa(i) * bb(j); for (int i = 0; i < na; ++i) {
16 } for (int j = 0; j < nb; ++j) {
17 } REAL(ab)[i+j] +=
18 RcppResultSet rs; REAL(a)[i] * REAL(b)[j];
19 rs.add("ab", ab); }
20 return rs.getReturnList(); }
21 } UNPROTECT(3);
return(ab);
}
Made with OpenOffice.org 16
17. C++ 内部では STL の vector などを用いて最後に
Rcpp の wrap 関数で SEXP に変換することも可能
1 #include <R.h>
2 #include <Rinternals.h>
3 #include <Rdefines.h>
4 #include <Rcpp.h>
5 #include <vector>
6
7 extern "C" SEXP rcpp_test(SEXP x, SEXP y) {
8 std::vector<double> xx(x), yy(y);
9 int n = xx.size();
10 std::vector<double> res(n);
11
12 for (int i = 0; i < n; ++i) {
13 double x = xx[i], y = yy[i];
14 if (x < y) res[i] = x * x;
15 else res[i] = -y * y;
16 }
17 return Rcpp::wrap(res);
18 }
Made with OpenOffice.org 17
18. 3. C/C++ からの R の利用
C/C++ コードで使用できる R の API がある
(“R.h” 等を使用.
“Writing R Extensions”Chapter.6 参照 ) .
C++ からの R の利用方法として,今回は
RInside パッケージを紹介する.
RInside を用いると, C++ から R を呼び出し
て処理を行わせ,その結果を C++ に戻すこと
が楽になる.
処理の呼び出し
R C/C++
RInside パッケージ
計算結果の受け渡し
Made with OpenOffice.org 18
19. 3 C/C++ からの R の利用
1 #include <iostream>
2 #include <algorithm>
3 #include "Rinside.h"
4
5 int main(int argc, char *argv[])
6 {
7 const int dim = 10;
8
9 // 線形回帰分析に用いるデータの生成
10 std::vector<double> x, y; となる
11 for (int i = 0; i < dim;++i) { ベクトル を
12 x.push_back(i); y.push_back(2*i); C++ で生成
13 }
14 // C++ 側でのデータの確認
15 std::cout << "In c++: x" << std::endl;
16 std::copy(x.begin(), x.end(),
17 std::ostream_iterator<double>(std::cout, " "));
18 std::cout << std::endl;
19 std::cout << "In c++: v" << std::endl;
20 std::copy(y.begin(), y.end(),
21 std::ostream_iterator<double>(std::cout, " "));
22 std::cout << std::endl;
Made with OpenOffice.org 19
20. 23 // R 側の分析データオブジェクトの生成
24 RInside R(argc, argv); R でも
25 R.assign(x, "x"); R.assign(y, "y"); ベクトル を生成
26 // R のコマンドの生成,実行
27 std::string evalstr = "cat('In R: x n'); print(x);
28 cat('In R: y n'); print(y);
29 z <- lm(y~x); z <- z$fitted.values;
30 cat('In R: fitted.values n'); print(z); z";
31 SEXP ans;
32 R.parseEval(evalstr, ans);
33
R のコマンドの生成・
34 // C++ において R の返り値の格納
35 RcppVector<double> vec(ans);
受け渡し・実行
36 std::vector<double> v = vec.stlVector();
37 // 確認
38 std::cout << "In c++: v" << std::endl;
39 std::copy(v.begin(), v.end(),
40 std::ostream_iterator<double>(std::cout, " "));
41 std::cout << std::endl;
Made with OpenOffice.org 20
21. [sfukushima@localhost test]$ ./rinside_test
In c++: x
0 1 2 3 4 5 6 7 8 9 C++ での
In c++: v ベクトル の中身の確認
0 2 4 6 8 10 12 14 16 18
In R: x
[1] 0 1 2 3 4 5 6 7 8 9 R での
In R: y ベクトル の中身の確認
[1] 0 2 4 6 8 10 12 14 16 18
In R: fitted.values
1 2 3 4 5 6 7 8 9 10 R の返り値の確認
0 2 4 6 8 10 12 14 16 18
In c++: v
5.2423e-16 2 4 6 8 10 12 14 16 18
C++ において R の返り値の確認
Made with OpenOffice.org 21
22. 参考文献
Dirk Eddelbuettel(2009):
“Rcpp and Rinside: Easier R and C++
integration”, UseR! 2009 Presentation.
Dirk Eddelbuettel,Romain francois(2010):
“Rcpp:Seamless R and C++”.
R Development Core Team(2010):
“Writing R Extensions(ver.2.11.0)”.
John M.Chambers(2008):
“Software for Data Analysis
-Programming with R-”, Springer.
Made with OpenOffice.org 22