Rcpp and the new R:: namespace for Rmath.h
Want to share your content on R-bloggers? click here if you have a blog, or here if you don't.
Rmath.h
— and illustrate one of the
key features (Rcpp attributes) in passing.
R, as a statistical language and environment, has very well written and tested statistical distribution functions providing
probability density, cumulative distribution, quantiles and random number draws for dozens of common and not so common distribution functions.
This code is used inside R, and available for use from standalone C or C++ programs via the standalone R math library which Debian /
Ubuntu have as a package r-mathlib
(and which can be built from R sources).
User sometimes write code against this interface, and then want to combine the code with other code, possibly even with Rcpp. We allowed
for this, but it required a bit of an ugly interface. R provides a C interface; these have no namespaces. Identifiers can clash, and to be
safe one can enable a generic prefix Rf_
. So functions which could clash such as length
or error
become Rf_length
and Rf_error
and are less likely to conflict with symbols from other libraries. Unfortunately, the side-effect
is that calling, say, the probability distribution function for the Normal distribution becomes Rf_pnorm5()
(with the 5
denoting the five parameters: quantile, mean, std.deviation, lowerTail, logValue). Not pretty, and not obvious.
So one of the things we added was another layer of indirection by adding a namespace R
with a bunch of inline’d wrapper
functions (as well as several handful of unit tests to make sure we avoided typos and argument transposition and what not).
The short example below shows this for a simple function taking a vector, and returning its pnorm
computed three different ways:
This example also uses the new Rcpp attributes described briefly in the announcement blog post and of course in more detail in the corresponding vignette. Let us just state here that we simply provide a complete C++ function, using standard Rcpp types -- along with one 'attribute' declaration of an export via Rcpp. That's it -- even easier than using inline.#include <Rcpp.h> // [[Rcpp::export]] Rcpp::DataFrame mypnorm(Rcpp::NumericVector x) { int n = x.size(); Rcpp::NumericVector y1(n), y2(n), y3(n); for (int i=0; i<n; i++) { // the way we used to do this y1[i] = ::Rf_pnorm5(x[i], 0.0, 1.0, 1, 0); // the way we can do it now y2[i] = R::pnorm(x[i], 0.0, 1.0, 1, 0); } // or using Rcpp sugar in one go y3 = Rcpp::pnorm(x); return Rcpp::DataFrame::create(Rcpp::Named("Rold") = y1, Rcpp::Named("Rnew") = y2, Rcpp::Named("sugar") = y3); }
Now in R we simply do
to obtain a callable R function with the C++ code just shown behind it. No Makefile, no command-line tool invocation -- nothing but a single call toR> sourceCpp("mypnorm.cpp")
sourceCpp()
which takes care of things --- and brings us a compiled C++ function to R just given the source file with
its attribute declaration.
We can now use the new function to compute the probaility distribution both the old way, the new way with the 'cleaner'
R::pnorm()
, and of course the Rcpp sugar way in a single call. We build a data frame in C++, and assert that all
three variants are the same:
This example hopefully helped to illustrate how Rcpp 0.10.0 brings both something really powerful (Rcpp attributes -- more on this another time, hopefully) and convenient in the new namespace for statistical functions.R> x <- seq(0, 1, length=1e3) R> res <- mypnorm(x) R> head(res) Rold Rnew sugar 1 0.500000 0.500000 0.500000 2 0.500399 0.500399 0.500399 3 0.500799 0.500799 0.500799 4 0.501198 0.501198 0.501198 5 0.501597 0.501597 0.501597 6 0.501997 0.501997 0.501997 R> all.equal(res[,1], res[,2], res[,3]) [1] TRUE R>
R-bloggers.com offers daily e-mail updates about R news and tutorials about learning R and many other topics. Click here if you're looking to post or find an R/data-science job.
Want to share your content on R-bloggers? click here if you have a blog, or here if you don't.