[Rcpp-devel] Pointer troubles
Manuel Castejón Limas
manuel.castejon at gmail.com
Thu Aug 4 13:16:54 CEST 2011
This is a toy example:
# ----------------------- Creating the pointers to C++ functions --------
otherCode <- ' // -------------------------- function definitions ---
double f0(double x) {
return( tanh(x) );
}
double f1(double x) {
return( 1-tanh(x)*tanh(x) );
}
'
testCode <- ' // --------------- return a couple of Xptr to f0 and f1
typedef double (*funcPtr)(double);
return List::create( _["f0"]=XPtr<funcPtr>(new
funcPtr(&f0)),
_["f1"]=XPtr<funcPtr>(new
funcPtr(&f1)) ) ;
'
testCodefun <- cxxfunction(sig = character(), body = testCode, includes =
otherCode, plugin="Rcpp")
functionPointers <- testCodefun()
functionPointers
# $f0
# <pointer: 0x10043eca0>
#
# $f1
# <pointer: 0x10043f420>
# ----------------------- Using the pointers to C++ functions --------
testCode <- '
typedef double (*funcPtr)(double);
List functionPointers(listOfFunctionPointers);
double xx=as<double>(x);
XPtr<funcPtr> f0XPtr = functionPointers["f0"];
XPtr<funcPtr> f1XPtr = functionPointers["f1"];
return NumericVector::create( _["f0(x)"]=(*f0XPtr)(xx) ,
_["f1(x)"]=(*f1XPtr)(xx) ) ;
'
testCodefun <- cxxfunction(sig =
signature(listOfFunctionPointers="externalpointer", x="numeric"), body =
testCode, includes = otherCode, plugin="Rcpp")
result <-testCodefun(listOfFunctionPointers=functionPointers, x=0.1)
result
# f0(x) f1(x)
# 0.09966799 0.99006629
El 04/08/11 00:18, "Dirk Eddelbuettel" <edd at debian.org> escribió:
>
>On 3 August 2011 at 14:48, Christian Gunning wrote:
>| On Wed, Aug 3, 2011 at 10:22 AM,
>| <rcpp-devel-request at r-forge.wu-wien.ac.at> wrote:
>| > Simple examples are in a demo file in the
>| > package, see demo(CompiledBenchmark) -- or more importantly, see its
>source
>| > and the RcppDE source.
>|
>| I'm now cobbling together a small XPtr section in Rcpp-quickref based
>| on these 2 related threads, which have been enormously helpful to me.
>
>You are the man! Much appreciated. But we should really make sure we
>settle
>on something simple yet complete. Maybe feeding R's optim or something
>simpler.
>
>| Thanks, I think I finally get it.
>|
>| In the meantime, for the inveterately lazy and/or confused, here's the
>| horse's mouth, with some key lines therein to trace up from:
>|
>|
>https://r-forge.r-project.org/scm/viewvc.php/pkg/RcppDE/demo/CompiledBench
>mark.R?view=markup&root=rcpp
>|
>| create_xptr <- cxxfunction(signature(funname="character"),
>| body=src.xptr, inc=inc, plugin="Rcpp")
>| ## ...
>| cppDE <- function(n, maxIt, fun) RcppDE::DEoptim(fn=fun,
>| lower=rep(-25, n),
>| upper=rep(25, n), control=list(NP=10*n, itermax=maxIt,
>| trace=FALSE))#, bs=TRUE))
>| ## ...
>| xptr <- create_xptr(funname)
>| ct <- system.time(invisible(cppDE(n, maxIt, xptr)))[3]
>
>What I didn't show was the receiving end. In the C++ function doing the
>optimisation setip, we switch based on what the user gives us (R
>function, or
>inline-created XPtr SEXP with a C function):
>
> Rcpp::DE::EvalBase *ev = NULL; // pointer to abstract base class
> if (TYPEOF(fcall) == EXTPTRSXP) { // non-standard mode: we are
>being passed an external pointer
> ev = new Rcpp::DE::EvalCompiled(fcall); // so assign a pointer using
>external pointer in fcall SEXP
> } else { // standard mode: env_ is an env, fcall_ is a function
> ev = new Rcpp::DE::EvalStandard(fcall, rho); // so assign R function and
>environment
> }
>
>and this 'ev' object is then evaluated with the parameters:
>
> double t_tmpC = ev->eval(par); // Evaluate mutant in t_tmpP
>
>It is implemented as some quick classes wrapped in a header file
>evaluate.h:
>
>
> class EvalBase {
> public:
> EvalBase() : neval(0) {};
> virtual double eval(SEXP par) = 0;
> unsigned long getNbEvals() { return neval; }
> protected:
> unsigned long int neval;
> };
>
> class EvalStandard : public EvalBase {
> public:
> EvalStandard(SEXP fcall_, SEXP env_) : fcall(fcall_), env(env_) {}
> double eval(SEXP par) {
> neval++;
> return defaultfun(par);
> }
> private:
> SEXP fcall, env;
> double defaultfun(SEXP par) { // essentialy same as the old
>evaluate
> SEXP fn = ::Rf_lang3(fcall, par, R_DotsSymbol); // this could be done
>with Rcpp
> SEXP sexp_fvec = ::Rf_eval(fn, env); // but is still a lot slower
>right now
> double f_result = REAL(sexp_fvec)[0];
> if (ISNAN(f_result))
> ::Rf_error("NaN value of objective function! \nPerhaps adjust the
>bounds.");
> return(f_result);
> }
> };
>
> typedef double (*funcPtr)(SEXP);
> class EvalCompiled : public EvalBase {
> public:
> EvalCompiled( Rcpp::XPtr<funcPtr> xptr ) {
> funptr = *(xptr);
> };
> EvalCompiled( SEXP xps ) {
> Rcpp::XPtr<funcPtr> xptr(xps);
> funptr = *(xptr);
> };
> double eval(SEXP par) {
> neval++;
> return funptr(par);
> }
> private:
> funcPtr funptr;
> };
>
>EvalBase is the abstract base class, EvalStandard uses standard R and
>EvalCompiled uses the compiled function.
>
>It all looks mighty complicated but once you squint at it for a few
>minutes
>it starts to make sense. And I share Manuel's excitement for doing
>something
>like this for Amore -- it make sense.
>
>But we need to clean it up into a simpler selfcontained example.
>Volunteers?
>
>Dirk
>
>--
>Gauss once played himself in a zero-sum game and won $50.
> -- #11 at http://www.gaussfacts.com
More information about the Rcpp-devel
mailing list