Submatrix summation doesn't work for NumericMatrix Rcpp - c++

I observed the following weird situation when defining an Rcpp function.
The first function works perfectly, and calculates the sum of submatrix s
#include <RcppArmadillo.h>
// [[Rcpp::depends(RcppArmadillo)]]
// [[Rcpp::export]]
double Sub(NumericMatrix m){
NumericMatrix s = m(Range(0,0),Range(0,1));
return sum(s);
}
However, when I alternate the code in the following way
#include <RcppArmadillo.h>
// [[Rcpp::depends(RcppArmadillo)]]
// [[Rcpp::export]]
double Sub(NumericMatrix m){
return sum(m(Range(0,0),Range(0,1)));
}
It doesn't work which is really counterintuitive. The error that I get is the following no matching function for call to 'sum(Rcpp::Matrix<14>::Sub)'
I just skip a step, where I define the submatrix NumericMatrix s.
A matrix that can be used to check that is the following
n = matrix(c(6090,16,0,0,618,1036,3,0,99,0,312,4,25,0,0,3,0,0,0,0,1794,0,0,0,0),5,5,byrow=TRUE)
n
[,1] [,2] [,3] [,4] [,5]
[1,] 6090 16 0 0 618
[2,] 1036 3 0 99 0
[3,] 312 4 25 0 0
[4,] 3 0 0 0 0
[5,] 1794 0 0 0 0

Related

When algorithm is placed inside loop it produces different results, C++

I create the following algorithm in Rcpp and compile it in R.
// [[Rcpp::depends(RcppArmadillo)]]
#include <RcppArmadilloExtensions/sample.h>
// [[Rcpp::export]]
arma::colvec Demo(arma::mat n, int K){
arma::colvec N(K);
for(int j=0; j<K; ++j){
for(int i=0; i<(K-j); ++i){
N[j] += accu(n.submat(i,0,i,j));
}
}
return N;
}
/***R
K = 4
n = cbind(c(1008, 5112, 1026, 25, 0), 0, 0, 0, 0)
Demo(n,K)
for(i in 1:3){
print(Demo(n,K))
print(K)
print(n)
}
*/
However, something really weird happens when I run it inside a loop.
For example, if I have
> K = 4
> n
[,1] [,2] [,3] [,4] [,5]
[1,] 1008 0 0 0 0
[2,] 5112 0 0 0 0
[3,] 1026 0 0 0 0
[4,] 25 0 0 0 0
[5,] 0 0 0 0 0
Then if I run the algorithm Demo a single time I receive the correct result
> Demo(n,K)
[,1]
[1,] 7171
[2,] 7146
[3,] 6120
[4,] 1008
However, if I run it multiple times inside a loop, it starts to behave weird
for(i in 1:3){
print(Demo(n,K))
print(K)
print(n)
}
[,1]
[1,] 7171
[2,] 7146
[3,] 6120
[4,] 1008
[1] 4
[,1] [,2] [,3] [,4] [,5]
[1,] 1008 0 0 0 0
[2,] 5112 0 0 0 0
[3,] 1026 0 0 0 0
[4,] 25 0 0 0 0
[5,] 0 0 0 0 0
[,1]
[1,] 14342
[2,] 14292
[3,] 12240
[4,] 2016
[1] 4
[,1] [,2] [,3] [,4] [,5]
[1,] 1008 0 0 0 0
[2,] 5112 0 0 0 0
[3,] 1026 0 0 0 0
[4,] 25 0 0 0 0
[5,] 0 0 0 0 0
[,1]
[1,] 21513
[2,] 21438
[3,] 18360
[4,] 3024
[1] 4
[,1] [,2] [,3] [,4] [,5]
[1,] 1008 0 0 0 0
[2,] 5112 0 0 0 0
[3,] 1026 0 0 0 0
[4,] 25 0 0 0 0
[5,] 0 0 0 0 0
In the first run, it computes it correctly, then in the second run it gives the correct output multiplied by 2, and in the third run, it gives the correct output multiplied by 3. But based on the algorithm steps, I do not see an obvious step that produces this kind of behavior.
The correct output should have been
for(i in 1:3){
print(Demo(n,K))
}
[,1]
[1,] 7171
[2,] 7146
[3,] 6120
[4,] 1008
[,1]
[1,] 7171
[2,] 7146
[3,] 6120
[4,] 1008
[,1]
[1,] 7171
[2,] 7146
[3,] 6120
[4,] 1008
You are incrementing N in place via +=.
Your function fails to ensure it is initialized at zero. Rcpp tends to do that by default (as I think it is prudent) -- but this can be suppressed for speed if you know you are doing.
A minimally repaired version of your code (with the correct header, and a call to .fill(0)) follows.
// [[Rcpp::depends(RcppArmadillo)]]
#include <RcppArmadillo.h>
// [[Rcpp::export]]
arma::colvec Demo(arma::mat n, int K){
arma::colvec N(K);
N.fill(0); // important, or construct as N(k, arma::fill::zeros)
for(int j=0; j<K; ++j){
for(int i=0; i<(K-j); ++i){
N[j] += accu(n.submat(i,0,i,j));
}
}
return N;
}
/***R
K = 4
n = cbind(c(1008, 5112, 1026, 25, 0), 0, 0, 0, 0)
Demo(n,K)
for(i in 1:3) {
print(Demo(n,K))
print(K)
print(n)
}
*/
You could also call .zeros() (once constructed) or use zeros(k) (to construct) or ... deploy a number of different ways to ensure your content is cleared before adding to it.
The shortest, after checking the documentation, may be arma::colvec(N, arma::fill::zeros).

Rcpp select/subset NumericMatrix column by a NumericVector

I can select all the rows of a matrix and a range of columns of a matrix as follows:
library(Rcpp)
cppFunction('
NumericMatrix subset(NumericMatrix x){
return x(_, Range(0, 1));
}
')
However, I would like to select columns based on a NumericVector y which, for instance, could be something like c(0, 1, 0, 0, 1). I tried this:
library(Rcpp)
cppFunction('
NumericMatrix subset(NumericMatrix x, NumericVector y){
return x(_, y);
}
')
but it doesn't compile. How do I do it?
Alas, Rcpp doesn't have great support for non-contiguous views or selecting in a single statement only columns 1 and 4. As you saw, selecting contiguous views or selecting all columns is accessible with Rcpp::Range(). You'll likely want to upgrade to RcppArmadillo for better control over matrix subsets.
RcppArmadillo subset examples
#include <RcppArmadillo.h>
// [[Rcpp::depends(RcppArmadillo)]]
// [[Rcpp::export]]
arma::mat matrix_subset_idx(const arma::mat& x,
const arma::uvec& y) {
// y must be an integer between 0 and columns - 1
// Allows for repeated draws from same columns.
return x.cols( y );
}
// [[Rcpp::export]]
arma::mat matrix_subset_logical(const arma::mat& x,
const arma::vec& y) {
// Assumes that y is 0/1 coded.
// find() retrieves the integer index when y is equivalent 1.
return x.cols( arma::find(y == 1) );
}
Test
# Sample data
x = matrix(1:15, ncol = 5)
x
# [,1] [,2] [,3] [,4] [,5]
# [1,] 1 4 7 10 13
# [2,] 2 5 8 11 14
# [3,] 3 6 9 12 15
# Subset only when 1 (TRUE) is found:
matrix_subset_logical(x, c(0, 1, 0, 0, 1))
# [,1] [,2]
# [1,] 4 13
# [2,] 5 14
# [3,] 6 15
# Subset with an index representing the location
# Note: C++ indices start at 0 not 1!
matrix_subset_idx(x, c(1, 3))
# [,1] [,2]
# [1,] 4 13
# [2,] 5 14
# [3,] 6 15
Pure Rcpp logic
If you do not want to take on the dependency of armadillo, then the equivalent for the matrix subset in Rcpp is:
#include <Rcpp.h>
// [[Rcpp::export]]
Rcpp::NumericMatrix matrix_subset_idx_rcpp(
Rcpp::NumericMatrix x, Rcpp::IntegerVector y) {
// Determine the number of observations
int n_cols_out = y.size();
// Create an output matrix
Rcpp::NumericMatrix out = Rcpp::no_init(x.nrow(), n_cols_out);
// Loop through each column and copy the data.
for(unsigned int z = 0; z < n_cols_out; ++z) {
out(Rcpp::_, z) = x(Rcpp::_, y[z]);
}
return out;
}

Eigen giving different results for inplace versus non-inplace versions of function

I am having a weird problem where two functions that should give identical results are disagreeing. I have included the code below. I know that the results of test1 are correct while test2 are wrong.
#include <RcppEigen.h>
using namespace Rcpp;
// [[Rcpp::depends(RcppEigen)]]
// [[Rcpp::export]]
Eigen::MatrixXd test1(Eigen::MatrixXd A){
int p = A.rows();
return A.triangularView<Eigen::Lower>().solve(Eigen::MatrixXd::Identity(p,p)).transpose();
}
// [[Rcpp::export]]
Eigen::MatrixXd test2(Eigen::MatrixXd A){
int p = A.rows();
Eigen::MatrixXd I = Eigen::MatrixXd::Identity(p,p);
A.triangularView<Eigen::Lower>().solveInPlace(I);
A.transposeInPlace();
return A;
}
/*** R
A <- rWishart(1, 10, diag(4))[,,1]
A <- t(chol(A))
test1(A)
test2(A)
*/
Here is the output
> test1(A)
[,1] [,2] [,3] [,4]
[1,] 0.2251857 -0.01455544 -0.20205410 -0.08993337
[2,] 0.0000000 0.32498583 -0.06486972 -0.14006616
[3,] 0.0000000 0.00000000 0.60379357 0.27294390
[4,] 0.0000000 0.00000000 0.00000000 0.37409978
> test2(A)
[,1] [,2] [,3] [,4]
[1,] 4.440779 0.1988932 1.5074352 0.04220045
[2,] 0.000000 3.0770572 0.3305895 0.91087781
[3,] 0.000000 0.0000000 1.6561952 -1.20836313
[4,] 0.000000 0.0000000 0.0000000 2.67308367
My question is how do I write an inplace version of test1 that is not incorrect? Also why is test2 incorrect?
The line:
A.triangularView<Eigen::Lower>().solveInPlace(I);
modifies I not A. So you need to ends test2 with:
I.transposeInPlace();
return I;

Column-wise ordering of matrix

I am new to RcppArmadillo. I am wondering how I can make a column-wise ordered matrix by the index of given vector. I know how to do it in R, but in RcppArmadillo it does not working. For example, in R,
aa = c(2,4,1,3)
# [1] 2 4 1 3
bb = cbind(c(1,5,4,2),c(3,1,0,8))
# [,1] [,2]
# [1,] 1 3
# [2,] 5 1
# [3,] 4 0
# [4,] 2 8
Trying to subset with R gives:
cc = bb[aa,]
# [,1] [,2]
# [1,] 5 1
# [2,] 2 8
# [3,] 1 3
# [4,] 4 0
I've tried the following using RcppArmadillo:
#include <RcppArmadillo.h>
using namespace Rcpp;
// [[Rcpp::depends(RcppArmadillo)]]
// [[Rcpp::export]]
List example(arma::vec aa,arma::mat bb){
int p = bb.n_rows;
int n = aa.size();
arma::uvec index_aa=sort_index(aa);;
List cc(n);
for(int it=0; it<p; it++){
cc(it) = bb.each_col();
}
return List::create(cc);
}
and,
#include <RcppArmadillo.h>
using namespace Rcpp;
// [[Rcpp::depends(RcppArmadillo)]]
// [[Rcpp::export]]
List example(arma::vec aa,arma::mat bb){
arma::uvec index_aa=sort_index(aa);
return List::create(bb.elem(index_aa));
}
Not sure why you are sorting the index here as that causes a new order to be introduced compared to bb[aa,].
Anyway, the idea here is to subset using the .rows() index, which requires a uvec or unsigned integer vector. As aa contains R indexes, we can translate them from R to C++ by subtracting 1 to take it from a 1-based index system to a 0-based index system.
#include <RcppArmadillo.h>
// [[Rcpp::depends(RcppArmadillo)]]
// [[Rcpp::export]]
arma::mat example_subset(arma::uvec aa, arma::mat bb){
// Convert to a C++ index from R (1 to 0-based indices)
aa = aa - 1;
return bb.rows(aa);
}
Test code:
aa = c(2, 4, 1, 3)
bb = cbind(c(1, 5, 4, 2), c(3, 1, 0, 8))
cpp_cc = example_subset(aa, bb)
r_cc = cbind(c(5,2,1,4),c(1,8,3,0))
all.equal(cpp_cc, r_cc)
# [1] TRUE

How to replace elements of a matrix in C++ with values from another matrix (using Rcpp)?

I have a small C++ function using Rcpp that replaces elements of one matrix with values from another matrix. It works fine for single cells, or a column as below:
cppFunction('NumericMatrix changeC(NumericMatrix one, NumericMatrix two) {
NumericMatrix a = one;
NumericMatrix b = two;
b(_,1) = a(_,1);
return b;
}')
changeC(g,f)
If originally f is the following matrix:
[,1] [,2] [,3] [,4] [,5] [,6]
[1,] 6 6 6 6 6 6
[2,] 6 6 6 6 6 6
[3,] 6 6 6 6 6 6
[4,] 6 6 6 6 6 6
[5,] 6 6 6 6 6 6
[6,] 6 6 6 6 6 6
and g looks like the following matrix:
[,1] [,2] [,3] [,4] [,5] [,6]
[1,] 5 5 5 5 5 5
[2,] 5 5 5 5 5 5
[3,] 5 5 5 5 5 5
[4,] 5 5 5 5 5 5
[5,] 5 5 5 5 5 5
[6,] 5 5 5 5 5 5
When I run changeC(g,f) I end up with (as expected):
[,1] [,2] [,3] [,4] [,5] [,6]
[1,] 6 5 6 6 6 6
[2,] 6 5 6 6 6 6
[3,] 6 5 6 6 6 6
[4,] 6 5 6 6 6 6
[5,] 6 5 6 6 6 6
[6,] 6 5 6 6 6 6
But what I really want to do is replace a subset of one matrix with a subset of another matrix from a different place (eg rows 1 to 3, columns 1 to 3 of one matrix (3*3) to rows 3 to 6, columns 3 to 6 (also 3*3) of the other matrix). I have tried:
cppFunction('NumericMatrix changeC(NumericMatrix one, NumericMatrix two) {
NumericMatrix a = one;
NumericMatrix b = two;
b( Range(0,2), Range(0,2)) = a( Range(3,5), Range(3,5));
return b;
}')
but this doesn't compile. Although:
cppFunction('NumericMatrix changeC(NumericMatrix one, NumericMatrix two) {
NumericMatrix a = one;
NumericMatrix b = two;
b = a( Range(3,5), Range(3,5));
return b;
}')
does compile. What am I doing wrong? In R I would do the following:
f[1:3,1:3] <- g[4:6,4:6] (but this is relatively slow with a very large matrix (hence Rcpp).
Thanks for any help in advance.
EDIT 1
After a bit of playing around I've managed to get my matrix to step east and west (and I assume it would be similar to north and south - possibly a two step approach for North East, North West??):
func <- 'NumericMatrix eastC(NumericMatrix a) {
int acoln=a.ncol();
NumericMatrix out(a.nrow(),a.ncol()) ;
for (int j = 0;j < acoln;j++) {
if (j > 0) {
out(_,j) = a(_,j-1);
} else {
out(_,j) = a(_,0);
}
}
return out ;
}'
cppFunction(func)
Any refinements would be welcome. I would ideally like to leave the first column as zeros rather than column 0. Any ideas?
I don't think the Rcpp subMatrix allows for assignments that way.
Take a look at using RcppArmadillo and Armadillo submatrix views
#include <RcppArmadillo.h>
// [[Rcpp::depends(RcppArmadillo)]]
using namespace arma;
// [[Rcpp::export]]
mat example( mat m1, mat m2) {
m1.submat( 0,0, 2,2) = m2.submat( 3,3, 5,5 );
return m1;
}
/*** R
m1 <- matrix(1,6,6)
m2 <- matrix(-1,6,6)
example(m1, m2)
*/
> m1 <- matrix(1,6,6)
> m2 <- matrix(-1,6,6)
> example(m1, m2)
[,1] [,2] [,3] [,4] [,5] [,6]
[1,] -1 -1 -1 1 1 1
[2,] -1 -1 -1 1 1 1
[3,] -1 -1 -1 1 1 1
[4,] 1 1 1 1 1 1
[5,] 1 1 1 1 1 1
[6,] 1 1 1 1 1 1