[Rcpp-devel] Passing an exposed function to another C++ function as a parameter

Dirk Eddelbuettel edd at debian.org
Wed Aug 3 19:22:41 CEST 2011


On 3 August 2011 at 18:59, Manuel Castejón Limas wrote:
| Great! I'm eager to see the example. Thank you very much indeed!
| 
| I'm sorry about the formatting of the table, I'm used to write on a very
| wide setting so it looked ok on my computer. I'll be more careful the next
| time.
| 
| Though I did not mention it in the first message, the problem posed has
| paramount importance for the new version of the AMORE package and may be
| for many others to come.
| 
| The thing is that, in the case of AMORE ---a neural network simulator---,
| the user of the package is provided the capability to write their own
| neuron activation functions and training cost functions. In the stable
| version on CRAN this is done by letting the user write those functions in
| R language at the cost of a lower performance. Those users that are ok
| with the functions provided in the package enjoy the benefits of compiled
| code; those writing their own functions have to cope with a lower speed
| unless they want to sink into the code of the package, but those are the
| less I guess.
| 
| Now, thanks to Rcpp, a see a new possibility which is to let the user
| write their own functions in C++ and use them along the provided ones in
| the package following the scheme I was trying to get to work, and all that
| without having to compromise performance.


As Romain mentioned, I addressed that with my 'port' of DEoptim to Rcpp in
the RcppDE package. It allows for user-defined objective functions that can
be either supplied in R or C. Simple examples are in a demo file in the
package, see demo(CompiledBenchmark) -- or more importantly, see its source
and the RcppDE source.

To take but one example, the 'Rastrigin' optimisation function is written (in
DEoptim and other places) as

    Rastrigin <- function(x) {
        sum(x+2 - 10 * cos(2*pi*x)) + 20
    }

and we can supply a C++ variant as

    double rastrigin(SEXP xs) {
      Rcpp::NumericVector x(xs);
      int n = x.size();
      double sum = 20.0;
      for (int i=0; i<n; i++) {
        sum += x[i]+2 - 10*cos(2*M_PI*x[i]);
      }
    return(sum);

from which we can build an XPtr object (where we actually switch over three
different possibilities, here simplified):

    typedef double (*funcPtr)(SEXP);
    return(XPtr<funcPtr>(new funcPtr(&rastrigin)));

and that XPtr is then passed down to the C++ code to be evaluated.

Have a look at the demo, it may get you towards where you want to go.  This
is still pretty raw and drafty code in RcppDE; I stopped when it started to
do what I wanted it to do.

Cheers, Dirk


| 
| The point is that the Tanh_f0 function, shown as an example, or many
| others will be written by the user if need be, while the rest of the code
| involved in training the network will be provided by the package.
| 
| There's beauty indeed in being able to merge those two worlds.
| 
| Similarly, the same thing might be done with classes. A package could then
| provide a framework and the users could extend the existing classes
| customizing the behavior of the package with the ease of using inline. Now
| I'm thinking about training algorithms in the case of AMORE.
| 
| But that's another story. For now, I'm dreaming on the example that Romain
| is cooking.
| 
| PS: Did I mention you guys did a great job with Rcpp! I love it. It's a
| revolutionary package in the R arena, IMHO.
| 
| 
| 
| El 03/08/11 15:29, "Dirk Eddelbuettel" <edd at debian.org> escribió:
| 
| >
| >On 3 August 2011 at 14:42, Romain Francois wrote:
| >| Hi,
| >| 
| >| This looks very similar to a problem Dirk faced in rewriting the
| >DEOptim 
| >| package to use Rcpp (the RcppDE package is on the Rcpp svn repo).
| >
| >(and on CRAN)
| > 
| >| Essentially the problem is that the Rcpp::Function is a C++ object that
| >| calls back to R, with additional protection, which eventually calls C++.
| >| 
| >| You should be able to bypass this entirely and access directly the
| >| pointer to the C++ function from the R variable. This way, you stay in
| >| the C++ world. This would allow you to branch your code depending on
| >| whether you loop over a pure R function or a C++ function.
| >| 
| >| I'll cook an example.
| >
| >Cool, thanks. Maybe add it to the Rcpp-FAQ vignette too?
| >
| >Dirk
| >
| >| 
| >| Romain
| >| 
| >| Le 03/08/11 08:22, Manuel Castejón Limas a écrit :
| >| >
| >| >> Dear all,
| >| >>
| >| >> I'm rewriting the AMORE package using Rcpp --- in fact it's more like
| >| >> I'm having a lot of fun while rewriting the AMORE package thanks to
| >Rcpp.
| >| >> Nevertheless, I'm facing this little problem that I hope it would be
| >| >> pretty easy for you to solve.
| >| >>
| >| >> Let's consider the C++ function Tanh_f0
| >| >>
| >| >> double
| >| >>
| >| >> Tanh_f0(double inducedLocalField)
| >| >>
| >| >>   {
| >| >>
| >| >>     return tanh(inducedLocalField);
| >| >>
| >| >>   }
| >| >>
| >| >>
| >| >> After compilation using inline, Tanh_f0 is exposed to R using Module
| >| >> and accessible through actMod$Tanh_f0
| >| >>
| >| >>
| >| >> actMod$Tanh_f0(0.1)
| >| >>
| >| >> # [1] 0.09966799
| >| >>
| >| >>
| >| >> Now, I want to pass actMod$Tanh_f0 as a parameter of a function in
| >| >> order to use the original C++ function Tanh_f0.
| >| >>
| >| >>
| >| >>
| >| >> testCode <- ' Rcpp::Function fx (myfun);
| >| >>
| >| >> double result = as<double>(fx(x));
| >| >>
| >| >> return wrap( result );
| >| >>
| >| >> '
| >| >>
| >| >> usingTanhf0 <- cfunction(sig=signature(myfun="function",
| >x="numeric"),
| >| >> body=testCode,Š)
| >| >>
| >| >>
| >| >> And that indeed works, but when compared to using a simple tanh
| >| >> function it shows quite a bad performance.
| >| >>
| >| >>
| >| >>
| >| >> testCode <- ' double value = as<double>(x);
| >| >>
| >| >> double result = tanh(value);
| >| >>
| >| >> return wrap( result );
| >| >>
| >| >> '
| >| >>
| >| >>
| >| >> usingTanh <- cfunction(sig=signature(x="numeric"), body=testCode, Š )
| >| >>
| >| >> benchmark(usingTanhf0(myfun=actMod$Tanh_f0, x=0.1) , usingTanh(
| >| >> x=0.1), columns=c("test", "replications", "elapsed", "relative"),
| >| >> order="relative", replications=1000)
| >| >>
| >| >> #                                           test replications elapsed
| >| >> relative
| >| >>
| >| >> # 2                           usingTanh(x = 0.1)         1000   0.004
| >| >>       1
| >| >>
| >| >> # 1 usingTanhf0(myfun = actMod$Tanh_f0, x = 0.1)         1000   0.080
| >| >>       20
| >| >>
| >| >>
| >| >> Looks like having to go the R way to get access to Tanh_f0 has a high
| >| >> cost. In order to be faster, it would be great if I could have access
| >| >> to the original Tanh_f0 which I guess is pointed to by
| >| >>  actMod$Tanh_f0, may be at the address 0x100153d30 ?
| >| >>
| >| >>
| >| >> actMod$Tanh_f0
| >| >>
| >| >> # internal C++ function <0x100153d30>
| >| >>
| >| >> #     signature : double Tanh_f0(double)
| >| >>
| >| >>
| >| >> After having had a look at RppDE sources, I guess the solution would
| >| >> be to pass the function as an external pointer; something like :
| >| >>
| >| >> testCode <- '
| >| >>
| >| >> typedef double (*funPtr)(double) ;
| >| >>
| >| >> Rcpp::XPtr<  funPtr > fx (myfun);
| >| >>
| >| >> double result = (*fx)(0.1);
| >| >>
| >| >> return wrap( result );
| >| >>
| >| >> '
| >| >>
| >| >> testCodefun <- cfunction(sig=signature(myfun="C++Function"),
| >| >> body=testCode,Š)
| >| >>
| >| >> result <- testCodefun(myfun=actMod$Tanh_f0)
| >| >>
| >| >>
| >| >> But this does NOT work and crashes R.
| >| >>
| >| >> Any hints?
| >| >>
| >| >> Thank you for your patience in reading such long message!
| >| >> Manuel
| >| >>
| >| >>
| >| >>
| >| >
| >| >
| >| > _______________________________________________
| >| > Rcpp-devel mailing list
| >| > Rcpp-devel at lists.r-forge.r-project.org
| >| > 
| >https://lists.r-forge.r-project.org/cgi-bin/mailman/listinfo/rcpp-devel
| >| 
| >| 
| >| -- 
| >| Romain Francois
| >| Professional R Enthusiast
| >| +33(0) 6 28 91 30 30
| >| http://romainfrancois.blog.free.fr
| >| http://romain-francois.com
| >| |- http://bit.ly/lJoWbH : Montpellier Comédie Club - Juin 2011
| >| |- http://bit.ly/kaSV6U : Stand up set at Up The Creek
| >| `- http://bit.ly/hdKhCy : Rcpp article in JSS
| >| 
| >| 
| >| _______________________________________________
| >| Rcpp-devel mailing list
| >| Rcpp-devel at lists.r-forge.r-project.org
| >| https://lists.r-forge.r-project.org/cgi-bin/mailman/listinfo/rcpp-devel
| >
| >-- 
| >Gauss once played himself in a zero-sum game and won $50.
| >                      -- #11 at http://www.gaussfacts.com
| 
| 

-- 
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