5

I have been trying to implement apply function in Rcpp so far the code looks like this

//[[Rcpp::export]]
NumericVector apply(NumericMatrix x,int dim,Function f){
  NumericVector output;
  if(dim==1){
   for(int i=0;i<x.nrow();i++){
     output[i]=f(x(i,_));
   }    
  }
  else if(dim==2){
   for(int i=0;i<x.ncol();i++){
     output[i]=f(x(_,i));
   }
  }
  return(output);
} 

but i'm getting an error "cannot convert SEXP to double in assignment" in line 6 and 11. Is there any way to convert the value returned by an arbitrary function to double? also is there a sugar function for the apply function.

gman
  • 1,242
  • 2
  • 16
  • 29
  • I also tried to explicitly convert the returned value to double but that doesn't seem to work as well – gman May 13 '14 at 11:55
  • `as` is how you do explicit conversion to a `double` – Romain Francois May 13 '14 at 12:52
  • Another problem of your code is that `output` is not created to the correct size. So even if you added `as` in the two places, you would not get what you want, and as a bonus you'd get undefined behavior as you assign out of bounds and Rcpp does not do bounds checks. – Romain Francois May 13 '14 at 12:57

2 Answers2

5

There is no sugar function for apply. The easiest way of doing what you want is to call as<double>, i.e.:

output[i]=as<double>(f(x(i,_)));

You could also embed this in a type that would call as for you, something like:

template <typename T>
class F {
public: 
  F( SEXP f_) : f(f_){}

  inline T operator()(NumericVector x){
    return as<T>(f(x)) ;  
  }

private:
  Function f ;
} ;

so that you could do:

// [[Rcpp::export]]
NumericVector apply_cpp(NumericMatrix x,int dim,F<double> f){
  if(dim==1){
    NumericVector output(x.nrow());
    for(int i=0;i<x.nrow();i++){
      output[i]=f(x(i,_));
    } 
    return output ;
  }
  else {
    NumericVector output(x.ncol());

    for(int i=0;i<x.ncol();i++){
      output[i]=f(x(_,i));
    }  
    return output ;
  }
} 

The F template from above assumes that the function takes a NumericVector and returns something that can be converted to a double. You could also embed type information about both inputs and outputs. Something like this (expressed in C++11):

template <typename T, typename... Args>
class F {
public: 
  F( SEXP f_) : f(f_){}

  inline T operator()(Args... args){
    return as<T>(f(args...)) ;  
  }

private:
  Function f ;
} ;

Then the signature would become:

// [[Rcpp::export]]
NumericVector apply_cpp(NumericMatrix x,int dim,F<double,NumericVector> f){
Romain Francois
  • 17,432
  • 3
  • 51
  • 77
  • Thank you @Romain Francois, This is a more generalized solution :) – gman May 13 '14 at 14:07
  • 1
    Well, this is actually answering the question, instead of throwing in vaguely related stuff. – Romain Francois May 13 '14 at 14:10
  • Also I am not clear about the Function object. Is it similar to function pointers? can you give me pointers to learn what is Function objects in rcpp. – gman May 13 '14 at 14:28
  • 1
    `Function` is an Rcpp api class that wraps an R function object and allows you to call the function with C++ `operator()`. – Romain Francois May 13 '14 at 14:49
4

The answers are, in order, "yes" and "yes", and you may want to read the "Rcpp Introduction" which contains the following lapply() example:

R> src <- '
+   Rcpp::List input(data);
+   Rcpp::Function f(fun);
+   Rcpp::List output(input.size());
+   std::transform(input.begin(), input.end(), output.begin(), f);
+   output.names() = input.names();
+   return output;
+   '
R> cpp_lapply <- cxxfunction(signature(data = "list", fun = "function"),
+    src, plugin = "Rcpp")

This was written for inline rather than Rcpp Attributes because that is how we rolled back in the day. We have more apply-alike functions in other examples and unit tests...

You have not specified what arguments your function f() takes and returns which makes fixing your question a little trickier.

Dirk Eddelbuettel
  • 360,940
  • 56
  • 644
  • 725
  • Thank you for the the answer :), The argument for the function is a numeric vector and it returns a double value. – gman May 13 '14 at 12:48