1

--------- Adding a summary of the problem ---------------------------------

I want to create a externalpointer for a user defined function which can be passed to the another function. The user will provide function name as a string, my question is how can I convert that into a function pointer, after checking that the user provided string (say fstr) matches with the name of the function that was created by the user, i.e.

if (fstr == "<USER_DEFINED_FUNCTION_NAME>")
  XPtr<funcPtr> fun(new funcPtr(&<USER_DEFINED_FUNCTION_NAME>), true);
else
  Rcpp::Rcout << "Supply the correct function name" << std::endl;

since, I don't know the name of the function created by the user, essentially the problem is - how can I get the string stored in the variable fstr?

The full problem is described below. Of course, I could be thinking of this problem in a totally wrong way and there may be a better way to create a function pointer to a user defined function.

Thanks


I am writing a package which provides a wrapper around the cvode solver for solving ODEs from the SUNDIALS ODE solving C library. The C function which describes the right hand side of the ODEs must be have the signature

int <FUNCTION_NAME> (realtype t, N_Vector y, N_Vector ydot, void *user_data)

where realtype, N_Vector are datatypes defined in the library and t is time, y is the vector of states (dependent variables) and ydot is the rate of change of those variables w.r.t. time.

I have written a package which provides a wrapper around the cvode function in this library to solve ODEs expressed as above. The package source code can be found here. The cvode function can be used to solve the example in SUNDIALS provided as follows:

I create a test.cpp (pasted below) which describes the RHS of ODEs, it also has the exported function to create externalpointer for the function which gets exported to R. Note that NV_Ith_S is also defined by the library. Also, a good example about function pointers in Rcpp can be found here

First I run Rcpp::sourceCpp(test.cpp), then I run my_fun <- putFunPtrInXPtr() to create a external pointer my_fun to my test function in test.cpp. Finally, after loading the package, I run the command

time_t <- c(0.0, 0.4, seq(from = 10.4, len = 12, by = 10)) # time vector
cvode(time_t, c(1,0,0), my_fun, 1e-04, c(1e-08, 1e-08, 1e-08))

to get results on console successfully. Here the second argument is the initial conditions (IC), my_fun is the pointer to ODE function, third argument is relative tolerance and fourth argument is absolute tolerance. See details about cvode here.

My question is this - I want to change the cvode in my package so that it can take function name as a string, i.e. cvode(NumericVector time, NumericVector IC, std::string fstr, double reltol, NumericVector abstol), instead of cvode(NumericVector, NumericVector, SEXP, double, NumericVector) where the string (fstr) is the user given name which should be same as the same of the function defined in .cpp file (here test function in test.cpp).

I am thinking in my cvode function, I can write

if (fstr == "<USER_DEFINED_FUNCTION_NAME>")
  XPtr<funcPtr> fun(new funcPtr(&<USER_DEFINED_FUNCTION_NAME>), true);
else
  Rcpp::Rcout << "Supply the correct function name" << std::endl;

However, I cannot think of any way of getting information regarding the USER_DEFINED_FUNCTION_NAME. Essentially, I want fun to point to the USER_DEFINED_FUNCTION_NAME, but can't think of any way.

In the end, I actually want the RHS function defined in .cpp to have the signature int <FUNCTION_NAME>(double t, NumericVector y, NumericVector ydot, void *user_data), from which I create a function with the correct signature to be fed to cvode, but not sure how this is possible also.

I would be very thankful for any guidance. Thanks!

#include <Rcpp.h>
using namespace Rcpp;

#include <cvode/cvode.h>               /* prototypes for CVODE fcts., consts. */
#include <nvector/nvector_serial.h>    /* serial N_Vector types, fcts., macros */
#include <cvode/cvode_dense.h>         /* prototype for CVDense */
#include <sundials/sundials_dense.h>   /* definitions DlsMat DENSE_ELEM */
#include <sundials/sundials_types.h>   /* definition of type realtype */

int test (realtype t, N_Vector y, N_Vector ydot, void *user_data){

  // static keyword before int is not really required here

  NV_Ith_S(ydot,0) = -0.04 * NV_Ith_S(y,0) + 1e04 * NV_Ith_S(y,1) * NV_Ith_S(y,2);
  NV_Ith_S(ydot,2) = 3e07 * NV_Ith_S(y,1) * NV_Ith_S(y,1);
  NV_Ith_S(ydot,1) = -NV_Ith_S(ydot,0) - NV_Ith_S(ydot,2);

  return(0);

}

// declare funcPtr as a type for function pointer to a function with the
// signature same as function which describes the RHS for ODEs
// see reference here - http://gallery.rcpp.org/articles/passing-cpp-function-pointers/
typedef int (*funcPtr)(realtype t, N_Vector y, N_Vector ydot, void *user_data);

// [[Rcpp::export]]
XPtr<funcPtr> putFunPtrInXPtr() {

  // return(XPtr<funcPtr> (new funcPtr(&test)));
    XPtr<funcPtr> testptr(new funcPtr(&test), true);
    return testptr;

}
Satya
  • 1,708
  • 1
  • 15
  • 39
  • 2
    Could you provide a *minimal* example that reproduces your problem? – F. Privé Nov 22 '17 at 07:48
  • I have added a summary. I don't have an example as I am stuck with not understanding a basic concept. Hope the summary helps, else I will try to cook up a contrived example. – Satya Nov 22 '17 at 15:40
  • To echo what Florian said, we don't have any of the specific headers you use, so it makes it difficult to help. One thing though is that you should definitely use `false` as the second argument of the `XPtr` constructor so that `delete` is not called. The construct `new funcPtr(&fun1_cpp)` in the article you mention feels wrong. – Romain Francois Nov 23 '17 at 09:00
  • @RomainFrancois and Florian - Thanks for your comments, to me it seems this approach of trying to find function name might not be the right way. I am thinking of trying another approach in my package. Anyway, thanks for your comments. – Satya Nov 24 '17 at 23:49
  • Have you read the answer from [RcppArmadillo pass user-defined...](https://stackoverflow.com/a/14428758/4408538)? There is a link in the answer there to the Rcpp gallery ([Passing user-supplied C++ functions...](http://gallery.rcpp.org/articles/passing-cpp-function-pointers/)). – Joseph Wood Nov 26 '17 at 14:25

0 Answers0