[Rcpp-devel] Repeatedly evaluating external C++ function in the same environment
Dirk Eddelbuettel
edd at debian.org
Tue Aug 5 17:27:11 CEST 2014
Hi Antonio,
On 5 August 2014 at 11:03, Antonio Coppola wrote:
| Hello RCPP,
|
| There is a puzzle that I have been wrestling with for a while now. This is in
| the context of a package for numerical optimization. The underlying
| implementation is, of course, in C++. I’d like to let the user pass in both R
| functions and external pointers to C++ for function evaluation, much like in
| the RcppDE package. I also want the user to be able to pass in an environment
| in which to evaluate the function. So far so good. No issue doing that with the
| R functions, and for the C++ pointers I define a class after the RcppDE model:
|
| class EvalCompiled : public EvalBase {
| public:
| EvalCompiled(Rcpp::XPtr<funcPtr> xptr, SEXP __env) {
| funptr = *(xptr);
| env = __env;
| };
| EvalCompiled(SEXP xps, SEXP __env) {
| Rcpp::XPtr<funcPtr> xptr(xps);
| funptr = *(xptr);
| env = __env;
| };
| Rcpp::NumericVector eval(SEXP par) {
| neval++;
| return funptr(par, env);
| }
| private:
| funcPtr funptr;
|
| SEXP env;
| };
|
| The user has to create the external pointer using inline in R. The following is
| an example using a logit regression setup with ridge penalty. The extra
| environment is required to pass in the data:
|
| lhoodL2.inc <- 'Rcpp::NumericVector lhood(SEXP xs, SEXP env){
| arma::vec par = Rcpp::as<arma::vec>(xs);
| Rcpp::Environment e = Rcpp::as<Rcpp::Environment>(env);
| arma::mat X = Rcpp::as<arma::mat>(e["X"]);
| arma::vec y = Rcpp::as<arma::vec>(e["y"]);
| double prec = Rcpp::as<double>(e["prec"]);
| arma::mat Xbeta = X * par;
| double sum1 = sum(y % Xbeta - log(1 + exp(Xbeta)));
| arma::mat sum2 = sum(pow(par, 2 * prec));
| arma::vec out = -(sum1 - 0.5 * sum2);
| Rcpp::NumericVector ret = Rcpp::as<Rcpp::NumericVector>(wrap(out));
| return ret;
| }
| '
|
| lhoodL2.body <- '
| typedef Rcpp::NumericVector (*funcPtr)(SEXP, SEXP);
| return(XPtr<funcPtr>(new funcPtr(&lhood)));
| '
|
| lhoodL2.CPP <- cxxfunction(signature(), body=lhoodL2.body,
| inc=lhoodL2.inc, plugin="RcppArmadillo")
|
| # Passing in some data
| env <- new.env()
| env[["X"]] <- X
| env[["y"]] <- y
| env[["prec"]] <- prec
|
| output <- myNumericalOptimizationFun(lhoodL2.CPP(), c(-1.2,1), environment=env)
|
| The external pointer is passed into the numerical optimization routine, and
| then the function is evaluated repeatedly until the optimization algorithm
| reaches convergence. Now this works, but there is a big inefficiency here,
| which is presumably slowing down things a lot. Namely, the data in the
| environment is copied in memory at each iteration of the function, even though
| this is not actually necessary. One would only need to copy the objects in
| memory the first time the function is evaluated, and then reference them with a
| pointer for the next iterations. Can you envision any way of doing this within
| the context of the RCPP framework?
Hm. Excellent question, and I quite like the XPtr use -- and I mentioned this
very trick for this very use in talks / workshops at U Chicago and U Kansas.
The environment should not get copied if it isn't altered. You could try
the Rcpp::Environment class.
Or you could try constructing an outer object holding the data, ensuring
there is only one and then supplying an accessor object. I know I am being
brief here but does that makes sense to you?
Dirk
--
http://dirk.eddelbuettel.com | @eddelbuettel | edd at debian.org
More information about the Rcpp-devel
mailing list