【问题标题】:Large Matrices in RcppArmadillo via the ARMA_64BIT_WORD define通过 ARMA_64BIT_WORD 定义的 RcppArmadillo 中的大型矩阵
【发布时间】:2017-03-28 06:51:23
【问题描述】:

在之前的帖子Large SpMat object with RcppArmadillo 中,我决定使用Rcpp 来计算一个大矩阵(~600,000 行 x 11 列)

我已经安装了RcppRcppArmadillo

> sessionInfo()
R version 3.3.1 (2016-06-21)
Platform: x86_64-apple-darwin15.6.0 (64-bit)
Running under: OS X 10.11.6 (El Capitan)

locale:
[1] en_US.UTF-8/en_US.UTF-8/en_US.UTF-8/C/en_US.UTF-8/en_US.UTF-8

attached base packages:
[1] stats     graphics  grDevices utils     datasets  methods   base     

other attached packages:
 [1] RcppArmadillo_0.7.500.0.0 Rcpp_0.12.7               cluster_2.0.4             skmeans_0.2-8            
 [5] ggdendro_0.1-20           ggplot2_2.1.0             lsa_0.73.1                SnowballC_0.5.1          
 [9] data.table_1.9.6          jsonlite_1.1              purrr_0.2.2               stringi_1.1.2            
[13] dplyr_0.5.0               plyr_1.8.4 

loaded via a namespace (and not attached):
 [1] assertthat_0.1   slam_0.1-38      MASS_7.3-45      chron_2.3-47     grid_3.3.1       R6_2.2.0         gtable_0.2.0    
 [8] DBI_0.5-1        magrittr_1.5     scales_0.4.0     tools_3.3.1      munsell_0.4.3    clue_0.3-51      colorspace_1.2-7
[15] tibble_1.2 

使用mtcars 之类的示例,这很完美:

library(lsa)    
x <- as.matrix(mtcars)
cosine(t(x))

这是来自lsacosine 函数:

cosR <- function(x) {
      co <- array(0, c(ncol(x), ncol(x)))
      ## f <- colnames(x)
      ## dimnames(co) <- list(f, f)
      for (i in 2:ncol(x)) {
        for (j in 1:(i - 1)) {
            co[i,j] <- crossprod(x[,i], x[,j])/
                sqrt(crossprod(x[,i]) * crossprod(x[,j]))
        }
    }
    co <- co + t(co)
    diag(co) <- 1
    return(as.matrix(co))
}

Rcpp 中的等价物是这样的:

library(Rcpp)
library(RcppArmadillo)
cppFunction(depends='RcppArmadillo',
            code="NumericMatrix cosCpp(NumericMatrix Xr) {
            int n = Xr.nrow(), k = Xr.ncol();
            arma::mat X(Xr.begin(), n, k, false); // reuses memory and avoids extra copy
            arma::mat Y = arma::trans(X) * X; // matrix product
            arma::mat res = Y / (arma::sqrt(arma::diagvec(Y)) * arma::trans(arma::sqrt(arma::diagvec(Y))));
            return Rcpp::wrap(res);
           }")

可以检查两个函数是否等价

all.equal(cosCpp(x),cosR(x))
[1] TRUE

但是当我在加载 Rcpp 后使用我的数据运行它时,我得到:

x <- as.matrix(my_data)
x <- t(my_data)
y <- cosCpp(x)
error: Mat::init(): requested size is too large
Error in eval(substitute(expr), envir, enclos) : 
  Mat::init(): requested size is too large

更新 @Coatless 建议 + @gvegayon 帖子 + 阅读时间后的解决方案

我将我的函数修改为:

sourceCpp("/myfolder/my_function.cpp")

my_function.cpp的内容是

// [[Rcpp::depends(RcppArmadillo)]]
#include <RcppArmadillo.h>
using namespace Rcpp;

// [[Rcpp::export]]
arma::sp_mat cosine_rcpp(
    const arma::mat & X
) {

  int k = X.n_cols;

  arma::sp_mat ans(k,k);

  for (int i=0;i<k;i++)
    for (int j=i;j<k;j++) {
      // X(i) x X(j)' / sqrt(sum(X^2) * sum(Y^2))
      ans.at(i,j) = arma::norm_dot(X.col(i), X.col(j));

    }

    return ans;
}

然后我运行

cosine_rcpp(x)

【问题讨论】:

  • 为了将来参考,"[...] 说我应该启用 ARMA_64BIT_WORD 但我没有运气启用它" 没有帮助;陈述(并可能展示)您在问题中尝试的内容。
  • 请帮自己(和我们)一个忙,使用sourceCpp()cppFunction() 超出两三行的任何内容都会失控。
  • 嗨。 sourceCpp() 很酷!我刚刚发布了解决方案的尝试。我以前从未曾经使用过 C++

标签: r rcpp


【解决方案1】:
  1. 由于/src 目录中的内容,RcppArmadillo 是一个仅限Rcpp 的包。要启用 C++11,请使用 // [[Rcpp::plugins(cpp11)]]
  2. ARMA_64BIT_WORD 未定义。要定义它,请在 #include &lt;RcppArmadillo.h&gt; 之前添加 #define ARMA_64BIT_WORD 1

使用sourceCpp()的示例实现

#define ARMA_64BIT_WORD 1
#include <RcppArmadillo.h>
// [[Rcpp::depends(RcppArmadillo)]]
// [[Rcpp::plugins(cpp11)]] 

// [[Rcpp::export]] 
arma::mat cosCpp(const arma::mat& X) {

    arma::mat Y = arma::trans(X) * X; // matrix product
    arma::mat res = Y / (arma::sqrt(arma::diagvec(Y)) * arma::trans(arma::sqrt(arma::diagvec(Y))));

    return res;
}

要在 /src/Makevars{.win} 中定义它以供包使用:

PKG_CPPFLAGS = -DARMA_64BIT_WORD=1

【讨论】:

  • @pachamaltese : 使用sourceCpp(code =" ") 获取上述代码或将其放入外部文件test.cpp 并通过sourceCpp(file="/path/to/test.cpp") 获取源代码
  • 感谢@Coatless。包含 cpp11 会产生另一个错误,我现在在更新中发布。
  • 当我不可避免地回到这一点时,主要是为我自己评论:订单很重要!不能只在任何地方添加 #define 语句,#include 之前的存在确实很重要 headdesk
猜你喜欢
  • 2021-02-02
  • 2020-06-10
  • 2017-08-06
  • 1970-01-01
  • 2020-05-09
  • 1970-01-01
  • 2013-04-12
  • 2011-05-02
相关资源
最近更新 更多