繁体   English   中英

将 RcppArmadillo 向量转换为 Rcpp 向量

[英]Convert RcppArmadillo vector to Rcpp vector

我正在尝试将 RcppArmadillo 向量(例如arma::colvec )转换为 Rcpp 向量( NumericVector )。 我知道我可以先将arma::colvec转换为SEXP ,然后将SEXP转换为NumericVector (例如as<NumericVector>(wrap(temp) ),假设 temp 是一个arma::colvec对象)。 但是这样做的好方法是什么?

我想这样做只是因为我不确定是否可以将arma::colvec对象作为参数传递给Rcpp::Function对象。

我试图用参数arma::vec评估一个Rcpp::Function ,它似乎采用四种形式的参数而没有编译错误。 也就是说,如果f是一个Rcpp::Functiona是一个arma::vec ,那么

  1. f(a)
  2. f(wrap(a))
  3. f(as<NumericVector>(wrap(a)))
  4. f(NumericVector(a.begin(),a.end()))

不会产生编译和运行时错误,至少表面上看是这样。

为此,我对四种说法进行了小测试。 因为我怀疑垃圾回收会出问题,所以我再次测试它们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

结果,第一种方法产生错误,第二种方法产生错误答案,只有第三种和第四种方法返回正确答案。

> # 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 ,则所有函数都将返回正确的结果。

> 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 在运行时收集垃圾时会受到中断,我们不知道它何时发生。 因此,不正确包装参数是危险的。

编辑:截至 2017 年 12 月 5 日,所有四个转换都产生了正确的结果。

  1. f(a)
  2. f(wrap(a))
  3. f(as<NumericVector>(wrap(a)))
  4. 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()))比其他方法快一点。

这应该适用于arma::vecarma::rowvecarma::colvec

template <typename T>
Rcpp::NumericVector arma2vec(const T& x) {
    return Rcpp::NumericVector(x.begin(), x.end());
}

我有同样的问题。 我用wrap在几层for循环的核心做转换,速度很慢。 我认为包装功能是拖慢速度的罪魁祸首,所以我想知道是否有一种优雅的方法可以做到这一点。

至于雷蒙德的问题,您可能想尝试包括像这样的命名空间: Rcpp::as<Rcpp::NumericVector>(wrap(A))而不是或包括一行using namespace Rcpp; 在代码的开头。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM