af::array 转换为 float 或 double

af::array conversion to float or double

我一直在试验 RcppArrayFire 包,主要是重写 RcppArmadillo 的一些成本函数,但似乎无法克服“从 'af::array' 到 'float' 没有可行的转换”。我也一直得到一些后端错误,下面的例子似乎没有这些。

这个 cov-var 示例写得很糟糕,只是为了使用我实际成本函数中的所有相关编码片段。截至目前,它是 "RcppArrayFire.package.skeleton".

生成的包中的唯一添加项
#include "RcppArrayFire.h"
#include <Rcpp.h>
// [[Rcpp::depends(RcppArrayFire)]]
// [[Rcpp::export]]
float example_ols(const RcppArrayFire::typed_array<f32>& X_vect,  const RcppArrayFire::typed_array<f32>& Y_vect){

  int Len = X_vect.dims()[0];
  int Len_Y = Y_vect.dims()[0];

  while( Len_Y < Len){
    Len --;
  }

  float mean_X = af::sum(X_vect)/Len;
  float mean_Y = af::sum(Y_vect)/Len;

  RcppArrayFire::typed_array<f32> temp(Len);
  RcppArrayFire::typed_array<f32> temp_x(Len);

  for( int f = 0; f < Len; f++){
    temp(f) = (X_vect(f) - mean_X)*(Y_vect(f) - mean_Y);
    temp_x(f) = af::pow(X_vect(f) -mean_X, 2);
  }

  return af::sum(temp)/af::sum(temp_x);
}


/*** R
  X <- 1:10
  Y <- 2*X +rnorm(10, mean = 0, sd = 1)
  example_ols(X, Y)
*/

首先要考虑的是 af::sum 函数,它有不同的形式:sf::sum(af::array),returns 设备内存中的 af::array 和模板化的 af::sum<T>(af::array) 那 returns 主机内存中的一个 T。因此,对您的示例的最小更改是使用 af::sum<float>:

#include "RcppArrayFire.h"
#include <Rcpp.h>
// [[Rcpp::depends(RcppArrayFire)]]
// [[Rcpp::export]]
float example_ols(const RcppArrayFire::typed_array<f32>& X_vect,
                  const RcppArrayFire::typed_array<f32>& Y_vect){

    int Len = X_vect.dims()[0];
    int Len_Y = Y_vect.dims()[0];

    while( Len_Y < Len){
        Len --;
    }

    float mean_X = af::sum<float>(X_vect)/Len;
    float mean_Y = af::sum<float>(Y_vect)/Len;

    RcppArrayFire::typed_array<f32> temp(Len);
    RcppArrayFire::typed_array<f32> temp_x(Len);

    for( int f = 0; f < Len; f++){
        temp(f) = (X_vect(f) - mean_X)*(Y_vect(f) - mean_Y);
        temp_x(f) = af::pow(X_vect(f) -mean_X, 2);
    }

    return af::sum<float>(temp)/af::sum<float>(temp_x);
}


/*** R
set.seed(1)
X <- 1:10
Y <- 2*X +rnorm(10, mean = 0, sd = 1)
example_ols(X, Y)
*/

但是,还有更多可以改进的地方。排名不分先后:

  • 您不需要包含 Rcpp.h
  • 有一个 af::mean 函数用于计算 af::array 的平均值。
  • 一般来说,RcppArrayFire::typed_array<T> 只需要将数组从 R 转换为 C++。在 C++ 中以及返回的方式中,您可以使用 af::array.
  • 即使您的设备不支持 double,您仍然可以在主机上使用 double 值。
  • 为了获得良好的性能,您应该避免 for 循环并使用 vectorized functions,就像在 R 中一样。您必须为 X 和 [=28 施加相同的维度=],虽然。

有趣的是,当我使用向量化函数时,我得到了不同的结果。现在我不确定为什么会这样,但下面的表格对我来说更有意义。您应该验证结果是否是您想要得到的:

#include <RcppArrayFire.h>
// [[Rcpp::depends(RcppArrayFire)]]
// [[Rcpp::export]]
double example_ols(const RcppArrayFire::typed_array<f32>& X_vect,
                   const RcppArrayFire::typed_array<f32>& Y_vect){

    double mean_X = af::mean<double>(X_vect);
    double mean_Y = af::mean<double>(Y_vect);

    af::array temp = (X_vect - mean_X) * (Y_vect - mean_Y);
    af::array temp_x = af::pow(X_vect - mean_X, 2.0);

    return af::sum<double>(temp)/af::sum<double>(temp_x);
}

/*** R
set.seed(1)
X <- 1:10
Y <- 2*X +rnorm(10, mean = 0, sd = 1)
example_ols(X, Y)
*/ 

顺便说一句,更短的版本是:

#include <RcppArrayFire.h>
// [[Rcpp::depends(RcppArrayFire)]]
// [[Rcpp::export]]
af::array example_ols(const RcppArrayFire::typed_array<f32>& X_vect,
                      const RcppArrayFire::typed_array<f32>& Y_vect){

    return af::cov(X_vect, Y_vect) / af::var(X_vect);
}

一般来说,尽可能多地使用内置函数是个好主意。