SC2

Statistical Computing 2

2. Using Rcpp in an R package (1)


Adding a C++ function to the package

In the previous section we described the structure of a basic package created by Rcpp.package.skeleton. Here we explain how to add further C++ functions to the package and how to export them. Suppose that we would like to add the following function to our mypack package:

printFile("dotRcpp.cpp")
#include <Rcpp.h>

using namespace Rcpp;

//' Dot product in Rcpp.
//'
//' @param x1 numeric vector
//' @param x2 numeric vector
//' @return dot product, that is \code{t(x1)%*%x2}
// [[Rcpp::export(dotRcpp)]]
NumericVector dotRcpp_I(NumericVector x1, NumericVector x2)
{
  NumericVector out(1);
  out[0] = sum(x1 * x2);
  return out;
}

This function simply calculates the dot product of two numeric vectors. Notice that the function definition is preceded by some comments starting with //' Dot product in Rcpp.. These will be used by compileAttributes to build the documentation of this function. To demostrate this, we must move the function to the folder containing the source code:

system("cp dotRcpp.cpp mypack/src/dotRcpp.cpp")

then we compile the Rcpp attributes:

compileAttributes("mypack")

The R wrapper to our C++ function can be found here:

printFile("mypack/R/RcppExports.R")
# Generated by using Rcpp::compileAttributes() -> do not edit by hand
# Generator token: 10BE3573-1514-4C36-9D1C-5A225CD40393

#' Dot product in Rcpp.
#'
#' @param x1 numeric vector
#' @param x2 numeric vector
#' @return dot product, that is \code{t(x1)%*%x2}
dotRcpp <- function(x1, x2) {
    .Call(`_mypack_dotRcpp_I`, x1, x2)
}

rcpp_hello_world <- function() {
    .Call(`_mypack_rcpp_hello_world`)
}

As you can see the dots dotRcpp function is preceded by roxygen comments, which can be used to produce the corresponding .Rd files using roxygenize("mypack"). dotRcpp is a wrapper around the C++ function _mypack_dotRcpp_I, which is itself a wrapper around the internal C++ function dotRcpp_I, and it is defined here:

printFile("mypack/src/RcppExports.cpp")
// Generated by using Rcpp::compileAttributes() -> do not edit by hand
// Generator token: 10BE3573-1514-4C36-9D1C-5A225CD40393

#include <Rcpp.h>

using namespace Rcpp;

#ifdef RCPP_USE_GLOBAL_ROSTREAM
Rcpp::Rostream<true>&  Rcpp::Rcout = Rcpp::Rcpp_cout_get();
Rcpp::Rostream<false>& Rcpp::Rcerr = Rcpp::Rcpp_cerr_get();
#endif

// dotRcpp_I
NumericVector dotRcpp_I(NumericVector x1, NumericVector x2);
RcppExport SEXP _mypack_dotRcpp_I(SEXP x1SEXP, SEXP x2SEXP) {
BEGIN_RCPP
    Rcpp::RObject rcpp_result_gen;
    Rcpp::RNGScope rcpp_rngScope_gen;
    Rcpp::traits::input_parameter< NumericVector >::type x1(x1SEXP);
    Rcpp::traits::input_parameter< NumericVector >::type x2(x2SEXP);
    rcpp_result_gen = Rcpp::wrap(dotRcpp_I(x1, x2));
    return rcpp_result_gen;
END_RCPP
}
// rcpp_hello_world
List rcpp_hello_world();
RcppExport SEXP _mypack_rcpp_hello_world() {
BEGIN_RCPP
    Rcpp::RObject rcpp_result_gen;
    Rcpp::RNGScope rcpp_rngScope_gen;
    rcpp_result_gen = Rcpp::wrap(rcpp_hello_world());
    return rcpp_result_gen;
END_RCPP
}

static const R_CallMethodDef CallEntries[] = {
    {"_mypack_dotRcpp_I", (DL_FUNC) &_mypack_dotRcpp_I, 2},
    {"_mypack_rcpp_hello_world", (DL_FUNC) &_mypack_rcpp_hello_world, 0},
    {NULL, NULL, 0}
};

RcppExport void R_init_mypack(DllInfo *dll) {
    R_registerRoutines(dll, NULL, CallEntries, NULL, NULL);
    R_useDynamicSymbols(dll, FALSE);
}

The mechanisms is the same described in the previous section. Notice that the compileAttribute will be called automatically when you build your package using Rstudio or devtools.