-
Notifications
You must be signed in to change notification settings - Fork 11
Rcpp in ade4
To use C++ functions with Rcpp in the ade4 package, one needs to:
- Install the Rcpp package
- Install the RcppArmadillo package (if needed)
- Modify several files
Source files:
- Files containing C++ code (.cpp) in the "src" folder
- Files containing R code (.R) in the "R" folder
- Files containing Rd code (.Rd) in the "man" folder
- Add aliases for C++ functions in file "man/ade4-internals.Rd"

R System files:
- DESCRIPTION file
- NAMESPACE file
"DESCRIPTION" file: To be done only once (should be done already !)
- In the "Imports:" field, add Rcpp (and RcppArmadillo, if needed)
- Add the "LinkingTo:" field, and add Rcpp to it
"NAMESPACE" file: Export all the added functions (R and C++):
- export("RV.randtest")
- export("RVrandtestCpp")

Two files, RcppExports.cpp and RcppExports.R are created automatically by the Rcpp::compileAttributes() function.
- In the "src" folder : File RcppExports.cpp contains the declaration of C++ functions
- In the "R" folder : File RcppExports.R contains the declaration of R functions
Warning ! These two files are re-generated automatically each time the Rcpp::compileAttributes() is called.
File RcppExports.cpp : nothing to change. The header string "ade4" is added to the beginning of the name of each exported function.
// Generated by using Rcpp::compileAttributes() -> do not edit by hand
// Generator token: 10BE3573-1514-4C36-9D1C-5A225CD40393
#include <RcppArmadillo.h>
#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
// RVintrarandtestCpp
arma::vec RVintrarandtestCpp(const arma::mat& X, const arma::mat& Y, Rcpp::IntegerVector fac, const int nrepet);
RcppExport SEXP _ade4_RVintrarandtestCpp(SEXP XSEXP, SEXP YSEXP, SEXP facSEXP, SEXP nrepetSEXP) {
BEGIN_RCPP
Rcpp::RObject rcpp_result_gen;
Rcpp::RNGScope rcpp_rngScope_gen;
Rcpp::traits::input_parameter< const arma::mat& >::type X(XSEXP);
Rcpp::traits::input_parameter< const arma::mat& >::type Y(YSEXP);
Rcpp::traits::input_parameter< Rcpp::IntegerVector >::type fac(facSEXP);
Rcpp::traits::input_parameter< const int >::type nrepet(nrepetSEXP);
rcpp_result_gen = Rcpp::wrap(RVintrarandtestCpp(X, Y, fac, nrepet));
return rcpp_result_gen;
END_RCPP
}
File RcppExports.R (in the "R" folder), the header string "C_" must be added to the beginning of each function name in the call to the .Call function (see first line of NAMESPACE file).
# Generated by using Rcpp::compileAttributes() -> do not edit by hand
# Generator token: 10BE3573-1514-4C36-9D1C-5A225CD40393
RVintrarandtestCpp <- function(X, Y, fac, nrepet) {
.Call(`C__ade4_RVintrarandtestCpp`, X, Y, fac, nrepet)
}
RVrandtestCpp <- function(X, Y, nrepet) {
.Call(`C__ade4_RVrandtestCpp`, X, Y, nrepet)
}
procusterandtestCpp <- function(X, Y, nrepet) {
.Call(`C__ade4_procusterandtestCpp`, X, Y, nrepet)
}
Another file must be edited manually: file "init.c" in the "src" folder. It contains the definitions of all the external functions (C and C++). The new C++ function must be added there, replacing all arguments by void * and adding the number of arguments.
- C function definitions go to the static const R_CMethodDef CEntries[] = { parameter
- C++ function definitions go to the static const R_CallMethodDef CallEntries[] = { parameter
- Header string "C_" must NOT be added before each function names
Note that this file is NOT rebuilt automatically by function Rcpp::compileAttributes().
#include <R.h>
#include <Rinternals.h>
#include <stdlib.h> // for NULL
#include <R_ext/Rdynload.h>
/* .C calls */
extern void gearymoran(void *, void *, void *, void *, void *, void *, void *);
extern void MSTgraph(void *, void *, void *, void *);
etc...
/* .Call calls */
extern void _ade4_RVrandtestCpp(void *, void *, void *);
extern void _ade4_RVintrarandtestCpp(void *, void *, void *, void *);
etc...
static const R_CMethodDef CEntries[] = {
{"gearymoran", (DL_FUNC) &gearymoran, 7},
{"MSTgraph", (DL_FUNC) &MSTgraph, 4},
etc...
static const R_CallMethodDef CallEntries[] = {
{"_ade4_procusterandtestCpp", (DL_FUNC) &_ade4_procusterandtestCpp, 3},
{"_ade4_RVrandtestCpp", (DL_FUNC) &_ade4_RVrandtestCpp, 3},
etc...
void R_init_ade4(DllInfo *dll)
{
R_registerRoutines(dll, CEntries, CallEntries, NULL, NULL);
R_useDynamicSymbols(dll, FALSE);
}
Notes:
- Once everything is set up, one can compile the ade4 package as usual with R CMD build/check/install.
- During development stages, function Rcpp::sourceCpp() can be used to compile and execute C++ functions, without re-building the whole package.
- Function Rcpp::compileAttributes() should be used to update the new C++ function definitions in files RcppExports.cpp and RcppExports.R, but the header string "C_" must be added manually each time before each function name in file RcppExports.R.
- Warning ! When using Rstudio for the "check" step, function Rcpp::compileAttributes(), will change files RcppExports.cpp and RcppExports.R. So the header string "C_" will be missing before function names, and compilation will fail.
Using a library of C++ functions:
- As in the case of C functions, C++ functions can be collected in a library.
- For C functions, file src/tests.c contains the permutation tests functions (testinter, testdiscrimin, testertrace, etc.)
- There is also the src/adesub.c file that contains "base" functions, (matrix computations, dynamic memory allocation, random permutations, etc.) The definitions of these functions are in the src/adesub.h file.
- For C++ functions, file testsCpp.cpp contains permutation test functions re-written in C++ (for example, testinter becomes testinterCpp, etc.)
- "Base" C++ functions (equivalent to the C functions in adesub.c) are grouped in file src/ade4libCpp.cpp and their definitions are in file inst/include/ade4libCpp.h.