Site icon R-bloggers

R Package Integration with Modern Reusable C++ Code Using Rcpp – Part 2

[This article was first published on R Views, and kindly contributed to R-bloggers]. (You can report issue about the content on this page here)
Want to share your content on R-bloggers? click here if you have a blog, or here if you don't.

Daniel Hanson is a full-time lecturer in the Computational Finance & Risk Management program within the Department of Applied Mathematics at the University of Washington. His appointment followed over 25 years of experience in private sector quantitative development in finance and data science.

In the first post in this series, we looked at configuring a Windows 10 environment for using the Rcpp package. However, what follows below, and going forward, is applicable to an up-to-date R, RStudio, and Rcpp configuration on any operating system.

Today, we will examine design considerations in integrating standard and portable C++ code in an R package, using Rcpp in the interface level alone. This will ensure no R-related dependencies are introduced into the C++ code base. In general, of course, best programming practices say we should strive to keep interface and implementation separate.

Design Considerations

For this discussion, we will assume the package developer has access to a repository of standard C++ code that is intended for use with other mathematical or scientific applications and interfaces. The goal is integrate this code into an R package, and then export functions to R that will use this existing C++ code. The end users need not be concerned that they are using C++ code; they will only see the exported functions that can be used and called like any other R function.

The package developer, at this stage, has two components that cannot communicate with each other, at least yet:

Establishing Communication

This is where Rcpp comes in. We will create an interface layer that utilizes functions and objects in the Rcpp C++ namespace that facilitate communication between R and C++. This interface will ensure that no dependence on R or Rcpp is introduced into our reusable code base.

The Rcpp namespace contains a treasure trove of functions and objects that abstract away the terse underlying C interface provided by R, making our job far less painful. However, at this initial stage, to keep the discussion focused on a basic interface example, we will limit our use of Rcpp functions to facilitate the transfer of numeric vector data in R to the workhorse STL container std::vector<double>, which is of course ubiquitous in quantitative C++ code.

Tags to Indicate Interface Functions

C++ interface functions are indicated by a tag that needs to be placed just above the function name and signature. It is written as

// [[Rcpp::export]]

This tag instructs the package build process to export a function of the exact same name to R. As an interface function, it will take arguments from an R session, route them in a call to a function or class in the C++ code base, and then take the results that are returned and pass them back to the calling function in R.

Conversion between R Vectors and C++ Vectors

The Rcpp::NumericVector class, as its name suggests, stores data taken from an R numeric vector, but what makes Rcpp even more powerful here is its inclusion of the C++ template function Rcpp::as<T>(.). This function safely and efficiently copies the contents of an Rcpp::NumericVector to a std::vector<double> object, as demonstrated in Figure 3, below.

Remark: Rcpp also has the function Rcpp::wrap(.), which copies values in an STL vector back into an Rcpp::NumericVector object, so that the results can then be to R; this function will be covered in our next article in this series.

A C++ Interface Function

Figure 3 shows a mythical Rcpp interface function at the top, called fcn(.), and a function in our reusable standard C++ code base called doSomething(.). Note first the tag that appears just above the interface function signature. It must be exactly one line above, and there must be a single space only between the second forward slash and the first left square bracket.

This interface function will be exported to R, where it can be called by the same function name, fcn(.), taking in an R numeric vector input. The Rcpp::NumericVector object takes this data in as the input to C++. The contents are then transferred to a C++ std::vector<double>, using the Rcpp template function Rcpp::as<vector<double>>(.).

The data can then be passed to the doSomething(.) function in the standard C++ code base, as it is expecting a std::vector<double> input. This function returns the C++ double variable ret to the variable y in the interface function. This requires no special conversion and can be passed back to R as a C++ double type.

Putting the High-Level Design Together

With the C++ interface in place, this means an R user can call an R function that has been exported from C++. When the results are returned, they can be used in other R functions, but where we get an extraordinarily complementary benefit is with R’s powerful data visualization capabilities. Unlike languages such as Python, Java, or VB.NET, C++ does not have a standard GUI, but we can use cutting-edge R packages such as ggplot2, plotly, shiny, and xts – among many others – to generate a massive variety of plots and visualizations that are simply not available in other general purpose languages.

Next Steps

This concludes our discussion of high-level design considerations. Coming next, we will look at examples of writing actual interface functions to simple, but real, standard C++ functions and classes.

To leave a comment for the author, please follow the link and comment on their blog: R Views.

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.