40

Consider the following R code,

## ----------- 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")

The user can pass a function name "fun", that is used by caller. I wish to perform the same task with RcppArmadillo objects (as part of a more complex task, obviously). The function would be defined in C++, and the user selects it at the R level by referring to its name:

caller_cpp(1:3, "fun1_cpp")

or

caller_cpp(1:3, "fun2_cpp")

etc.

Here's my naive attempt for the caller function, that even fails to compile:

## ----------- 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);
      }

   ')

Edit: adapted the example after following Dirk's suggestion to look at RcppDE.

baptiste
  • 75,767
  • 19
  • 198
  • 294

1 Answers1

32

(Sometime you need to use svn log ... on files to see how dated they are...)

I think a better use case is in my "port" of the C-based DEoptim to Rcpp / RcppArmadillo: RcppDE. In it, I allow the optimization routine to use either an R function (as DEoptim does) or a user-supplied compiled function -- which is what you want here as I understand it.

There is a tiny bit of C++ scaffolding, but you should have no problem following that.

Edit on 2013-01-21 Below is a complete solution which I have also justed posted as this new post at the Rcpp Gallery -- including some comments and sample usage.

// [[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);
}
Dirk Eddelbuettel
  • 360,940
  • 56
  • 644
  • 725
  • thanks, will look this up! hopefully my utter ignorance of c++ won't prevent me from copying and pasting things yet again. – baptiste Jan 20 '13 at 20:16
  • Unfortunately there's a bit too much happening in RcppDE for me to follow. In `evaluate.h` I see new classes being defined, some presumably to call an arbitrary R function, others (I imagine) to call a C++ function (I only want the latter). If a kind soul has time to spare, it would make for a great minimal example in the nice http://gallery.rcpp.org/. – baptiste Jan 20 '13 at 21:50
  • reading the vignette confirms the impression I had looking at the code. If I only want to deal with compiled functions, selected by their name, do I need this virtual class business? – baptiste Jan 20 '13 at 22:19
  • Maybe not. You could start with something simpler just bringing an XPtr down. I needed some generality in RcppDE hence the scaffolding. – Dirk Eddelbuettel Jan 20 '13 at 23:18
  • Ok, just posted an update, as well as a post [on the Rcpp Gallery](http://gallery.rcpp.org/articles/passing-cpp-function-pointers/). – Dirk Eddelbuettel Jan 21 '13 at 17:37
  • 3
    that's totally awesome; you should have waited for a bounty! – baptiste Jan 21 '13 at 18:13
  • Oh, I take a bounty :) I can always edit the answer away "for now" :) – Dirk Eddelbuettel Jan 21 '13 at 18:33
  • This looks great. Would this work if you had a map of strings representing function nicknames and function references? That way you can just arbitrarily expand the map instead of the function. – John Apr 21 '14 at 16:08
  • 2
    You still need the actual function pointers but you could switch between them given the map. – Dirk Eddelbuettel Apr 21 '14 at 16:32