2

I have a project in R which uses C++ functions to speed up computations. In my src-folder I have a C++ file which calls functions I have defined in different header files and C++ files in the same folder. To provide a minimum working example I have created a new project with some very small files of which I describe the contents below.

src/test_func.cpp:

#include "RcppArmadillo.h"
#include "extra1.h"


// [[Rcpp::export]]
arma::vec OLS(const arma::mat & X, const arma::vec & y)
{
    arma::vec beta = compute_b(X, y);

    return beta;
}


// [[Rcpp::export]]
arma::vec sparse_solver()
{
    arma::sp_mat X = arma::sprandu<arma::sp_mat>(1000, 1000, 0.1);
    arma::vec y(1000, arma::fill::randu);

    arma::vec beta = compute_sp_b(X, y);

    return beta;
}

src/extra1.h:

#include "RcppArmadillo.h"

arma::vec compute_b(const arma::mat & X, const arma::vec & y);
arma::vec compute_sp_b(const arma::sp_mat & X, const arma::vec & y);

src/extra1.cpp:

#define ARMA_USE_SUPERLU 1

#include "RcppArmadillo.h"
#include "extra1.h"


arma::vec compute_b(const arma::mat & X, const arma::vec & y)
{
    arma::vec b = arma::solve(X.t() * X, X.t() * y);

    return b;
}


arma::vec compute_sp_b(const arma::sp_mat & X, const arma::vec & y)
{
    arma::vec b = arma::spsolve(X, y, "superlu");

    return b;
}

Using this code via

Sys.setenv("PKG_LIBS" = "-lsuperlu")
Rcpp::sourceCpp("src/test_func.cpp")

X = matrix(rnorm(20), nrow = 10)
b = matrix(rnorm(2))
y = X %*% b + matrix(rnorm(10, 0, 0.1))

OLS(X, y)
sparse_solver()

works exactly as expected, I am able to use my functions in R without any hiccups. However, my project has grown and has far more than a single header file and corresponding cpp file and using this to recompile everything if I have made small changes to a single file is starting to take quite a bit of time. Additionally, I read in some posts online that Rcpp::sourceCpp() is not meant for compiling multiple source files and that creating a package is recommended.

To achieve this I followed instructions online and created the file structure using RcppArmadillo::RcppArmadillo.package.skeleton("Test2", example_code = FALSE), copied my source code to the src folder and ran Rcpp::compileAttributes("Test2"). Then I pressed the option Install and Restart in the Build tab in Rstudio and got the following error:

Error: package or namespace load failed for ‘Test2’ in dyn.load(file, DLLpath = DLLpath, ...):
    ... some_path/Test2.so: undefined symbol: set_default_options
Error: loading failed
Execution halted
ERROR: loading failed

Which has probably to do with the use of SuperLU by my code. If I comment out the #define ARMA_USE_SUPERLU 1 and replace "superlu" by "lapack" in arma::spsolve() the package builds without issues (but this is not really a feasible solution, as it turns the sparse matrix into a dense one). I have no experience building R packages and I can't find an example package online which uses SuperLU to solve sparse systems of equations to figure out how to get this package to build. At the moment I don't really care about portability, this package is still purely for personal use, but lately some additional reasons to turn it into an installable package have come up (I would like to also be able to call these functions from Python using the rpy2 library, for which it appears to be necessary to be an installed package).

In short, my question is if someone knows how to build packages using SuperLU or knows of an R package that uses SuperLU so I can take a look at how they were able to get it to compile.

Edit: my operating system is Ubuntu 20.04

daniel
  • 88
  • 1
  • 6
  • I _think_ that is a duplicate, and we covered this both at the Rcpp Gallery, possibly here too, and on the mailing list. – Dirk Eddelbuettel May 07 '21 at 19:18
  • In the Rcpp Gallery I could only find the way to compile a program using SuperLU using the Rcpp::sourceCpp() approach which I also described in my question. I don't know how this relates to actually building the package. How should I incorporate the ```Sys.setenv("PKG_LIBS" = "-lsuperlu")``` in building the package? – daniel May 07 '21 at 19:25
  • 1
    See my recent-ish arXiv paper also added as vignette [Rcpp-libraries](https://cloud.r-project.org/web/packages/Rcpp/vignettes/Rcpp-libraries.pdf) -- it is more involved with libraries requiring a link step. What if your users do not have SuperLU on their system? – Dirk Eddelbuettel May 07 '21 at 19:32
  • Ideally I would like to make the use of SuperLU conditional on whether it is present. If it is not, the alternative would be transforming the sparse matrix into a dense one and using the lapack solver. – daniel May 07 '21 at 20:47
  • 1
    That can be done. A number of my packages have `autoconf` code in script `configure` to detect presence. You can build on that. – Dirk Eddelbuettel May 07 '21 at 21:01

0 Answers0