犰狳:将立方体子视图(管)转换为矢量

时间:2017-07-03 22:07:56

标签: c++ rcpp armadillo

当我尝试从armadillo cube(使用tube或slice)获取vector / double时出现编译错误。如何从立方体到(行)vec?我找不到优雅的演员/变形犰狳功能。

#include <RcppArmadillo.h>
//#include <Rcpp.h>
using namespace Rcpp;

// [[Rcpp::export]]
void testarma() {
  arma::mat B;

  B << 0.555950 << 0.274690 << 0.540605 << 0.798938 << arma::endr
    << 0.108929 << 0.830123 << 0.891726 << 0.895283 << arma::endr
    << 0.948014 << 0.973234 << 0.216504 << 0.883152 << arma::endr
    << 0.023787 << 0.675382 << 0.231751 << 0.450332 << arma::endr;

  B.print("B:");

  // cubes ("3D matrices")
  arma::cube Q(B.n_rows, B.n_cols, 4);

  Q.slice(0) = B;
  Q.slice(1) = 2.0 * B;
  Q.slice(2) = 3.0 * B;
  Q.slice(3) = 4.0 * B;

  Q.print("Q:");

  Rcpp::Rcout << "Q.tube(0, 1): " << std::endl << Q.tube(0, 1) << std::endl;

  arma::rowvec whatIwant = arma::rowvec(4).fill(0.0);

  for (int i = 0; i < 4; i++) {
    // This gives an error. cannot convert 'arma::subview_col<double>' to 'double' in assignment
    //whatIwant[i] = Q.slice(i).row(0).col(1);
    Rcpp::Rcout << "At slice i=" << i << " value=" << Q.slice(i).row(0).col(1) << std::endl;
  }

  // But I don't want to write for loop. I am sure there exists
  // an "armadillo" way (function) that does exactly this
  // How to convert output of tube to rowvec?
}

1 个答案:

答案 0 :(得分:5)

我认为有三种方法可以做到:

  1. 使用as_scalar()的循环将最终子集转换为double
  2. 子集到多维数据集然后使用共享内存指针
  3. 直接子集到rowvec
  4. 最后一个选项很可能是你想要的,因为它可以内联完成。

    在您的情况下,操作将是:

    arma::rowvec A = Q(arma::span(0), arma::span(1), arma::span::all);
    

    这取自文档的subcube子集部分。

    上述每种情况的实施如下所示。

    #include <RcppArmadillo.h>
    
    // [[Rcpp::depends(RcppArmadillo)]]
    
    // [[Rcpp::export]]
    void cube_subset_to_rowvec() {
        // Sample data
        arma::mat B;
    
        B << 0.555950 << 0.274690 << 0.540605 << 0.798938 << arma::endr
          << 0.108929 << 0.830123 << 0.891726 << 0.895283 << arma::endr
          << 0.948014 << 0.973234 << 0.216504 << 0.883152 << arma::endr
          << 0.023787 << 0.675382 << 0.231751 << 0.450332 << arma::endr;
    
        // cubes ("3D matrices")
        arma::cube Q(B.n_rows, B.n_cols, 4);
    
        Q.slice(0) = B;
        Q.slice(1) = 2.0 * B;
        Q.slice(2) = 3.0 * B;
        Q.slice(3) = 4.0 * B;
    
        // Objective
        Rcpp::Rcout << "Q.tube(0, 1): " << std::endl << Q.tube(0, 1) << std::endl;
    
        // Individually loading elements
        arma::rowvec individual_elements(4);
        for (int i = 0; i < 4; i++) {
            individual_elements[i] = arma::as_scalar(Q.slice(i).row(0).col(1));
            Rcpp::Rcout << "At slice i=" << i << " value=" << individual_elements[i] << std::endl;
        }
    
        // Subset to cube then use a shared memory pointer
        arma::cube mem_ex = Q.tube(0,1);
        arma::rowvec cub_subset = arma::rowvec(mem_ex.memptr(), mem_ex.n_elem, 1, false);
        Rcpp::Rcout << cub_subset << std::endl;
    
        // Direct subset to a rowvec
        arma::rowvec direct_subset = Q(arma::span(0), arma::span(1), arma::span::all);
        Rcpp::Rcout << direct_subset << std::endl;
    
    }
    

    执行命令

    cube_subset_to_rowvec()
    

    输出:

    Q.tube(0, 1): 
    [cube slice 0]
       0.2747
    
    [cube slice 1]
       0.5494
    
    [cube slice 2]
       0.8241
    
    [cube slice 3]
       1.0988
    
    
    At slice i=0 value=0.27469
    At slice i=1 value=0.54938
    At slice i=2 value=0.82407
    At slice i=3 value=1.09876
       0.2747   0.5494   0.8241   1.0988
    
       0.2747   0.5494   0.8241   1.0988