问题描述
我正在尝试将RcppArmadillo矢量(例如arma::colvec
)转换为Rcpp矢量(NumericVector
).我知道我可以先将arma::colvec
转换为SEXP
,然后再将SEXP
转换为NumericVector
(例如as<NumericVector>(wrap(temp)
),假设temp是arma::colvec
对象).但是,这样做的一个好方法是什么?
I am trying to convert RcppArmadillo vector (e.g. arma::colvec
) to a Rcpp vector (NumericVector
). I know I can first convert arma::colvec
to SEXP
and then convert SEXP
to NumericVector
(e.g. as<NumericVector>(wrap(temp)
), assuming temp is an arma::colvec
object). But what is a good way to do that?
我想这样做只是因为我不确定是否可以将arma::colvec
对象作为参数传递给Rcpp::Function
对象.
I want to do that simply because I am unsure if it is okay to pass arma::colvec
object as a parameter to an Rcpp::Function
object.
推荐答案
我试图用参数arma::vec
评估Rcpp::Function
,看来它采用四种形式的参数而没有编译错误.也就是说,如果f
是Rcpp::Function
而a
是arma::vec
,则
I was trying to Evaluate a Rcpp::Function
with argument arma::vec
, it seems that it takes the argument in four forms without compilation errors. That is, if f
is a Rcpp::Function
and a
is a arma::vec
, then
-
f(a)
-
f(wrap(a))
-
f(as<NumericVector>(wrap(a)))
-
f(NumericVector(a.begin(),a.end()))
f(a)
f(wrap(a))
f(as<NumericVector>(wrap(a)))
f(NumericVector(a.begin(),a.end()))
至少显然不会产生编译和运行时错误.
produce no compilation and runtime errors, at least apparently.
基于这个原因,我对四个版本的参数进行了一些测试.由于我怀疑垃圾回收中会出问题,因此我再次进行测试gctorture
.
For this reason, I have conducted a little test for the four versions of arguments. Since I suspect that somethings will go wrong in garbage collection, I test them again gctorture
.
gctorture(on=FALSE)
Rcpp::sourceCpp(code = '
#include <RcppArmadillo.h>
// [[Rcpp::depends(RcppArmadillo)]]
using namespace Rcpp;
// [[Rcpp::export]]
double foo1(arma::vec a, arma::vec b, Function f){
double sum = 0.0;
for(int i=0;i<100;i++){
sum += as<double>(f(a, b));
}
return sum;
}
// [[Rcpp::export]]
double foo2(arma::vec a, arma::vec b, Function f){
double sum = 0.0;
for(int i=0;i<100;i++){
sum += as<double>(f(wrap(a),wrap(b)));
}
return sum;
}
// [[Rcpp::export]]
double foo3(arma::vec a, arma::vec b, Function f){
double sum = 0.0;
for(int i=0;i<100;i++){
sum += as<double>(f(as<NumericVector>(wrap(a)),as<NumericVector>(wrap(b))));
}
return sum;
}
// [[Rcpp::export]]
double foo4(arma::vec a, arma::vec b, Function f){
double sum = 0.0;
for(int i=0;i<100;i++){
sum += as<double>(f(NumericVector(a.begin(),a.end()),NumericVector(b.begin(),b.end())));
}
return sum;
}
')
# note that when gctorture is on, the program will be very slow as it
# tries to perfrom GC for every allocation.
# gctorture(on=TRUE)
f = function(x,y) {
mean(x) + mean(y)
}
# all three functions should return 700
foo1(c(1,2,3), c(4,5,6), f) # error
foo2(c(1,2,3), c(4,5,6), f) # wrong answer (occasionally)!
foo3(c(1,2,3), c(4,5,6), f) # correct answer
foo4(c(1,2,3), c(4,5,6), f) # correct answer
结果是,第一种方法产生错误,第二种方法产生错误的答案,只有第三种和第四种方法返回正确的答案.
As a result, the first method produces an error, the second method produces a wrong answer and only the third and the fourth method return the correct answer.
> # they should return 700
> foo1(c(1,2,3), c(4,5,6), f) # error
Error: invalid multibyte string at '<80><a1><e2>'
> foo2(c(1,2,3), c(4,5,6), f) # wrong answer (occasionally)!
[1] 712
> foo3(c(1,2,3), c(4,5,6), f) # correct answer
[1] 700
> foo4(c(1,2,3), c(4,5,6), f) # correct answer
[1] 700
请注意,如果将gctorture
设置为FALSE
,则所有功能都将返回正确的结果.
Note that, if gctorture
is set FALSE
, then all functions will return a correct result.
> foo1(c(1,2,3), c(4,5,6), f) # error
[1] 700
> foo2(c(1,2,3), c(4,5,6), f) # wrong answer (occasionally)!
[1] 700
> foo3(c(1,2,3), c(4,5,6), f) # correct answer
[1] 700
> foo4(c(1,2,3), c(4,5,6), f) # correct answer
[1] 700
这意味着在运行时收集垃圾时方法1和方法2会中断,我们不知道它何时发生.因此,危险不能正确地包装参数.
It means that method 1 and method 2 are subjected to break when garbage is collected during runtime and we don't know when it happens. Thus, it is dangerous to not wrap the parameter properly.
修改:自2017年12月5日起,所有四次转换都能产生正确的结果.
Edit: as of 2017-12-05, all four conversions produce the correct result.
-
f(a)
-
f(wrap(a))
-
f(as<NumericVector>(wrap(a)))
-
f(NumericVector(a.begin(),a.end()))
f(a)
f(wrap(a))
f(as<NumericVector>(wrap(a)))
f(NumericVector(a.begin(),a.end()))
这是基准
> microbenchmark(foo1(c(1,2,3), c(4,5,6), f), foo2(c(1,2,3), c(4,5,6), f), foo
3(c(1,2,3), c(4,5,6), f), foo4(c(1,2,3), c(4,5,6), f))
Unit: milliseconds
expr min lq mean median uq
foo1(c(1, 2, 3), c(4, 5, 6), f) 2.575459 2.694297 2.905398 2.734009 2.921552
foo2(c(1, 2, 3), c(4, 5, 6), f) 2.574565 2.677380 2.880511 2.731615 2.847573
foo3(c(1, 2, 3), c(4, 5, 6), f) 2.582574 2.701779 2.862598 2.753256 2.875745
foo4(c(1, 2, 3), c(4, 5, 6), f) 2.378309 2.469361 2.675188 2.538140 2.695720
max neval
4.186352 100
5.336418 100
4.611379 100
3.734019 100
f(NumericVector(a.begin(),a.end()))
比其他方法快一点.
And f(NumericVector(a.begin(),a.end()))
is marginally faster than other methods.
这篇关于将RcppArmadillo矢量转换为Rcpp矢量的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!