Search code examples
rloopsmatrixrcpp

Rcpp: Calculation in loop stops with error "Not a matrix"


in an R script I source a cpp file to make some calculations. In that R script, a function defined in the cpp file is called and a matrix and an integer is provided. After a few rounds through the loop it gives the error "Not a matrix" (in line of code resid = (x(_,j) - x(_,i))*(x(_,j) - x(_,i));), even though for the rounds before it worked. R script:

## all together
# rm(list=ls())
library(RcppArmadillo)
library(Rcpp)

sourceCpp("~/test.cpp",verbose = FALSE)

cat("start loop")
for(n in c(45:46)){
  cat("\n", n, "\n")
  p_m <- matrix(data=rnorm(n^2,1,1),nrow = n, ncol=n)
  print(class(p_m))
  print(some_function(p_m,nosamples=10))
}
cat("finished")

I start this R script via the command line. R version R-4.1.0. In R-Studio it crashes with a fatal error.

The cpp file:

// [[Rcpp::depends(RcppArmadillo)]]
#include <RcppArmadillo.h>
using namespace Rcpp;
// [[Rcpp::export]]
NumericVector some_function(NumericMatrix x,int nosamples) {
  int ncol = x.ncol();
  NumericVector out2(nosamples);
  int loops;
  int loops2;
  double result=0;
  NumericVector::iterator it;
  double acc = 0;
  NumericVector resid(ncol);
  NumericVector out(ncol*(ncol-1)/2);
  loops2=0;
  std::cout << nosamples << std::endl;
  std::cout << (ncol-1) << std::endl;
  std::cout << ncol*(ncol-1)/2 << std::endl;
  while(loops2 < (nosamples)){
    std::cout << "loops2:" << std::endl;
    std::cout << loops2 << std::endl;
    loops=0;
    int i;
    int j;
    for(j=0;j<(ncol-1);++j){
      std::cout << " j: " << j << std::endl;
      for (i = (j+1); i < (ncol); ++i) {
        std::cout << " i: " << i << std::endl;
          resid = (x(_,j) - x(_,i))*(x(_,j) - x(_,i)); //here it stops
          std::cout << " i: " << i << std::endl; 
          for(int ii=0; ii<ncol;++ii){
            acc += resid[i];
          }
         result=sqrt(acc);
          loops += 1;
          out[loops] = result;
          std::cout << " i: " << i << std::endl;
      }
    }
    std::cout << "loops:" << std::endl;
    std::cout << loops << std::endl;
    out = out[out > 0];
    it = std::min_element(out.begin(), out.end());
    out= *it;
    std::cout << out << std::endl;
    loops2 += 1;
    out2[loops2]=out[0];
  }
  std::cout << "cpp finished" << std::endl;
  return(out2);
}

Can someone explain what the problem is about?

Thanks and kind regards

Edit

I adapted some things in the cpp file (shown below) and the error disappeared. First I thought, everything is fine. But when I increase the number of loops, another problem occurs: the function breaks, but no error is shown. It breaks after loop number 543 ("loop2: 543"). At least it does the same in each round of the while loop with the same data.

I adapted the R-script and the ccp file to make this problem (at least on my machine) reproducible.

I know this code seems to be somehow meaningless, but it is part of a bigger program and I wanted to give here a minimum example.

The R script:

## all together
# rm(list=ls())
library(RcppArmadillo)
library(Rcpp)

sourceCpp("~/test.cpp",verbose = FALSE)

cat("start loop")
for(n in c(100:101)){
  cat("\n", n, "\n")
  p_m <- matrix(data=rnorm(n^2,1,1),nrow = n, ncol=n)
  print(class(p_m))
  print(some_function(p_m,nosamples=800))
}
cat("finished")

The cpp file:

// [[Rcpp::depends(RcppArmadillo)]]
// [[Rcpp::depends(RcppEigen)]]
#include <RcppArmadillo.h>
#include <RcppEigen.h>
using namespace Rcpp;
using  Eigen::Map;
using  Eigen::VectorXd;
typedef  Map<VectorXd>  MapVecd;


// [[Rcpp::export]]
NumericVector some_function(NumericMatrix x,int nosamples) {
  
  int ncol = x.ncol();
  NumericVector out(ncol*(ncol-1)/2);
  NumericVector out2(nosamples);
  NumericVector out3(ncol*(ncol-1)/2);
  NumericVector resid(ncol);
  int loops;
  int loops2;
  double result=0;
  double acc = 0;
  
  int show_cout=0;
  
  loops2=0;
  
  std::cout << nosamples << std::endl;
  std::cout << (ncol-1) << std::endl;
  std::cout << ncol*(ncol-1)/2 << std::endl;
  
  while(loops2 < (nosamples)){
    
    std::cout << "loops2:" << loops2 << std::endl;
    
    loops=0;
    int i;
    int j;
    
    for(j=0;j<(ncol-1);++j){
      // std::cout << " j: " << j << std::endl;
      for (i = (j+1); i < (ncol); ++i) {
        
        if(show_cout==1){
          std::cout << " i: " << i << std::endl;
        }
        
        resid = (x(_,j) - x(_,i))*(x(_,j) - x(_,i));
        
        if(show_cout==1){
          std::cout << " i: " << i << std::endl;
        }
        
        for(int ii=0; ii<ncol;++ii){
          acc += resid[ii];
          
        }
        
        result=sqrt(acc);
        
        loops += 1;
        
        out[loops] = result;
        
        if(show_cout==1){
          std::cout << " i: " << i << std::endl;
        }
      }
      
    }
    
    // std::cout << "loops:" << loops << std::endl;
    
    // 
    out = out[out > 0];
    
    const MapVecd xy(as<MapVecd>(out));
    
    out3=xy.minCoeff();
    
    out2[loops2]=out3[0];
    
    loops2 += 1;
  }
  std::cout << "cpp finished" << std::endl;
  return(out2);
  
}

Solution

  • Two things here:

    1. Use out[loops++] = result; instead of loops += 1; out[loops] = result; because you were starting at 1, and probably accessing the last element outside of the range of this vector.

    2. Use for(int ii=0; ii<ncol;++ii){ double eps = x(ii, j) - x(ii, i); acc += eps * eps; } instead of relying on this resid vector.