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).
Related
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
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;
I wrote the following simple example with Rcpp and OpenMP that works fine when I source the cpp file from RStudio:
#include <Rcpp.h>
#include <omp.h>
// [[Rcpp::plugins(openmp)]]
using namespace Rcpp;
// [[Rcpp::export]]
NumericMatrix my_matrix(int I, int J, int nthreads) {
NumericMatrix A(I,J);
int i,j,tid;
omp_set_num_threads(nthreads);
#pragma omp parallel for private(i, j, tid)
for(int i = 0; i < I; i++) {
for(int j = 0; j < J; j++) {
tid = omp_get_thread_num();
A(i,j) = tid ;
}
}
return A;
}
/*** R
set.seed(42)
my_matrix(10,10,5)
*/
[,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9] [,10]
[1,] 0 0 0 0 0 0 0 0 0 0
[2,] 0 0 0 0 0 0 0 0 0 0
[3,] 1 1 1 1 1 1 1 1 1 1
[4,] 1 1 1 1 1 1 1 1 1 1
[5,] 2 2 2 2 2 2 2 2 2 2
[6,] 2 2 2 2 2 2 2 2 2 2
[7,] 3 3 3 3 3 3 3 3 3 3
[8,] 3 3 3 3 3 3 3 3 3 3
[9,] 4 4 4 4 4 4 4 4 4 4
[10,] 4 4 4 4 4 4 4 4 4 4
However, the same code does not work as expected if I create a package:
> rcpphello::my_matrix(10,10,5)
[,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9] [,10]
[1,] 0 0 0 0 0 0 0 0 0 0
[2,] 0 0 0 0 0 0 0 0 0 0
[3,] 0 0 0 0 0 0 0 0 0 0
[4,] 0 0 0 0 0 0 0 0 0 0
[5,] 0 0 0 0 0 0 0 0 0 0
[6,] 0 0 0 0 0 0 0 0 0 0
[7,] 0 0 0 0 0 0 0 0 0 0
[8,] 0 0 0 0 0 0 0 0 0 0
[9,] 0 0 0 0 0 0 0 0 0 0
[10,] 0 0 0 0 0 0 0 0 0 0
Why is the same code only using one thread if I call it from within my package? In case it helps, I pushed all the code to this github repo
Add to src/Makevars and src/Makevars.win:
PKG_CXXFLAGS = $(SHLIB_OPENMP_CXXFLAGS)
PKG_LIBS = $(SHLIB_OPENMP_CXXFLAGS)
This enables the -fopenmp flag. Otherwise, you will not end up having OpenMP enabled in your package.
Note: When using:
// [[Rcpp::plugins(openmp)]]
This sets the -fopenmp parameter only when run with sourceCpp(). This option does not transfer into a package. Hence, we must establish the setting in Makevars and Makevars.win.
A short example can be found here:
https://github.com/r-pkg-examples/rcpp-and-openmp
Though, I'll need to clean it up a bit.
#coatless answered the question already. I would like to add one caveat: Don't use data structures from R or Rcpp within parallel code. You can use RcppParallel, though:
#include <Rcpp.h>
// [[Rcpp::plugins(openmp)]]
#include <omp.h>
// [[Rcpp::depends(RcppParallel)]]
#include <RcppParallel.h>
using namespace Rcpp;
// [[Rcpp::export]]
NumericMatrix my_matrix(int I, int J, int nthreads) {
NumericMatrix A(I,J);
// create a thread safe accessor for A
RcppParallel::RMatrix<double> a(A);
int tid;
omp_set_num_threads(nthreads);
#pragma omp parallel for private(tid)
for(int j = 0; j < J; j++) {
for(int i = 0; i < I; i++) {
tid = omp_get_thread_num();
a(i, j) = tid ;
}
}
return A;
}
/*** R
set.seed(42)
my_matrix(12,10,5)
*/
Note that I have also changed the access to column major and removed the additional declaration of i and j. Note that variables declared inside of a parallel section are automatically private.
And in case you want to use R's RNG (since you are setting the seed), there is another "don't do that". Have a look at packages like sitmo or dqrng for RNGs that can be used with parallel code.
I made a first stab at an Rcpp function via inline and it solved my speed problem (thanks Dirk!):
Replace negative values by zero
The initial version looked like this:
library(inline)
cpp_if_src <- '
Rcpp::NumericVector xa(a);
int n_xa = xa.size();
for(int i=0; i < n_xa; i++) {
if(xa[i]<0) xa[i] = 0;
}
return xa;
'
cpp_if <- cxxfunction(signature(a="numeric"), cpp_if_src, plugin="Rcpp")
But when called cpp_if(p), it overwrote p with the output, which was not as intended. So I assumed it was passing by reference.
So I fixed it with the following version:
library(inline)
cpp_if_src <- '
Rcpp::NumericVector xa(a);
int n_xa = xa.size();
Rcpp::NumericVector xr(a);
for(int i=0; i < n_xa; i++) {
if(xr[i]<0) xr[i] = 0;
}
return xr;
'
cpp_if <- cxxfunction(signature(a="numeric"), cpp_if_src, plugin="Rcpp")
Which seemed to work. But now the original version doesn't overwrite its input anymore when I re-load it into R (i.e. the same exact code now doesn't overwrite its input):
> cpp_if_src <- '
+ Rcpp::NumericVector xa(a);
+ int n_xa = xa.size();
+ for(int i=0; i < n_xa; i++) {
+ if(xa[i]<0) xa[i] = 0;
+ }
+ return xa;
+ '
> cpp_if <- cxxfunction(signature(a="numeric"), cpp_if_src, plugin="Rcpp")
>
> p
[1] -5 -4 -3 -2 -1 0 1 2 3 4 5
> cpp_if(p)
[1] 0 0 0 0 0 0 1 2 3 4 5
> p
[1] -5 -4 -3 -2 -1 0 1 2 3 4 5
I'm not the only one who has tried to replicate this behavior and found inconsistent results:
https://chat.stackoverflow.com/transcript/message/4357344#4357344
What's going on here?
They key is 'proxy model' -- your xa really is the same memory location as your original object so you end up changing your original.
If you don't want that, you should do one thing: (deep) copy using the clone() method, or maybe explicit creation of a new object into which the altered object gets written. Method two does not do that, you simply use two differently named variables which are both "pointers" (in the proxy model sense) to the original variable.
An additional complication, though, is in implicit cast and copy when you pass an int vector (from R) to a NumericVector type: that creates a copy, and then the original no longer gets altered.
Here is a more explicit example, similar to one I use in the tutorials or workshops:
library(inline)
f1 <- cxxfunction(signature(a="numeric"), plugin="Rcpp", body='
Rcpp::NumericVector xa(a);
int n = xa.size();
for(int i=0; i < n; i++) {
if(xa[i]<0) xa[i] = 0;
}
return xa;
')
f2 <- cxxfunction(signature(a="numeric"), plugin="Rcpp", body='
Rcpp::NumericVector xa(a);
int n = xa.size();
Rcpp::NumericVector xr(a); // still points to a
for(int i=0; i < n; i++) {
if(xr[i]<0) xr[i] = 0;
}
return xr;
')
p <- seq(-2,2)
print(class(p))
print(cbind(f1(p), p))
print(cbind(f2(p), p))
p <- as.numeric(seq(-2,2))
print(class(p))
print(cbind(f1(p), p))
print(cbind(f2(p), p))
and this is what I see:
edd#max:~/svn/rcpp/pkg$ r /tmp/ari.r
Loading required package: methods
[1] "integer"
p
[1,] 0 -2
[2,] 0 -1
[3,] 0 0
[4,] 1 1
[5,] 2 2
p
[1,] 0 -2
[2,] 0 -1
[3,] 0 0
[4,] 1 1
[5,] 2 2
[1] "numeric"
p
[1,] 0 0
[2,] 0 0
[3,] 0 0
[4,] 1 1
[5,] 2 2
p
[1,] 0 0
[2,] 0 0
[3,] 0 0
[4,] 1 1
[5,] 2 2
edd#max:~/svn/rcpp/pkg$
So it really matters whether you pass int-to-float or float-to-float.
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