Search code examples
rsumrcpp

problem with sum function after inplace editing using Rcpp


If modifying a value of an IntegerVector in Rcpp:

#include <Rcpp.h>
using namespace Rcpp;

// [[Rcpp::export]]
void test(IntegerVector x) {
  x[5] = 77;
}

After running test() function in R :

x <- 10:1
test(x)
print(x)  #  10  9  8  7  6 77  4  3  2  1
sum(x)  # 55

The sum function return the value of the original array 10:1. How can I solve this problem?

There is no problem when using e.g. x <- sample(10L) instead.


Solution

  • @F.Privé's suspicion is correct. This is an issue with ALTREP, which Rcpp does not support yet, c.f. Rcpp/#812 and Rcpp/#906. We can see this more explicitly by inspecting the variable x:

    #include <Rcpp.h>
    using namespace Rcpp;
    
    // [[Rcpp::export]]
    void test(IntegerVector x) {
      x[5] = 77;
    }
    
    /*** R
    x <- 10:1
    .Internal(inspect(x))
    test(x)
    .Internal(inspect(x))
    print(x)  #  10  9  8  7  6 77  4  3  2  1
    sum(x)  # 55
    
    x <- 10:1
    .Internal(inspect(x))
    x[6] <- 77L
    .Internal(inspect(x))
    print(x)  #  10  9  8  7  6 77  4  3  2  1
    sum(x)
    */
    

    The first block gives:

    > x <- 10:1
    
    > .Internal(inspect(x))
    @55f79a9d6c58 13 INTSXP g0c0 [NAM(3)]  10 : 1 (compact)
    
    > test(x)
    
    > .Internal(inspect(x))
    @55f79a9d6c58 13 INTSXP g0c0 [NAM(3)]  10 : 1 (expanded)
    
    > print(x)  #  10  9  8  7  6 77  4  3  2  1
     [1] 10  9  8  7  6 77  4  3  2  1
    
    > sum(x) # 55
    [1] 55
    

    While the second block gives:

    > x <- 10:1
    
    > .Internal(inspect(x))
    @55f79b1f9018 13 INTSXP g0c0 [NAM(3)]  10 : 1 (compact)
    
    > x[6] <- 77L
    
    > .Internal(inspect(x))
    @55f7a096e5e8 13 INTSXP g0c4 [NAM(1)] (len=10, tl=0) 10,9,8,7,6,...
    
    > print(x)  #  10  9  8  7  6 77  4  3  2  1
     [1] 10  9  8  7  6 77  4  3  2  1
    
    > sum(x)
    [1] 127
    

    So after changing a value in the vector, it still claims to be 10 : 1, for which sum uses a short-cut. See here for further reading (including references) on ALTREP.

    For now the only solution seems to be to refrain from altering the function argument.