2012-10-22 8 views
6

私はRプログラムから呼び出したいC言語の関数 "foo"を書きました。この関数は、入力として行列を取り込み、その上でいくつかの演算を行います(各要素に1を加える)。それは私が2次元配列を渡すにはどうすればよいR .Cインタフェース:多次元配列の受け渡し

void foo(int *nin, double *x) 
{ 
int n = nin[0]; 

int i; 

for (i=0; i<n; i++) 
    x[i] = x[i] * x[i]; 
} 

として実装fooで

.C("foo", n=as.integer(5), x=as.double(rnorm(5))) 

として単一のベクトルに簡単ですが? "double * x"を "double ** x"に変更すると、セグメンテーション違反が発生します。任意のポインタが高く評価されました。

答えて

7

このようなストレートな操作については、.Cをあきらめる必要はありません。 Rの行列はベクトル+次元であることに注意してください。同様にCでは、行列とその次元を渡し、ベクトルの適切なオフセットとして行列の要素にアクセスします。

void cplus1(double *x, int *dim) 
{ 
    for (int j = 0; j < dim[1]; ++j) 
     for (int i = 0; i < dim[0]; ++i) 
      x[j * dim[0] + i] += 1; 
} 

ような何かがとても素敵なパーティートリック.C

library(inline) 
sig <- signature(x="numeric", dim="integer") 
body <- " 
    for (int j = 0; j < dim[1]; ++j) 
     for (int i = 0; i < dim[0]; ++i) 
      x[j * dim[0] + i] += 1; 
" 

cfun <- cfunction(sig, body=body, language="C", convention=".C") 

plus1 <- function(m) { 
    m[] = cfun(as.numeric(m), dim(m))$x 
    m 
} 
+0

'.Call'はない – transang

+0

@transangを行いながら目標から渡されたオブジェクトを_modify_する場合' .C'は、CプログラムにPARAMをコピーするオーバーヘッド時間を追加し、結果をコピーバックと

Rの場合、Cでコピーする必要があります。コピーを '.C()'で自動的かつ安全に行うか、 '.Call()'でエラーを起こす可能性が高い手動で行うことができます。 Rcppのやり方では、Dirkの答えで 'Rcpp :: clone(M)'ステートメントにメモリコピーが必要です。もちろん、Rcppは深刻なCレベルの開発にとって素晴らしいことです。 –

8

.C()をあきらめて、.Call()に切り替えると、Rオブジェクト全体をいわゆるSEXPオブジェクトとして渡すことができます。

RのC API、またはRcppを使って難しい方法を解析することができます。

R> library(inline) # use version 0.3.10 for rcpp() wrapper 
R> 
R> addMat <- rcpp(signature(ms="numeric"), body=' 
+ Rcpp::NumericMatrix M(ms); 
+ Rcpp::NumericMatrix N = Rcpp::clone(M); 
+ for (int i=0; i<M.nrow(); i++) 
+  for (int j=0; j<M.ncol(); j++) 
+   N(i,j) = M(i,j) + 1; 
+ return(N); 
+ ') 
R> addMat(matrix(1:9,3,3)) 
    [,1] [,2] [,3] 
[1,] 2 5 8 
[2,] 3 6 9 
[3,] 4 7 10 
R> 
0

としてinlineを使用して、あなたは@Martinモルガンの答えのように追加のパラメータによって行列の次元を渡す必要があります。 .Call

SEXP foo(SEXP mat){ 
    SEXP dims = getAttttrib(mat, R_DimSymbol); 
    int nrow = INTEGER(dims)[0]; 
    int ncol = INTEGER(dims)[1]; 
    //... 
} 
+0

その行列をコピーすることを忘れないでください! –