2013-01-20 6 views
37

함수 이름 "재미가"저를 사용하여 caller 전달할 수RcppArmadillo 패스 사용자 정의 기능

## ----------- R version ----------- 

caller <- function(x=1:3, fun = "identity", ...){ 

    ## do some other stuff 
    ## ... 
    ## then call the function 
    eval(call(fun, x)) 

} 

fun1 <- function(x, ...){ 
    x + x 
} 

fun2 <- function(x, a = 10) a * x 

caller(fun = "fun1") 
caller(fun = "fun2") 

사용자 다음 R 코드를 고려한다. 나는 RcppArmadillo 객체로 동일한 작업을 수행하기를 원합니다 (더 복잡한 작업의 일부로, 분명히). 기능은 C++에 정의하고, 사용자는 그 이름을 참조하여 R 수준에서 선택 될 것이다 :

caller_cpp(1:3, "fun1_cpp") 

또는

caller_cpp(1:3, "fun2_cpp") 

는 여기에 대한 내 순진한 시도이다 심지어 컴파일에 실패한 호출자 함수 :

## ----------- C++ version ----------- 

library(Rcpp) 
require(RcppArmadillo)  

sourceCpp(code = ' 

     // [[Rcpp::depends("RcppArmadillo")]] 

     #include <RcppArmadillo.h> 

     using namespace arma ; 
     using namespace Rcpp ; 


     colvec fun1_cpp(const colvec x) 
     { 
     colvec y ; 
     y = x + x; 
     return (y); 
     } 

     colvec fun2_cpp(const colvec x) 
     { 
     colvec y ; 
     y = 10*x; 
     return (y); 
     } 

    // mysterious pointer business in an attempt 
    // to select a compiled function by its name 

     typedef double (*funcPtr)(SEXP); 
     SEXP putFunPtrInXPtr(SEXP funname) { 
      std::string fstr = Rcpp::as<std::string>(funname); 
      if (fstr == "fun1") 
       return(Rcpp::XPtr<funcPtr>(new funcPtr(&fun1_cpp))); 
      else if (fstr == "fun2") 
      return(Rcpp::XPtr<funcPtr>(new funcPtr(&fun2_cpp))); 

     } 

     // [[Rcpp::export]] 
     colvec caller_cpp(const colvec x, character funname) 
     { 
     Rcpp::XPtr fun = putFunPtrInXPtr(funname); 
     colvec y ; 
     y = fun(x); 
     return (y); 
     } 

    ') 

편집 : RcppDE를보기 위해 Dirk의 제안을 따른 후 예제를 수정했습니다.

답변

29

내가 더 나은 사용 사례가 Rcpp/RcppArmadillo에 C 기반 DEoptim 내 "포트"의 생각 (언젠가 당신은 ... 그들이 날짜를 기입 방식을 볼 파일에 svn log ...를 사용할 필요) : RcppDE. 그것에서 최적화 루틴이 R 함수 (DEoptim이하는 것처럼) 나 사용자가 제공 한 컴파일 된 함수를 사용하도록 허용합니다. 이것은 내가 이해할 때 원하는 것입니다.

C++ 스 캐 폴딩의 작은 비트가 있지만 그 다음에는 아무런 문제가 없습니다.

편집 날짜 : 2013-01-21 다음은 일부 의견 및 샘플 사용을 포함하여 this new post at the Rcpp Gallery으로 게시 된 완벽한 해결책입니다.

// [[Rcpp::depends(RcppArmadillo)]] 
#include <RcppArmadillo.h> 

using namespace arma; 
using namespace Rcpp; 

vec fun1_cpp(const vec& x) { // a first function 
    vec y = x + x; 
    return (y); 
} 

vec fun2_cpp(const vec& x) { // and a second function 
    vec y = 10*x; 
    return (y); 
} 

typedef vec (*funcPtr)(const vec& x); 

// [[Rcpp::export]] 
XPtr<funcPtr> putFunPtrInXPtr(std::string fstr) { 
    if (fstr == "fun1") 
     return(XPtr<funcPtr>(new funcPtr(&fun1_cpp))); 
    else if (fstr == "fun2") 
     return(XPtr<funcPtr>(new funcPtr(&fun2_cpp))); 
    else 
     return XPtr<funcPtr>(R_NilValue); // runtime error as NULL no XPtr 
} 

// [[Rcpp::export]] 
vec callViaString(const vec x, std::string funname) { 
    XPtr<funcPtr> xpfun = putFunPtrInXPtr(funname); 
    funcPtr fun = *xpfun; 
    vec y = fun(x); 
    return (y); 
} 

// [[Rcpp::export]] 
vec callViaXPtr(const vec x, SEXP xpsexp) { 
    XPtr<funcPtr> xpfun(xpsexp); 
    funcPtr fun = *xpfun; 
    vec y = fun(x); 
    return (y); 
} 
+0

감사합니다. 잘하면 C + +의 내 완전 무지가 나를 다시 복사하고 붙여 넣기에서 방지하지 않을 것입니다. – baptiste

+0

불행히도 RcppDE에서 너무 많은 일이 일어나고 있습니다. 'evaluate.h'에서 새로운 클래스가 정의되고있는 것을 볼 수 있습니다. 아마도 임의의 R 함수를 호출 할 수도 있고, C++ 함수를 호출하기 위해 다른 함수를 호출 할 수도 있습니다. 친절한 사람이 시간을 허비한다면 좋은 http://gallery.rcpp.org/에서 최소한의 모범을 보일 것입니다. – baptiste

+0

비 네트를 읽으면 코드를보고있는 느낌이 들립니다. 이름으로 선택된 컴파일 된 함수 만 처리하려는 경우 가상 클래스 비즈니스가 필요합니까? – baptiste