有没有更快的方法在Rcpp / c ++中进行Cholesky分解?

时间:2016-03-06 16:06:43

标签: r matrix linear-algebra rcpp armadillo

这是马尔可夫链蒙特卡罗(MCMC)算法中出现的问题。我觉得这个问题很常见,特别是在分层高斯模型中。因此,如果有一个更有效的解决方案,那将是很好的。所以问题是这样的:

我有许多正整数向量xi,{1}从1到n,p.s.d。矩阵i和p.s.d.矩阵A。对于每个B,我想计算以下Cholesky分解:

  

chol(kron(diagmat(xi),A)+ B)

所以xi是多元高斯的协方差矩阵,我想从这个高斯中进行采样,因此需要对其进行Cholesky分解。 kron( diagmat( xi ), A ) + BA的维度不小,我有一个很大的B,因此计算所有n的上述Cholesky分解是非常耗时的。以下是我使用xi编写的Rcpp函数:

RcppArmadillo

我还使用以下代码测试计算效率:将其与R对应物进行比较:

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

// [[Rcpp::export]]
mat test_C(mat A, mat B, mat X){
  int n_x = X.n_cols;
  int d_B = B.n_rows;
  mat sample(d_B, n_x);
  mat mS_chol_inv;
  for (int i = 0; i < n_x; i++){
    mS_chol_inv = inv(trimatu( chol(kron(diagmat( X.col(i) ),A) + B) ));
    sample.col(i) = mS_chol_inv*randn(d_B);
  }
  return(sample);
}

结果如下

test_R <- function(A,B,X){
  n_x <- ncol(X)
  d_B <- ncol(B)
  res <- sapply(1:n_x, function(x){
    mS_chol <- chol( kronecker( diag(X[,x]),A ) + B )
    return( mS_chol%*%as.matrix( rnorm(d_B) ) )
  })
  return(res)
}

# Simulate Data
R1 <- matrix(rnorm(24*2),24,2)
A <- R1%*%t(R1) + 0.1*diag(24)
R2 <- matrix(rnorm(264*2),264,2)
B <- R2%*%t(R2) + 0.1*diag(264)
X <- matrix(rpois(11*2178, 5),11,2178)

res <- benchmark(res_R <- test_R(A, B, X),
             res_C <- test_C(A, B, X),
             columns=c("test", "replications", "elapsed", "relative"),
             order="relative",
             replications = 2)

可以看出,单次运行大约是10秒,这在MCMC算法中根本不可行。此外,由于> print(res) test replications elapsed relative 1 res_R <- test_R(A, B, X) 2 18.920 1.000 2 res_C <- test_C(A, B, X) 2 20.724 1.095 支配着计算复杂性,因此使用chol()优于纯Rcpp的改进是微不足道的。但也许我没有编写最有效的代码?那么有什么建议吗?

由于R内的矩阵是非常结构化的,唯一变化的是chol(),也许有一些我不知道可以有效解决这个问题的代数技巧?我在数学下发布了这个线性代数问题,这里是link。不幸的是到目前为止我还没有得到任何解决方案,人们确实指出这是令人尴尬的平行。

关于代码/代数的任何建议都会有所帮助!谢谢你的时间。

2 个答案:

答案 0 :(得分:2)

您可以尝试使用以前称为RRO的艺术家MeasureString中的Microsoft R 。它集成了多线程英特尔MKL库(找到并安装它的相同位置),并且在英特尔硬件矩阵操作上非常快。

免责声明:YMMV

答案 1 :(得分:0)

改用 RcppEigen 会让您受益匪浅。

这是因为:

  • Eigen 具有更快的 Cholesky 求解器
  • Eigen 允许引用子视图,并具有用于从这些子视图中解决 Cholesky 的内置优化
  • Eigen 有大量专门针对 LLT 分解的幕后优化,您可以在不知情的情况下从中受益。

就您可以预期的性能提升而言,我只能谈谈我的用例,我使用 LLT 分解将矩阵分解到 100x100,但犰狳几乎慢了 50%

查看 Eigen 和 Armadillo 的源代码! Armadillo 通过通用模板运行每个 cholesky 到 LAPACK/BLAS“辅助”库。 Eigen 在内部运行决策树来选择优化的实现,然后尽可能参考内存中的内部结构直接求解。

tl;dr:对于分解,你不会轻易击败 Eigen。