Home > Back-end >  Loading a R package's function from Rcpp function in a new package namespace
Loading a R package's function from Rcpp function in a new package namespace

Time:01-16

I am developing a package for R and would like to load the functionalities of an R package inside an Rcpp function.

I know about Rcpp::Environment env("package:package_of_interest"), but this only works when the "package_of_interest" is loaded from R via library("package_of_interest"). Furthermore, I added the "package_of_interest" in the DESCRIPTION file below DEPENDS. That means, whenever I load my package with library("my_package") in R all functionalities are given as the desired package is auto-loaded. However, if I call the function via my_package::my_functionX(...) it drops an error and states that it can't convert the object to an environment: [type=character; target=ENVSXP]. enter image description here Is there any way to solve this problem? Can I convert the input (character) to target (ENVSXP)?

I previously studied Call a function from c via environment Rcpp and Rcpp trouble importing 'hessian' from R package 'numDeriv' and was confirmed with my approach.

In the following, I give you a minimal example to reproduce the error. With library(bigmemory) called first, this will work, but without not.

#include <iostream>
// [[Rcpp::depends(RcppArmadillo, BH, bigmemory)]]
#include <bigmemory/BigMatrix.h>
#include <bigmemory/MatrixAccessor.hpp>
#include <RcppArmadillo.h>
#include <Rdefines.h>
    
    
// [[Rcpp::export]]
void test_make_bm(std::size_t nrows, std::size_t ncols, std::string type, 
    bool separated = false, bool binarydescriptor = false, bool shared = true)
{

    // this line drops the error
    Rcpp::Environment bigmemory = Rcpp::Environment("package:bigmemory");
    // you can also directly call Rcpp::Environment bigmemory("package:bigmemory")
    
    Rcpp::Function big_matrix = bigmemory["big.matrix"];
            
    SEXP bm = big_matrix(
            Rcpp::_["nrow"] = nrows,
            Rcpp::_["ncol"] = ncols,
            Rcpp::_["type"] = type,
            Rcpp::_["init"] = R_NilValue,
            Rcpp::_["dimnames"] = R_NilValue,
            Rcpp::_["separated"] = separated,
            Rcpp::_["backingfile"] = R_NilValue,
            Rcpp::_["backingpath"] = R_NilValue,
            Rcpp::_["descriptorfile"] = R_NilValue,
            Rcpp::_["binarydescriptor"] = binarydescriptor,
            Rcpp::_["shared"] = shared);
        
    SEXP address = GET_SLOT(bm, Rf_install("address"));
    Rcpp::XPtr<BigMatrix> xptr(address);
        
    arma::mat m((double*) xptr->matrix(), xptr->nrow(), xptr->ncol());
    m.print();
    Rcpp::Rcout << "\n";
          
    return;

}

Is there any way to load the package from Rcpp? Does anyone know why bigmemory's BigMatrix has no constructor in C ?

CodePudding user response:

This is essentially the same as one of the unit test files, this has been documented behavior for as long as it existed. If you need a function from a package that is not yet attached, you need to go via the namespace.

> Rcpp::cppFunction(paste0("double mysd(NumericVector x) { ", 
       r"(Environment ns = Environment::namespace_env("stats");)", 
       r"(Function f = ns["sd"]; return as<double>(f(x)); })"))
> mysd(1:10)
[1] 3.02765
> mysd(1:10)
[1] 3.02765
> 

(I split the cppFunction() call over three lines for readability, but you can make it just one which is also how I wrote it to test this.)

CodePudding user response:

So after some research, I present you the solution. In order to get access to the packagename::package_function() functionality you have to use the namespace_env function from the Environment namespace.

#include <iostream>
// [[Rcpp::depends(RcppArmadillo, BH, bigmemory)]]
#include <bigmemory/BigMatrix.h>
#include <bigmemory/MatrixAccessor.hpp>
#include <RcppArmadillo.h>
#include <Rdefines.h>

// [[Rcpp::export]]
void test_make_bm(std::size_t nrows, std::size_t ncols, std::string type, 
    bool separated = false, bool binarydescriptor = false, bool shared = true)
{
Rcpp::Environment bigmemory = Rcpp::Environment::namespace_env("bigmemory");
   Rcpp::Function big_matrix = bigmemory["big.matrix"];
            
   SEXP bm = big_matrix(
            Rcpp::_["nrow"] = nrows,
            Rcpp::_["ncol"] = ncols,
            Rcpp::_["type"] = type,
            Rcpp::_["init"] = R_NilValue,
            Rcpp::_["dimnames"] = R_NilValue,
            Rcpp::_["separated"] = separated,
            Rcpp::_["backingfile"] = R_NilValue,
            Rcpp::_["backingpath"] = R_NilValue,
            Rcpp::_["descriptorfile"] = R_NilValue,
            Rcpp::_["binarydescriptor"] = binarydescriptor,
            Rcpp::_["shared"] = shared);
        
    SEXP address = GET_SLOT(bm, Rf_install("address"));
    Rcpp::XPtr<BigMatrix> xptr(address);
        
    arma::mat m((double*) xptr->matrix(), xptr->nrow(), xptr->ncol());
    m.print();
    Rcpp::Rcout << "\n";
          
    return;   
}
  • Related