Search code examples
rlistloopsrcpp

Dynamically updated list in Rcpp stores only last value


I have a NumericMatrix whose values are updated every iteration of a loop. I want to store the matrix in a List every iteration. The code below gives a minimal reproducible example. However, when I compile and run this in R, every element of the list is identical to the final matrix, rather than storing each matrix. Why would this be the case, and how can I fix it? This seems like a very simple problem, but I haven't been able to find a solution.

Example code:

#include <Rcpp.h>
using namespace Rcpp;

// [[Rcpp::export]]
List updatingList(int n) {
  // Create a NumericMatrix that will be updated every step
  NumericMatrix mat(n, 2);
  for (int i=0; i < n; i++) { // set the initial state of the susceptible hosts
    mat(i,0) = 0; // initial Th1 
    mat(i,1) = 1; // initial Th2
  }
  // create a List that will store mat every step
  List list(n);
  
  for (int j=0; j < n; j++) {
    // store the value of mat
    list(j) = mat;
    // update mat
    for (int i=0; i < n; i++) { 
      mat(i,0) += 1; 
      mat(i,1) += 1; 
    }
  }
  return(list);  
}

/*** R
updatingList(3)
*/

Example output:

> updatingList(3)
[[1]]
     [,1] [,2]
[1,]    3    4
[2,]    3    4
[3,]    3    4

[[2]]
     [,1] [,2]
[1,]    3    4
[2,]    3    4
[3,]    3    4

[[3]]
     [,1] [,2]
[1,]    3    4
[2,]    3    4
[3,]    3    4

Solution

  • After a few years with R you become familiar with the 'copy-on-write' idiom. What you have here is, really, just one instance of the matrix so what you back is consequently always the same. As it is the same matrix. And that is, come to think (a bit) about it, a feature.

    What you want here is so 'seal' the matrix value away. So all we need to change is one line:

        // store a deep copy of mat
        list(j) = clone(mat);
    

    By requesting deep copies at each loop run you actually get distinct instances as you desire.

    Output

    > Rcpp::sourceCpp("answer.cpp")
    
    > updatingList(3)
    [[1]]
         [,1] [,2]
    [1,]    0    1
    [2,]    0    1
    [3,]    0    1
    
    [[2]]
         [,1] [,2]
    [1,]    1    2
    [2,]    1    2
    [3,]    1    2
    
    [[3]]
         [,1] [,2]
    [1,]    2    3
    [2,]    2    3
    [3,]    2    3
    
    >