Проще говоря: не используйте ссылку (&
) рядом с параметром X
в определении функции. Это активирует использование RcppArmadillo расширенного конструктора для arma::mat
, который повторно использует объектную память R (c.f. include/RcppArmadilloWrap.h
)
Итак, чтобы решить эту проблему, перейдите по ссылке:
List centering_reuse_memory(arma::mat & X) {
# ^ reference/reuse
# Routine given in OP
}
Кому:
List centering_new_memory(arma::mat X) {
# ^ Direct copy
# Routine given in OP
}
Понимание обмена ...
Давайте посмотрим, как меняется объект.
# Create the original object
set.seed(42)
X <- replicate(3, rnorm(5, 5, 3))
# Create a duplicate object not sharing memory with X
set.seed(42)
X_clone <- replicate(3, rnorm(5, 5, 3))
# View object
X
# [,1] [,2] [,3]
# [1,] 9.112875 4.681626 8.9146090
# [2,] 3.305905 9.534566 11.8599362
# [3,] 6.089385 4.716023 0.8334179
# [4,] 6.898588 11.055271 4.1636337
# [5,] 6.212805 4.811858 4.6000360
# Check equality
all.equal(X, X_clone)
# [1] TRUE
Теперь запустим функцию с параметром arma::mat & X
.
res <- centering_reuse_memory(X)
# Verify results are the same.
all.equal(X, X_clone)
# [1] "Mean relative difference: 8.387859"
# Check X manually to see what changed...
X
# [,1] [,2] [,3]
# [1,] 1.34167459 -0.7368308 0.6566715
# [2,] -1.45185917 0.8327104 1.3376293
# [3,] -0.11282266 -0.7257062 -1.2116948
# [4,] 0.27645691 1.3245379 -0.4417510
# [5,] -0.05344967 -0.6947113 -0.3408550
Почему есть разница? Итак, используя ссылки, изменения в функции C ++ распространяются обратно на переменную X
, находящуюся в R , которая соответствует объекту, хранящемуся в res$X
.
# Verify R's X matches the saved C++ routine X modification
all.equal(X, res$X)
# [1] TRUE