Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

Tags:

c++

r

matrix

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?

like image 390
AntonyDW Avatar asked Dec 08 '15 16:12

AntonyDW


1 Answers

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
like image 108
Thell Avatar answered Oct 06 '22 08:10

Thell