<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.
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/CompiledBenchmark.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]
-Christian
A man, a plan, a cat, a ham, a yak, a yam, a hat, a canal ? Panama!
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/CompiledBenchmark.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
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