JJ Allaire
May 29th, 2013
Origins of S
Languages in R and CRAN
Native Code: Problems and Opportunities
Can We Have the Best of Both Worlds?
On May 5th, 1976, a group of users from the statistics research group at Bell Labs discussed creating a new system for statistical computing. Some of the requirements:
Language | Percent |
---|---|
C | 52% |
Fortran | 26% |
R | 22% |
librestats (8/27/11)
Language | Percent |
---|---|
R | 48% |
C/C++ | 46% |
Fortran | 5% |
Perl | 1% |
librestats (8/29/11)
Native Code
Interpeted Code
What's Difficult About C++?
#include <R.h>
#include <Rinternals.h>
SEXP reverse(SEXP x) {
SEXP res;
int i, r, P=0;
PROTECT(res = Rf_allocVector(
REALSXP, Rf_length(x)));
for(i=Rf_length(x), r=0; i>0; i--, r++)
REAL(res)[r] = REAL(x)[i-1];
UNPROTECT(1);
return res;
}
R System/Library Developers
R Users
We can do better for R users!
R users need a system that:
The Rcpp Package
Why “Attributes”?
Interactive C++ with sourceCpp
Some Examples
// Matrix of 4 rows & 5 columns
NumericMatrix xx(4, 5);
// Fill with value
int xsize = xx.nrow() * xx.ncol();
for (int i = 0; i < xsize; i++) {
xx[i] = 7;
}
// Assign to single element
xx(0,1) = 4;
NumericVector x = NumericVector::create(
-2.0, -1.0, 1.0, 2.0);
NumericVector xAbs = abs( x );
NumericVector xCeiling = ceiling( x );
NumericVector xFloor = floor( x );
bool b = all( x < 3.0 ).is_true();
// lookup rnorm function
Environment stats("package:stats");
Function rnorm = stats["rnorm"];
// call rnorm function
rnorm(100,
_["mean"] = 10.2,
_["sd"] = 3.2);
// raise an R error
if (failed)
stop("an unexpected error occurred!");
#include <Rcpp.h>
using namespace Rcpp;
// [[Rcpp::export]]
double piCpp(int N) {
NumericVector x = runif(N);
NumericVector y = runif(N);
NumericVector d = sqrt(x*x + y*y);
return 4.0 * sum(d < 1.0) / N;
}
> sourceCpp("pi.cpp")
> piCpp(1000)
[1] 3.048
Attributes are annotations added to source code to express intent or automatically generate code (i.e. compiler extensions). They are part of the C++11 standard.
[[omp::parallel]]
void someFunction() {}
In R we use compilers that don't (yet) support C++11, so attributes are added as specially formatted comments:
// [[Rcpp::export]]
sourceCpp
is a function that sources C++ files just as the source
function sources R files[[Rcpp::export]]
attribute are made available to Rset.seed(42)
y <- rnorm(100000)
benchmark(runSumCpp(y, 4500),
runSumR(y, 4500),
order = "relative")[,1:4]
reps time rel
1 runSumCpp(y, 4500) 100 0.082 1.00
2 runSumR(y, 4500) 100 33.717 411.18
http://gallery.rcpp.org/articles/transforming-a-matrix/
sourceCpp("matrix.cpp")
m <- matrix(c(1,2,3, 11,12,13),
nrow = 2, ncol=3)
matrixSqrt(m)
[,1] [,2] [,3]
[1,] 1.000000 1.732051 3.464102
[2,] 1.414214 3.316625 3.605551
http://gallery.rcpp.org/articles/creating-xts-from-c++/
library(xts)
sourceCpp("xts.cpp")
foo <- createXts(1, 4)
foo
[,1]
1970-01-02 1
1970-01-03 2
1970-01-04 3
1970-01-05 4
You can use the [[Rcpp::depends]]
attribute to declare a dependency on an R package.
The inclusion of the [[Rcpp::depends]]
attribute causes sourceCpp
to configure the build environment to correctly compile and link against the package
Dependencies are discovered both by scanning for package include directories and by invoking inline plugins if they are available for a package.
[[Rcpp::plugins]]
attribute loads inline plugins http://gallery.rcpp.org/articles/simple-lambda-func-c++11/
sourceCpp("cpp11.cpp")
transformEx(c(1:5))
[1] 1 4 9 16 25
sourceCpp
can be seamlessly moved into packages for sharing with a wider audience.Rcpp::compileAttributes
function should be called prior to building the package – this automatically generates the required R and C++ bindings.Rcpp::depends
doesn't work in packages, rather the standard mechanism of the package DESCRIPTION
file is used.src
directory of the package looking for [[Rcpp::export]]
attributes.R/RcppExports.R
src/RcppExports.cpp
Bootstrap via Rcpp.package.skeleton
Package with hello, world example:
Rcpp.package.skeleton(
"NewPackage", attributes=TRUE)
Package from existing cpp file:
Rcpp.package.skeleton(
"NewPackage", cpp_files=c("foo.cpp"))
Source file identical to what we'd use with sourceCpp
Need to call compileAttributes
right before building the package
Tools that automatically call compileAttributes
:
Also supports transposing roxygen2 comments
Two talks worth watching to get a flavor for what's happening in modern C++:
Not Your Father's C++ Herb Sutter (Chair, ISO C++ Standards Committee) http://goo.gl/N9YbS
Clang: Defending C++ from Murphy's Million Monkey's
Chandler Carruth (Google)
http://goo.gl/ixNGP
Contains a wealth of articles (all with full source code) demonstrating the use of Rcpp.