RcppArmadillo and C++ division issue - rcpp

A very simple question regarding RcppArmadillo. Trying to multiply a vector by a scalar, and getting different results depending on small changes in syntax.
Any ideas?
// [[Rcpp::depends("RcppArmadillo")]]
// [[Rcpp::export]]
arma::vec funtemp(arma::vec x)
{
// return(x/10); // this works
// return((1/10)*x); // this does not work
return(x*(1/10)); // this does not work
}

Ahh, the good ol' integer vs. double division problem in C++. Before we begin, note that: arma::vec is by default a double and 1, 10, 1/10 are all ints...
Let's take a look at your functions separately:
#include <RcppArmadillo.h>
// [[Rcpp::depends("RcppArmadillo")]]
// [[Rcpp::export]]
arma::vec funtemp_one(arma::vec x)
{
return(x/10); // this works
}
// [[Rcpp::export]]
arma::vec funtemp_two(arma::vec x)
{
return((1/10)*x); // this does not work
}
// [[Rcpp::export]]
arma::vec funtemp_three(arma::vec x)
{
return(x*(1/10)); // this does not work
}
Therefore, when we run through your problem we get:
> funtemp_one(1)
[,1]
[1,] 0.1
> funtemp_two(1)
[,1]
[1,] 0
> funtemp_three(1)
[,1]
[1,] 0
In the later functions (e.g. the 1/10), the operator/ that is being used is int based division. As a result, 2 ints enter and 1 int is returned. If the result is not divisible, then you end up with a zero being returned as it is outside of the integer scope.
In order to use the double version, which returns a double, at least one of the ints must be explicitly cast to a double. This happens by default in the first case as you have a double/int due to arma::vec's structure. The second and third cases have an int/int structure that can be dealt with in two ways: 1. use a .0 after the int or 2. explicitly cast the value as a double with double(int)
e.g.
// [[Rcpp::export]]
arma::vec funtemp_four(arma::vec x)
{
return(x*(1/10.0)); // this works
}
// [[Rcpp::export]]
arma::vec funtemp_five(arma::vec x)
{
return(x*(1/double(10))); // this works
}
Will give what you expect:
> funtemp_four(1)
[,1]
[1,] 0.1
> funtemp_five(1)
[,1]
[1,] 0.1

Related

Conversion of Rcpp::NumericMatrix to Eigen::MatrixXd

I am facing a very similar issue to these questions:
convert Rcpp::NumericVector to Eigen::VectorXd
Converting between NumericVector/Matrix and VectorXd/MatrixXd in Rcpp(Eigen) to perform Cholesky solve
I am writing an R-package, that uses the RcppEigen library for Matrix arithmetic. My problem is that the project is not compiling because of an error in the conversion of the Rcpp::NumericMatrix input to an Eigen::MatrixXd.
The file looks like this:
#include <map>
#include <Rcpp.h>
...
using namespace Eigen;
...
// [[Rcpp::export]]
Rcpp::List my_function(Rcpp::NumericMatrix input_matrix)
{
...
Map<MatrixXd> GATE_matrixx(Rcpp::as<Map<MatrixXd> >(GATE_matrix));
...
}
This gives me the following error:
Myfile.cpp:40:65: required from here
C:/Users/User/AppData/Local/Programs/R/R-4.2.2/library/Rcpp/include/Rcpp/internal/Exporter.h:31:31:error:
matching function for call to 'Eigen::Map<Eigen::Matrix<double, -1,
-1> >::Map(SEXPREC*&) 31 | Exporter( SEXP x ) : t(x) | ^ In file included from
C:/Users/User/AppData/Local/Programs/R/R-4.2.2/library/RcppEigen/include/Eigen/Core:19
from
C:/Users/User/AppData/Local/Programs/R/R-4.2.2/library/RcppEigen/include/Eigen/SparseCore:11
from
C:/Users/User/AppData/Local/Programs/R/R-4.2.2/library/RcppEigen/include/Eigen/Sparse:26
from Myfile.cpp:8
I have also tried to change the line to:
MatrixXd input_matrix_eigen(Rcpp::as\<MatrixXd\>(input_matrix));
This gives me the equivalent error :
Myfile.cpp:40:54: required from here
C:/Users/User/AppData/Local/Programs/R/R
4.2.2/library/RcppEigen/include/Eigen/src/Core/Matrix.h:332:31:error: matching function for call to 'Eigen::Matrix<double, -1,
-1>::_init1<SEXPREC*>(SEXPREC* const&)
Do you have any ideas?
If more information is required to evaluate the issue, just let me know.
If you use the command
RcppEigen::RcppEigen.package.skeleton("demoPackage")
an example package demoPackage is created for you which you can install the usual way. It contains example functions to create amd return a matrix:
// [[Rcpp::export]]
Eigen::MatrixXd rcppeigen_hello_world() {
Eigen::MatrixXd m1 = Eigen::MatrixXd::Identity(3, 3);
// Eigen::MatrixXd m2 = Eigen::MatrixXd::Random(3, 3);
// Do not use Random() here to not promote use of a non-R RNG
Eigen::MatrixXd m2 = Eigen::MatrixXd::Zero(3, 3);
for (auto i=0; i<m2.rows(); i++)
for (auto j=0; j<m2.cols(); j++)
m2(i,j) = R::rnorm(0, 1);
return m1 + 3 * (m1 + m2);
}
If you set the same seed as I do you should get the same matrix
> set.seed(42)
> demoPackage::rcppeigen_hello_world()
[,1] [,2] [,3]
[1,] 8.11288 -1.694095 1.089385
[2,] 1.89859 5.212805 -0.318374
[3,] 4.53457 -0.283977 10.055271
>

Fill a NumericMatrix with a single value on construction

I'm trying to fill a NumericMatrix with a single value on construction. As an example, consider the following:
#include <Rcpp.h>
using namespace Rcpp;
// [[Rcpp::export]]
void test() {
NumericMatrix res(1, 1, NA_REAL);
}
This is throwing the error of:
error: call to constructor of 'Vector<14, PreserveStorage>' is ambiguous
VECTOR( start, start + (static_cast<R_xlen_t>(nrows_)*ncols) ),
^ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
file46e92f4e027d.cpp:6:17: note: in instantiation of function template specialization 'Rcpp::Matrix<14, PreserveStorage>::Matrix<double>' requested here
NumericMatrix res(1, 1, NA_REAL);
/Library/Frameworks/R.framework/Versions/4.0/Resources/library/Rcpp/include/Rcpp/vector/Vector.h:88:5: note: candidate constructor [with T = double]
Vector( const T& size, const stored_type& u,
^
/Library/Frameworks/R.framework/Versions/4.0/Resources/library/Rcpp/include/Rcpp/vector/Vector.h:211:5: note: candidate constructor [with InputIterator = double]
Vector( InputIterator first, InputIterator last){
^
Why is a NumericMatrix unable to be instantiated with a single value alongside fixed dimensions?
So in short this works (one longer line broken in three for display):
> Rcpp::cppFunction("NumericVector fp() {
+ NumericVector res(3,NA_REAL);
+ return res;}")
> fp()
[1] NA NA NA
>
but there is no matching constructor using rows, cols for matrices. So you have to use what vectors give you above, and set dimensions by hand.
For example via (where I had it all in one line which I broke up here for exposition)
> Rcpp::cppFunction("NumericMatrix fp(int n, int k) {
+ NumericVector res(n*k,NA_REAL);
+ res.attr(\"dim\") = IntegerVector::create(n,k);
+ return NumericMatrix(res);}")
> fp(2,3)
[,1] [,2] [,3]
[1,] NA NA NA
[2,] NA NA NA
>
Not to usurp Dirk, but there isn't a need to set the dimensions of the matrix with .attr().
Filling a matrix, unlike a vector, requires supplying an iterator with n * p elements alongside dimensions for the constructor.
Matrix(const int& nrows_, const int& ncols, Iterator start)
For other constructors, please see: inst/include/Rcpp/vector/Matrix.h
With this in mind, the original example can be changed to:
#include <Rcpp.h>
using namespace Rcpp;
// [[Rcpp::export]]
Rcpp::NumericMatrix matrix_fill_by_vec(int n, int p) {
// fill matrix using a vector
Rcpp::NumericVector A = Rcpp::NumericVector(n * p, NA_REAL);
Rcpp::NumericMatrix B = Rcpp::NumericMatrix(n, p, A.begin());
return B;
}
Taking it for a test drive, we get:
matrix_fill_by_vec(3, 2)
# [,1] [,2]
# [1,] NA NA
# [2,] NA NA
# [3,] NA NA

Apply lambda function to `arma::cube` in `RcppArmadillo`

I tried to use RcppArmadillo to compute the Frobenious norm across each slice of an array(arma::cube). The example code in file cxxFuns.cpp is presented below.
// [[Rcpp::depends(RcppArmadillo)]]
#include "RcppArmadillo.h"
// [[Rcpp::export]]
arma::vec array_norm (arma::cube & x) {
arma::vec out = x.each_slice([](arma::mat& x0) {return arma::norm(x0, "fro") ;}) ;
return out ;
}
After the cpp file is compiled successfully, the function array_norm throws an exception:
set.seed(2020)
Rcpp::sourceCpp('cxxFuns.cpp')
x <- array(rnorm(3*4*5), 3:5)
array_norm(x)
#> error: copy into matrix: can't interpret cube with dimensions 3x4x5 as a vector
#> Error in array_norm(x) :
#> copy into matrix: can't interpret cube with dimensions 3x4x5 as a vector
Created on 2020-12-02 by the reprex package (v0.3.0)
That actually an error message from Armadillo because something is not right with your logic yet -- the result is not a vector. You can see that by changing to this (self-contained, a very nice Rcpp trick) code:
Code
// [[Rcpp::depends(RcppArmadillo)]]
#include "RcppArmadillo.h"
// [[Rcpp::export]]
bool array_norm (arma::cube & x) {
auto out = x.each_slice([](arma::mat& x0) {return arma::norm(x0, "fro") ;}) ;
out.print("out");
return true;
}
/*** R
set.seed(2020)
x <- array(rnorm(3*4*5), 3:5)
array_norm2(x)
*/
Output
> Rcpp::sourceCpp("~/git/stackoverflow/65104769/answer.cpp")
> set.seed(2020)
> x <- array(rnorm(3*4*5), 3:5)
> array_norm2(x)
out
[cube slice 0]
0.3770 -1.1304 0.9391 0.1174
0.3015 -2.7965 -0.2294 -0.8531
-1.0980 0.7206 1.7591 0.9093
[cube slice 1]
1.1964 1.8000 -2.2890 1.0982
-0.3716 1.7040 0.0583 0.3182
-0.1233 -3.0388 2.1744 -0.0731
[cube slice 2]
0.8343 0.9367 -0.8125 2.4354
0.1988 -0.1474 -0.7437 0.3881
1.2978 0.1104 1.0953 0.2906
[cube slice 3]
-0.2856 0.4472 -0.3010 0.2531
0.0760 0.9085 -0.7260 -0.3707
-0.5603 -0.5051 -1.1801 0.0222
[cube slice 4]
0.6600 0.6014 0.1188 -1.3283
0.4888 -0.6738 0.1212 -0.5669
-0.1888 0.4761 -0.1860 0.5788
[1] TRUE

Compute density using Rcpp sugar function [duplicate]

From R, I'm trying to run sourceCpp on this file:
#include <RcppArmadillo.h>
// [[Rcpp::depends(RcppArmadillo)]]
using namespace arma;
using namespace Rcpp;
// [[Rcpp::export]]
vec dnormLog(vec x, vec means, vec sds) {
int n = x.size();
vec res(n);
for(int i = 0; i < n; i++) {
res[i] = log(dnorm(x[i], means[i], sds[i]));
}
return res;
}
See this answer to see where I got the function from. This throws the error:
no matching function for call to 'dnorm4'
Which is the exact error I was hoping to prevent by using the loop, since the referenced answer mentions that dnorm is only vectorized with respect to its first argument. I fear the answer is obvious, but I've tried adding R:: before the dnorm, tried using NumericVector instead of vec, without using log() in front. No luck. However, adding R:: before dnorm does produce a separate error:
too few arguments to function call, expected 4, have 3; did you mean '::dnorm4'?
Which is not fixed by replacing dnorm above with R::dnorm4.
There are two nice teachable moments here:
Pay attention to namespaces. If in doubt, don't go global.
Check the headers for the actual definitions. You missed the fourth argument in the scalar version R::dnorm().
Here is a repaired version, included is a second variant you may find interesting:
#include <RcppArmadillo.h>
// [[Rcpp::depends(RcppArmadillo)]]
// [[Rcpp::export]]
arma::vec dnormLog(arma::vec x, arma::vec means, arma::vec sds) {
int n = x.size();
arma::vec res(n);
for(int i = 0; i < n; i++) {
res[i] = std::log(R::dnorm(x[i], means[i], sds[i], FALSE));
}
return res;
}
// [[Rcpp::export]]
arma::vec dnormLog2(arma::vec x, arma::vec means, arma::vec sds) {
int n = x.size();
arma::vec res(n);
for(int i = 0; i < n; i++) {
res[i] = R::dnorm(x[i], means[i], sds[i], TRUE);
}
return res;
}
/*** R
dnormLog( c(0.1,0.2,0.3), rep(0.0, 3), rep(1.0, 3))
dnormLog2(c(0.1,0.2,0.3), rep(0.0, 3), rep(1.0, 3))
*/
When we source this, both return the same result because the R API allows us to ask for logarithms to be taken.
R> sourceCpp("/tmp/dnorm.cpp")
R> dnormLog( c(0.1,0.2,0.3), rep(0.0, 3), rep(1.0, 3))
[,1]
[1,] -0.923939
[2,] -0.938939
[3,] -0.963939
R> dnormLog2(c(0.1,0.2,0.3), rep(0.0, 3), rep(1.0, 3))
[,1]
[1,] -0.923939
[2,] -0.938939
[3,] -0.963939
R>

Indexing using input matrix RcppArmadillo

I have two vectors.. one is an output by group and the second is an index for the appartenance to one group. In practice, it is something like that
mean_group = 1, 2, 3
group_id = 1,1,3,2,3,2
And I would like to to assign each id to the value of its group.. In basic R, I will just do mean_group[group_id]..
I have to avoid using a loop, otherwise, there would be no point in using armadillo. Is there a way to do that?
Thanks in advance
I am not sure how hard you tried to find this in the Armadillo documentation, but this works out of the box in Armadillo. Try the following as file armaind.cpp:
#include <RcppArmadillo.h>
// [[Rcpp::depends(RcppArmadillo)]]
// [[Rcpp::export]]
arma::vec subsetter(arma::vec big, arma::uvec ind) {
arma::vec small = big.elem( ind );
return small;
}
/*** R
big <- 2*(1:10)
ind <- c(3,5,7)
subsetter(big, ind)
*/
which gets you
R> Rcpp::sourceCpp("/tmp/armaind.cpp")
R> big <- 2*(1:10)
R> ind <- c(3,5,7)
R> subsetter(big, ind)
[,1]
[1,] 8
[2,] 12
[3,] 16
R>
Note the off-by-one indexing difference between R and C++.

Resources