Introduction to Rcpp
Marquette University
SCoRT - Summer 2025
evalCpp() & cppFunction()sourceCpp()Advantages:
evalCpp()evalCpp() evaluates a single C++ expression. Includes and dependencies can be declared.
This allows us to quickly check C++ constructs.
cppFunction()Rcpp::cppFunction("
bool isOdd_cpp(int num = 10) {
bool result = (num % 2 == 1);
return result;
}")
c(isOdd_cpp(42L), isOdd_cpp(43L))
># [1] FALSE TRUEcppFunction() in R console or scriptLet’s consider a simple possible \(VAR(1)\) system of \(k\) variables.
For \(k = 2\):
\[ X_t = X_{t-1} B + E_t \]
where \(X_t\) is a row vector of length \(2\), \(B\) is a \(2×2\) matrix, and \(E_t\) is a row of the error matrix of \(2\) columns.
In R (C++) code, given both the coefficient and error matrices:
Rcpp::cppFunction('arma::mat cppSim(arma::mat B, arma::mat E) {
int m = E.n_rows, n = E.n_cols;
arma::mat X(m, n);
X.row(0) = arma::zeros<arma::mat>(1, n);
for (int r = 1; r < m; r++) {
X.row(r) = X.row(r-1) * B + E.row(r);
}
return X;
}', depends="RcppArmadillo")
a <- matrix(c(0.5, 0.1, 0.1, 0.5), nrow = 2)
e <- matrix(rnorm(10000), ncol = 2)
rbenchmark::benchmark(cppSim(a, e), rSim(a, e), order="relative")[, 1:4]
># test replications elapsed relative
># 1 cppSim(a, e) 100 0.010 1.0
># 2 rSim(a, e) 100 0.728 72.8
#remotes::install_github("https://github.com/andrie/pagerank.git")
suppressMessages(library(utils))
library(pagerank)
cran <- "https://cloud.r-project.org"
pr <- compute_pagerank(cran)
round(100 * pr[1:5], 3)
># Rcpp ggplot2 dplyr MASS magrittr
># 2.744 1.516 1.274 1.122 0.814
db <- tools::CRAN_package_db() # added in R 3.4.0
db <- db[!duplicated(db[, 1]), ] # rows: number of packages
nTot <- nrow(db) # columns: different attributes
nRcpp <- length(tools::dependsOnPkgs("Rcpp", recursive = FALSE, installed = db))
nCompiled <- table(db[, "NeedsCompilation"])[["yes"]]
propRcpp <- nRcpp / nCompiled * 100
data.frame(tot = nTot, totRcpp = nRcpp, totCompiled = nCompiled,
RcppPctOfCompiled = propRcpp)
># tot totRcpp totCompiled RcppPctOfCompiled
># 1 22501 3053 4981 61.29291sourceCpp()Create standalone .cpp files with:
sourceCpp()
Consider a function defined as
\[ f(n) = \begin{cases} n & \text{when } n < 2 \\ f(n-1) + f(n-2) & \text{when } n \ge 2 \end{cases} \] that creates Fibonacci sequence. The R implementation and use:
R vectors ↔︎ C++ classes:
NumericVector, IntegerVector, CharacterVector, LogicalVectorScalars: double, int, String, bool
Key methods:
.size(), .begin(), .end()NumericVector out(n)R Type mapping:
library(Rcpp)
cppFunction("NumericVector logabs(NumericVector x) {
return log(abs(x));
}")
logabs(seq(-5, 5, by = 2))
># [1] 1.609438 1.098612 0.000000 0.000000 1.098612 1.609438log(abs()) runs directly on vectors as R would.code/logabs2.cppNot vectorized but ‘sweeps’ f() along std::vector<double> via STL std::transform().
Add to package:
LinkingTo: Rcpp in DESCRIPTIONuseDynLib(pkg) & importFrom(Rcpp, sourceCpp) in NAMESPACEusethis::use_rcpp() automates setup
Run Rcpp::compileAttributes() to generate bindings
Thirteen Simple Steps Vignette by Dirk Eddelbuettel
vignette('Rcpp-attributes')