0

To solve differential equations, I use the Rcpp package in R and the boost package in C++. I created the eq function in C++, which transform the R function mod_cpp into a "C++ function" (see below). The eq function is next put as an argument in the integrate_const function. Finally, I can compile it in R with Rcpp and I get an R function called my_fun, which only depends on the vector vs. Everything works well.

// [[Rcpp::export]]
void my_fun22(Rcpp::NumericVector &x, const double t){
  Function f("mod_cpp");
  x=f(_["t"]=t,_["x"]=x);
}     

Rcpp::NumericVector nvec(130);
void eq(const state_type &x, state_type &dxdt, const double t){
  boost_array_to_nvec2(x, nvec);
  my_fun22(nvec,t);
  nvec_to_boost_array2(nvec, dxdt);
}

Rcpp::NumericMatrix my_fun(const Rcpp::NumericVector vs) {
  state_type x = nvec_to_boost_array(vs); // initial conditions
  integrate_const(make_dense_output( 1E-4 , 1E-4 , stepper_type () ) ,
                eq , x , 0.0 , 120.0 , 1.0 , write_cout);
  return data;
}

The problem is that all the parameters of my model contained in the mod_cpp function are fixed. What I want to do now is to create another function that does the same job as my_fun but that depends on some parameters of the model. More precisely, create a function called my_fun2(vs, theta) that depends on vs AND theta. I already tried to do so, but was struggling with redifining the eq function within the my_fun function as it is not allowed to define a function within another function in R. Did I miss something?

Anthony Hauser
  • 659
  • 1
  • 6
  • 14
  • I read your question quickly but you should take a look at the RcppNumerical package and "functors". – F. Privé May 18 '18 at 14:41
  • And/or look at the [Rcpp Gallery post on passing a user-supplied C++ function around](http://gallery.rcpp.org/articles/passing-cpp-function-pointers/) -- as well as the [underlying SO post from 2013](http://stackoverflow.com/questions/14428687/rcpparmadillo-pass-user-defined-function). – Dirk Eddelbuettel May 18 '18 at 16:13

1 Answers1

0

For achieving what you want I would use c++ 11 lambda functions and instead of creating eq as a function I would define it as a second order function: a function that returns a different function which argument can be the theta you mentioned. For instance:

...
Rcpp::NumericMatrix my_fun(const Rcpp::NumericVector vs, const float theta) {
  state_type x = nvec_to_boost_array(vs); // initial conditions
  integrate_const(make_dense_output( 1E-4 , 1E-4 , stepper_type () ) ,
            eq(theta) , x , 0.0 , 120.0 , 1.0 , write_cout);
...
}

and then the modified eq would be something like:

std::function<void(const state_type, state_type, const double)> eq(const float theta) {
   return [&theta](const state_type &x, state_type &dxdt, const double t) {
     // do something with theta here
     // for instance, modify nvec
     ...
     // then your old function body
     boost_array_to_nvec2(x, nvec);
     my_fun22(nvec,t);
     nvec_to_boost_array2(nvec, dxdt);
   }
}

This way you can pass parameters in execution time. I haven't tested it, but the idea should be fine I guess.

To use c++ 11 features you need to make sure you have installed a c++ compiler in your system path that can compile c++ 11 code and to edit the Makevars file in your R project and add the following at the top:

PKG_CXXFLAGS = -g -O3 -std=c++11

More about this here, for example.

Batato
  • 560
  • 5
  • 18
  • The following error comes: error: reference to 'function' is ambiguous – Anthony Hauser May 19 '18 at 12:07
  • this is because `function` wasn't found, you need to use the `std` namespace or replace `function` by `std::function`. Check updated answer. – Batato May 19 '18 at 12:51
  • Where is Makevars located? In the Rcpp package, I haven't any Makevars file. – Anthony Hauser May 20 '18 at 14:37
  • Usually what I do when creating R packages with linked c++ code is just to create a R studio project in a new folder choosing the Rcpp template. In my case `Makevars` are in the `src` folder. Maybe [this example](https://github.com/rcarcasses/schrodinger) can give you a hint (disclaimer: I made it). There is even an example of a second order function [here](https://github.com/rcarcasses/schrodinger/blob/2c605ea6bfab580d8156b7058f8d2305cf12ca04/src/numerov.hpp#L39), if you need further help just let me know. – Batato May 20 '18 at 17:11
  • Actually I found 2 different Makevars file, located in 2 different package folder: RcppEigen and RcppArmadillo, but no Makevars for Rcpp package, is it normal? Maybe I should ask a new question specifically to that problem. – Anthony Hauser May 21 '18 at 09:57
  • Well, I don't think those `Makevars` files will interfere with the one of the package you are actually creating, so yes, I think is normal. If the file is not present on the `src` folder you can just create it and put the code inside. If you consider necessary you can ask a new question, I'll be happy to help as well :). – Batato May 21 '18 at 10:05
  • Actually, I don't get why I need to create a new R package. Is it due to the use of C++ 11? – Anthony Hauser May 21 '18 at 11:43
  • 1
    Well yes, I guess you are right, probably you don't need to, but probably is a good idea too to put all your code into a package (this is just my personal choice, whether is the best approach or not probably depends on your specific problem). Also, since you are already using `Rcpp`, it would be probably better to use the c++ code of `Eigen` and `armadillo` directly in your code and *not* to use the `R` wrappers, which are mostly designed to be used from R directly, not from c++ code. Again, this depends of what are you are trying to achieve. – Batato May 21 '18 at 12:27
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/171473/discussion-between-anthony-hauser-and-batato). – Anthony Hauser May 21 '18 at 14:01