Search code examples
c++rc++11rcppeigen3

correctly registering a plugin to use Eigen via Rcpp


I'm trying to be able to use a c++ class template in R. This was my first try at a small reproducible example.

library(inline)
library(Rcpp)
inc <- 
"#include <Eigen/Dense>

template <size_t dim>
class SillyWrapper  
{
public:
  Eigen::Matrix<double,dim,1> m_vec;
  SillyWrapper(const Eigen::Matrix<int,dim,1>& vec) : m_vec(vec);
};"
src <- 
'SillyWrapper mything(Rcpp::as<Eigen::Map<Eigen::Matrix<double,dim,1>>>(x));'

library(inline)
fun <- cxxfunction(signature(x="numeric"),
                   body=src, 
                   includes=inc, 
                   plugin="Rcpp")
fun(rnorm(3))

How to I get access to the Eigen headers, though?

On my machine they are at /usr/include/eigen3/. I think I need to "register a plugin." I'm not sure where this file path goes in. I've tried a few of the named arguments, but no luck. Here's one example of something that I've tried that doesn't work:

library(inline)
library(Rcpp)
inc <- 
'template <size_t dim>
class SillyWrapper  
{
public:
  Eigen::Matrix<double,dim,1> m_vec;
  SillyWrapper(const Eigen::Matrix<int,dim,1>& vec) : m_vec(vec);
};'
src <- 
    'SillyWrapper mything(Rcpp::as<Eigen::Map<Eigen::Matrix<double,dim,1>>>(x));'
plug <- Rcpp.plugin.maker(include.before = "#include <Eigen/Dense>", 
                          LinkingTo = "-I/usr/include/eigen3/") # correct arg name?
inline::registerPlugin("eigenDemo", plug)
fun <- cxxfunction(signature(x="numeric"),
                   body=src, 
                   includes=inc, 
                   plugin="eigenDemo")

I know there is an RcppEigen library that already exists, that would help with this example. If it's possible, I would like to see an answer that doesn't make use of this, though, because the information will be more applicable to other situations where this isn't available. Also, where do you put the c++11 flags? Apparently you can only use cxxfunction with one plugin at a time.

Edit:

Thanks @RalfStubner. For those interested, I have posted a follow-up question here.


Solution

  • Several comments:

    1. I would use Rcpp::cppFunction instead of inline::cxxfunction.
    2. As Dirk noted in the comments, why are you not using RcppEigen? In particular for Rcpp::as<Eigen::...> you will need that package anyway.
    3. It is possible to create such a plugin on the fly, but setting include paths is a bit more complicated (see example below).
    4. What are you trying to achieve? R won't know what to do with an instance of SillyWrapper.

    Example, where I have used some code from the Eigen documentation due to point 4. above:

    src <- '
    void foo() {
      Eigen::MatrixXd m(2,2);
      m(0,0) = 3;
      m(1,0) = 2.5;
      m(0,1) = -1;
      m(1,1) = m(1,0) + m(0,1);
      Rcpp::Rcout << "Here is the matrix m:\\n" << m << std::endl;
    }'
    

    Let's compile and run this code using the infrastructure provided by RcppEigen:

    Rcpp::cppFunction(code = src,
                      depends = "RcppEigen",
                      includes = "#include <Eigen/Dense>")
    
    foo()
    #> Here is the matrix m:
    #>   3  -1
    #> 2.5 1.5
    

    And now with our own plugin:

    Rcpp::registerPlugin(
        name = "Eigen3",
        plugin = function(x) {
            plug <- Rcpp::Rcpp.plugin.maker(include.before = "#include <Eigen/Dense>")
            settings <- plug()
            settings$env$PKG_CPPFLAGS = "-I/usr/include/eigen3"
            settings
        }
    )
    
    Rcpp::cppFunction(code = src,
                      plugins = "Eigen3")
    
    foo()
    #> Here is the matrix m:
    #>   3  -1
    #> 2.5 1.5
    

    Created on 2019-09-04 by the reprex package (v0.3.0)

    So while it is in principle possible to write an on-the-fly plugin for a system installed Eigen library, I am unsure how useful that would be given that RcppEigen exists.