作为 S4 对象的一部分返回时避免复制犰狳矩阵
Avoiding copying Armadillo matrix when returning as part of S4 object
我有一个 Rcpp 函数,它接受一个 S4 栅格对象,将一些数据插入到一个槽中,然后 returns 该对象的一个新版本。这是一个最小的代表:
#include <RcppArmadillo.h>
// [[Rcpp::depends(RcppArmadillo)]]
// [[Rcpp::export]]
Rcpp::S4 new_raster(Rcpp::S4 raster, int n_elem) {
Rcpp::S4 r_data(raster.slot("data"));
r_data.slot("values") = Rcpp::NumericVector(n_elem);
// Need help with...
// creating armadillo vector from `r_data.slot("values")` here
// arma::vec new_data = ... ?
return raster;
}
/*** R
library("raster")
r <- raster(res = 0.1)
n <- ncell(r)
r1 <- new_raster(r, n)
head(r1@data@values)
*/
由于返回的数据可能非常大,我想避免创建向量的多个副本。如何在不复制的情况下在 raster@data@values
插槽中创建 Armadillo 矢量?
编辑: 我没有正确理解问题。 objective 是 从 S4 对象中提取 信息并与 Armadillo 对象共享该内存。我保留了这个答案的第一部分,因为它仍然有优点,因为它强调了如何重用 Armadillo 对象内存并重新分配给 NumericVector
。不过,考虑到在 Noam 的回应之后问题现在变得清晰起来,第二部分可能更相关。
如果我对问题的理解正确,objective 是重用分配给初始犰狳向量的内存位置(例如零填充)。每个评论的子目标是稍后将其移至 NumericVector
。
那么,我们开始吧:
#include<RcppArmadillo.h>
// [[Rcpp::depends(RcppArmadillo)]]
// [[Rcpp::export]]
Rcpp::NumericVector vec_mem_ex(int n_elem) {
// Make the initial vector
arma::vec X(n_elem, arma::fill::zeros);
// Create a new vector
arma::vec Y(X.begin(), X.n_elem, false, true);
// `copy_aux_mem` is set to false, the vector will instead directly
// use the auxiliary memory (ie. no copying).
// This is dangerous in certain circumstances!
// `strict` is set to true, the vector will be bound to the
// auxiliary memory for its lifetime; the number of elements
// in the vector can't be changed
// Show memory is shared by modifying value
Y.fill(42.0);
// Convert X to a NumericVector
Rcpp::NumericVector Z = Rcpp::NumericVector(X.begin(), X.end());
return Z;
}
/***R
(a = vec_mem_ex(5))
*/
这给出:
> (a = vec_mem_ex(5))
[1] 42 42 42 42 42
编辑
要捕捉问题的 S4
性并通过@noam-ross 的回答给出更新,请考虑以下几点:
#include <RcppArmadillo.h>
// [[Rcpp::depends(RcppArmadillo)]]
// [[Rcpp::export]]
Rcpp::S4 new_raster(Rcpp::S4 raster, int n_elem) {
// Embed S4 object for nesting
Rcpp::S4 r_data(raster.slot("data"));
// Create obj@data@values
// Initializes values with a vector of 0's.
r_data.slot("values") = Rcpp::NumericVector(n_elem);
// --- The new part...
// We do _not_ have access to the vector that was stored in r_data.slot("values")
// Convert from SEXP to NumericVector
Rcpp::NumericVector temp = Rcpp::NumericVector(r_data.slot("values"));
// Use the advanced vector ctor of Armadillo to capture the memory location
arma::vec new_data(
temp.begin(), // Uses the iterator interface to access the double* requirement
n_elem, // Set the size of the vector
false, // Avoid copying by disabling `copy_aux_mem`
true // Bind memory by enabling `strict`
);
// Show memory is shared by modifying value
new_data.fill(42.0);
// --- End new
return raster;
}
/*** R
library("raster")
r <- raster(res = 0.1)
n <- ncell(r)
r1 <- new_raster(r, n)
head(r1@data@values)
*/
我通过为插槽分配一个空但大小合适的 NumericVector 来解决这个问题,然后在其上调用 as()
以找到内存指针以使用高级 Armadillo 构造函数,正如@DirkEddelbuettel 和@coatless 所建议的那样。
#include <RcppArmadillo.h>
// [[Rcpp::depends(RcppArmadillo)]]
// [[Rcpp::export]]
Rcpp::S4 new_raster(Rcpp::S4 raster, int n_elem) {
Rcpp::S4 r_data(raster.slot("data"));
r_data.slot("values") = Rcpp::NumericVector(n_elem);
arma::vec new_data(
Rcpp::as<Rcpp::NumericVector>(r_data.slot("values")).begin(),
n_elem, false, true
);
new_data.randn();
return raster;
}
/*** R
library("raster")
r <- raster(res = 0.1)
n <- ncell(r)
r1 <- new_raster(r, n)
head(r1@data@values)
*/
结果:
#>[1] -0.26417159 -0.89250080 2.02276338 2.01164847 0.45227281 -0.09313601
我有一个 Rcpp 函数,它接受一个 S4 栅格对象,将一些数据插入到一个槽中,然后 returns 该对象的一个新版本。这是一个最小的代表:
#include <RcppArmadillo.h>
// [[Rcpp::depends(RcppArmadillo)]]
// [[Rcpp::export]]
Rcpp::S4 new_raster(Rcpp::S4 raster, int n_elem) {
Rcpp::S4 r_data(raster.slot("data"));
r_data.slot("values") = Rcpp::NumericVector(n_elem);
// Need help with...
// creating armadillo vector from `r_data.slot("values")` here
// arma::vec new_data = ... ?
return raster;
}
/*** R
library("raster")
r <- raster(res = 0.1)
n <- ncell(r)
r1 <- new_raster(r, n)
head(r1@data@values)
*/
由于返回的数据可能非常大,我想避免创建向量的多个副本。如何在不复制的情况下在 raster@data@values
插槽中创建 Armadillo 矢量?
编辑: 我没有正确理解问题。 objective 是 从 S4 对象中提取 信息并与 Armadillo 对象共享该内存。我保留了这个答案的第一部分,因为它仍然有优点,因为它强调了如何重用 Armadillo 对象内存并重新分配给 NumericVector
。不过,考虑到在 Noam 的回应之后问题现在变得清晰起来,第二部分可能更相关。
如果我对问题的理解正确,objective 是重用分配给初始犰狳向量的内存位置(例如零填充)。每个评论的子目标是稍后将其移至 NumericVector
。
那么,我们开始吧:
#include<RcppArmadillo.h>
// [[Rcpp::depends(RcppArmadillo)]]
// [[Rcpp::export]]
Rcpp::NumericVector vec_mem_ex(int n_elem) {
// Make the initial vector
arma::vec X(n_elem, arma::fill::zeros);
// Create a new vector
arma::vec Y(X.begin(), X.n_elem, false, true);
// `copy_aux_mem` is set to false, the vector will instead directly
// use the auxiliary memory (ie. no copying).
// This is dangerous in certain circumstances!
// `strict` is set to true, the vector will be bound to the
// auxiliary memory for its lifetime; the number of elements
// in the vector can't be changed
// Show memory is shared by modifying value
Y.fill(42.0);
// Convert X to a NumericVector
Rcpp::NumericVector Z = Rcpp::NumericVector(X.begin(), X.end());
return Z;
}
/***R
(a = vec_mem_ex(5))
*/
这给出:
> (a = vec_mem_ex(5))
[1] 42 42 42 42 42
编辑
要捕捉问题的 S4
性并通过@noam-ross 的回答给出更新,请考虑以下几点:
#include <RcppArmadillo.h>
// [[Rcpp::depends(RcppArmadillo)]]
// [[Rcpp::export]]
Rcpp::S4 new_raster(Rcpp::S4 raster, int n_elem) {
// Embed S4 object for nesting
Rcpp::S4 r_data(raster.slot("data"));
// Create obj@data@values
// Initializes values with a vector of 0's.
r_data.slot("values") = Rcpp::NumericVector(n_elem);
// --- The new part...
// We do _not_ have access to the vector that was stored in r_data.slot("values")
// Convert from SEXP to NumericVector
Rcpp::NumericVector temp = Rcpp::NumericVector(r_data.slot("values"));
// Use the advanced vector ctor of Armadillo to capture the memory location
arma::vec new_data(
temp.begin(), // Uses the iterator interface to access the double* requirement
n_elem, // Set the size of the vector
false, // Avoid copying by disabling `copy_aux_mem`
true // Bind memory by enabling `strict`
);
// Show memory is shared by modifying value
new_data.fill(42.0);
// --- End new
return raster;
}
/*** R
library("raster")
r <- raster(res = 0.1)
n <- ncell(r)
r1 <- new_raster(r, n)
head(r1@data@values)
*/
我通过为插槽分配一个空但大小合适的 NumericVector 来解决这个问题,然后在其上调用 as()
以找到内存指针以使用高级 Armadillo 构造函数,正如@DirkEddelbuettel 和@coatless 所建议的那样。
#include <RcppArmadillo.h>
// [[Rcpp::depends(RcppArmadillo)]]
// [[Rcpp::export]]
Rcpp::S4 new_raster(Rcpp::S4 raster, int n_elem) {
Rcpp::S4 r_data(raster.slot("data"));
r_data.slot("values") = Rcpp::NumericVector(n_elem);
arma::vec new_data(
Rcpp::as<Rcpp::NumericVector>(r_data.slot("values")).begin(),
n_elem, false, true
);
new_data.randn();
return raster;
}
/*** R
library("raster")
r <- raster(res = 0.1)
n <- ncell(r)
r1 <- new_raster(r, n)
head(r1@data@values)
*/
结果:
#>[1] -0.26417159 -0.89250080 2.02276338 2.01164847 0.45227281 -0.09313601