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>
This is a new feature release, and we are very exciting about the
changes, notably Rcpp attributes which make using C++ from R even
easier than inline (see below as well as the
new
vignette for details and first examples), the extensions to Rcpp
modules (see below) and more as for example new Rcpp sugar
functions, a new error output device syncing to R, and a new namespace R>
for the statistical functions from Rmath.h
.
The complete NEWS
entry for 0.10.0 is below; more details are in the ChangeLog file in the package and on the
Rcpp Changelog page.
Thanks to CRANberries, you can also look at a diff to the previous release 0.9.15. As always, even fuller details are on the Rcpp Changelog page and the Rcpp page which also leads to the downloads, the browseable doxygen docs and zip files of doxygen output for the standard formats. A local directory has source and documentation too. Questions, comments etc should go to the rcpp-devel mailing list off the R-Forge pageChanges in Rcpp version 0.10.0 (2012-11-13)
Support for C++11 style attributes (embedded in comments) to enable use of C++ within interactive sessions and to automatically generate module declarations for packages:
Rcpp::export attribute to export a C++ function to R
sourceCpp()
function to source exported functions from a file
cppFunction()
andevalCpp()
functions for inline declarations and execution
compileAttribtes()
function to generate Rcpp modules from exported functions within a packageRcpp::depends attribute for specifying additional build dependencies for
sourceCpp()
Rcpp::interfaces attribute to specify the external bindings
compileAttributes()
should generate (defaults to R-only but a C++ include file using R_GetCCallable can also be generated)New vignette "Rcpp-attribute"
Rcpp modules feature set has been expanded:
Functions and methods can now return objects from classes that are exposed through modules. This uses the make_new_object template internally. This feature requires that some class traits are declared to indicate Rcpp's
wrap
/as
system that these classes are covered by modules. The macro RCPP_EXPOSED_CLASS and RCPP_EXPOSED_CLASS_NODECL can be used to declared these type traits.Classes exposed through modules can also be used as parameters of exposed functions or methods.
Exposed classes can declare factories with ".factory". A factory is a c++ function that returns a pointer to the target class. It is assumed that these objects are allocated with new on the factory. On the R side, factories are called just like other constructors, with the "new" function. This feature allows an alternative way to construct objects.
"converter" can be used to declare a way to convert an object of a type to another type. This gets translated to the appropriate "as" method on the R side.
Inheritance. A class can now declare that it inherits from another class with the .derives<Parent>( "Parent" ) notation. As a result the exposed class gains methods and properties (fields) from its parent class.
New sugar functions:
which_min
implements which.min. Traversing the sugar expression and returning the index of the first time the minimum value is found.
which_max
idem
unique
uses unordered_set to find unique values. In particular, the version for CharacterVector is found to be more efficient than R's version
sort_unique
calculates unique values and then sorts them.Improvements to output facilities:
Implemented
sync()
so that flushing output streams worksAdded
Rcerr
output stream (forwarding toREprintf
)Provide a namespace 'R' for the standalone Rmath library so that Rcpp users can access those functions too; also added unit tests
Development releases sets variable RunAllRcppTests to yes to run all tests (unless it was alredy set to 'no'); CRAN releases do not and still require setting – which helps with the desired CRAN default of less testing at the CRAN server farm.
Update: One link corrected.