Casting a MatrixXd to a Matrix3d with RcppEigen - r

With RcppEigen, I need a Matrix3d as an argument of a function. But this is not possible, it only accepts MatrixXd. I've tried to cast as follows but that doesn' work:
Rcpp::List MtoAxisAngle(Eigen::MatrixXd & m)
{
Eigen::Matrix3d m3 = m.cast();
......
Any solution ?

You can use the existing matrix in the initialization of the new matrix:
// [[Rcpp::depends(RcppEigen)]]
#include <RcppEigen.h>
// [[Rcpp::export]]
Rcpp::List MtoAxisAngle(Eigen::MatrixXd & m)
{
Eigen::Matrix3d m3(m);
return Rcpp::List::create(Rcpp::Named("size") = m3.size());
}
/*** R
MtoAxisAngle(matrix(1:9,3,3))
# MtoAxisAngle(matrix(1:16,4,4))
*/
Since a call with a non-conforming matrix kills R, you should check beforehand if the size is correct.

Related

how to create a Rcpp NumericVector from Eigen::Tensor without copying underlying data

If I create a large Tensor in Eigen, and I like to return the Tensor back to R as multi-dimension array. I know how to do it with data copy like below. Question: is it possible to do it without the data-copy step?
#include <Rcpp.h>
#include <RcppEigen.h>
#include <unsupported/Eigen/CXX11/Tensor>
// [[Rcpp::depends(RcppEigen)]]
using namespace Rcpp;
template <typename T>
NumericVector copyFromTensor(const T& x)
{
int n = x.size();
NumericVector ans(n);
IntegerVector dim(x.NumDimensions);
for (int i = 0; i < x.NumDimensions; ++i) {
dim[i] = x.dimension(i);
}
memcpy((double*)ans.begin(), (double*)x.data(), n * sizeof(double));
ans.attr("dim") = dim;
return ans;
}
// [[Rcpp::export]]
NumericVector getTensor() {
Eigen::Tensor<double, 3> x(4, 3, 1);
x.setRandom();
return copyFromTensor(x);
}
/*** R
getTensor()
*/
As a general rule you can zero-copy one the way into your C++ code with data coming from R and already managed by R.
On the way out of your C++ code with data returning to R anything that is not created used the R allocator has to be copied.
Here your object x is a stack-allocated so you need a copy. See Writing R Extensions about the R allocator; Eigen may let you use it when you create a new Tensor object. Not a trivial step. I think I would just live with the copy.

RcppArmadillo's sample() is ambiguous after updating R

I commonly work with a short Rcpp function that takes as input a matrix where each row contains K probabilities that sum to 1. The function then randomly samples for each row an integer between 1 and K corresponding to the provided probabilities. This is the function:
// [[Rcpp::depends(RcppArmadillo)]]
#include <RcppArmadilloExtensions/sample.h>
using namespace Rcpp;
// [[Rcpp::export]]
IntegerVector sample_matrix(NumericMatrix x, IntegerVector choice_set) {
int n = x.nrow();
IntegerVector result(n);
for ( int i = 0; i < n; ++i ) {
result[i] = RcppArmadillo::sample(choice_set, 1, false, x(i, _))[0];
}
return result;
}
I recently updated R and all packages. Now I cannot compile this function anymore. The reason is not clear to me. Running
library(Rcpp)
library(RcppArmadillo)
Rcpp::sourceCpp("sample_matrix.cpp")
throws the following error:
error: call of overloaded 'sample(Rcpp::IntegerVector&, int, bool, Rcpp::Matrix<14>::Row)' is ambiguous
This basically tells me that my call to RcppArmadillo::sample() is ambiguous. Can anyone enlighten me as to why this is the case?
There are two things happening here, and two parts to your problem and hence the answer.
The first is "meta": why now? Well we had a bug let in the sample() code / setup which Christian kindly fixed for the most recent RcppArmadillo release (and it is all documented there). In short, the interface for the very probability argument giving you trouble here was changed as it was not safe for re-use / repeated use. It is now.
Second, the error message. You didn't say what compiler or version you use but mine (currently g++-9.3) is actually pretty helpful with the error. It is still C++ so some interpretative dance is needed but in essence it clearly stating you called with Rcpp::Matrix<14>::Row and no interface is provided for that type. Which is correct. sample() offers a few interface, but none for a Row object. So the fix is, once again, simple. Add a line to aid the compiler by making the row a NumericVector and all is good.
Fixed code
#include <RcppArmadillo.h>
#include <RcppArmadilloExtensions/sample.h>
// [[Rcpp::depends(RcppArmadillo)]]
using namespace Rcpp;
// [[Rcpp::export]]
IntegerVector sample_matrix(NumericMatrix x, IntegerVector choice_set) {
int n = x.nrow();
IntegerVector result(n);
for ( int i = 0; i < n; ++i ) {
Rcpp::NumericVector z(x(i, _));
result[i] = RcppArmadillo::sample(choice_set, 1, false, z)[0];
}
return result;
}
Example
R> Rcpp::sourceCpp("answer.cpp") # no need for library(Rcpp)
R>

Rcpp: call functions from existing R packages when building cppFunction() [duplicate]

I am considering calling a R function from c++ via environment, but I got an error, here is what I did
#include <Rcpp.h>
using namespace Rcpp;
// [[Rcpp::export]]
NumericVector call(NumericVector x){
Environment env = Environment::global_env();
Function f = env["fivenum"];
NumericVector res = f(x);
return res;
}
Type call(x), this is what I got,
Error: cannot convert to function
I know I can do it right in another way,
#include <Rcpp.h>
using namespace Rcpp;
// [[Rcpp::export]]
NumericVector callFunction(NumericVector x, Function f) {
NumericVector res = f(x);
return res;
}
and type
callFunction(x,fivenum)
But still wondering why first method failed.
fivenum function is not defined in the global environment but in the stats package enviroment, so you should get it from that:
...
Environment stats("package:stats");
Function f = stats["fivenum"];
...
In addition to #digEmAll's answer, I would like to mention a more general approach, which mimics R's packagename::packagefunctionX(...) approach.
The advantage is that you don't have to call library("dependend_library"), i.e., in this case, library(stats). That is useful when you call a function from your package, without previously calling library.
// [[Rcpp::export]]
Rcpp::NumericVector five_nums(Rcpp::NumericVector x){
Rcpp::Environment stats = Rcpp::Environment::namespace_env("stats");
Rcpp::Function f = stats["fivenum"];
return Rcpp::NumericVector(f(x));
}
/*** R
five_nums(stats::rnorm(25, 2, 3))
*/

Call R functions in RcppArmadillo with armadillo data type

I am translating my R code with some prepared functions to RcppArmadillo. I want to use some of these functions directly in my Rcpp code,instead of translating. For example, I want to call the sigma2 function:
sigma2<- function(xi.vec,w.vec,log10lambda,n,q){
lambda <- 10^log10lambda
(1/(n-q))*sum((lambda*xi.vec*(w.vec^2))/(lambda*xi.vec+1))
}
A typical Rcpp code is as below:
#include <RcppArmadillo.h>
// [[Rcpp::depends(RcppArmadillo)]]
// [[Rcpp::export]]
SEXP myS(){
Rcpp::Environment myEnv = Rcpp::Environment::global_env();
Rcpp::Function myS = myEnv["sigma2"];
arma::vec xvec = myEnv["xi.vec"];
arma::vec wvec = myEnv["w.vec"];
double l = myEnv["log10lambda"];
int n = myEnv["n"];
int q = myEnv["q"];
return myS(Rcpp::Named("xi.vec",xvec),
Rcpp::Named("w.vec",wvec),
Rcpp::Named("l",l),
Rcpp::Named("n",n),
Rcpp::Named("q",q));
}
Of course it works. But my problem is that in my case, the parameters of sigma2 function should be defined before as output of another function(say func1) in RcppArmadillo and they have armadillo data type. For instance, xi.vec and w.vec have vec type. Now I want to know how can I modified this code to call sigma2? Do I need to change my environment?
First, just say no to embedding R functions and environments into C++ routines. There is no speedup in this case; only a considerable slowdown. Furthermore, there is a greater potential for things to go cockeye if the variables are not able to be retrieved in the global.env scope.
In your case, you seem to be calling myS() from within myS() with no terminating condition. Thus, your function will never end.
e.g.
SEXP myS(){
Rcpp::Function myS = myEnv["sigma2"];
return myS(Rcpp::Named("xi.vec",xvec),
Rcpp::Named("w.vec",wvec),
Rcpp::Named("l",l),
Rcpp::Named("n",n),
Rcpp::Named("q",q));
}
Switch one to be myS_R and myS_cpp.
Regarding environment hijacking, you would need to pass down to C++ the values. You cannot reach into an R function to obtain values specific passed to it before it is called.
e.g.
SEXP myS_cpp(arma::vec xvec, arma::vec wvec, double l, int n, int q){
// code here
}

Call a function from c++ via environment Rcpp

I am considering calling a R function from c++ via environment, but I got an error, here is what I did
#include <Rcpp.h>
using namespace Rcpp;
// [[Rcpp::export]]
NumericVector call(NumericVector x){
Environment env = Environment::global_env();
Function f = env["fivenum"];
NumericVector res = f(x);
return res;
}
Type call(x), this is what I got,
Error: cannot convert to function
I know I can do it right in another way,
#include <Rcpp.h>
using namespace Rcpp;
// [[Rcpp::export]]
NumericVector callFunction(NumericVector x, Function f) {
NumericVector res = f(x);
return res;
}
and type
callFunction(x,fivenum)
But still wondering why first method failed.
fivenum function is not defined in the global environment but in the stats package enviroment, so you should get it from that:
...
Environment stats("package:stats");
Function f = stats["fivenum"];
...
In addition to #digEmAll's answer, I would like to mention a more general approach, which mimics R's packagename::packagefunctionX(...) approach.
The advantage is that you don't have to call library("dependend_library"), i.e., in this case, library(stats). That is useful when you call a function from your package, without previously calling library.
// [[Rcpp::export]]
Rcpp::NumericVector five_nums(Rcpp::NumericVector x){
Rcpp::Environment stats = Rcpp::Environment::namespace_env("stats");
Rcpp::Function f = stats["fivenum"];
return Rcpp::NumericVector(f(x));
}
/*** R
five_nums(stats::rnorm(25, 2, 3))
*/

Resources