稀疏矩阵乘法的执行时间

时间:2017-11-14 02:36:12

标签: r rcpp armadillo

我正在运行的产品扩散研究中的关键步骤涉及稀疏矩阵与向量的乘法。下面的代码使用Rcpp和R中的版本重现代码。

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

using namespace Rcpp;

// [[Rcpp::export]]
arma::vec multiply(arma::sp_mat A, arma::vec nodes_status) {

  return A * nodes_status;
}


/***R

library(rbenchmark)
library(igraph)

g <- sample_smallworld(dim = 1, size = 1e5, nei = 12, p = 0.65)

nodes <- V(g)
A <- get.adjacency(g)

nodes.status <- sample(x = c(0, 1), 
                       size = length(nodes), 
                       replace = TRUE, 
                       prob = c(0.9, 0.1))

multiplyR <- function(A, n) {return(as.vector(A %*% n))}

sum(multiply(A, nodes.status) == multiplyR(A, nodes.status)) == 1e5 # check if the results are the same

benchmark(multiply(A, nodes.status), multiplyR(A, nodes.status), order = "relative")[, 1:4]

*/ 

当我运行此代码时,两个函数的答案都相符,但执行时间如下:

                    test     replications elapsed relative
2 multiplyR(A, nodes.status)          100    1.30    1.000
1  multiply(A, nodes.status)          100    3.66    2.815

这里的代码有什么问题?在我的案例中,Rcpp中是否有更有效的乘法习惯用法?

1 个答案:

答案 0 :(得分:1)

没有。这里记录的问题有两个方面:

  1. R 中的稀疏矩阵转换为 RcppArmadillo 对象所需的转换时间大于Matrix的使用 C 例程。
  2. 复制参考创建的成本。
  3. 关于2.,arma::sp_mat的构造使用副本,因为它没有引用(例如&)作为后缀。特别要注意:

    #define ARMA_64BIT_WORD
    #include <RcppArmadillo.h>
    
    //[[Rcpp::depends(RcppArmadillo)]]
    
    // [[Rcpp::export]]
    arma::vec sp_multiply_copy(arma::sp_mat A, arma::vec nodes_status) {
      return A * nodes_status;
    }
    
    // [[Rcpp::export]]
    arma::vec sp_multiply_ref(const arma::sp_mat& A, const arma::vec& nodes_status) {
      return A * nodes_status;
    }
    

    从这里开始,两者之间略有不同的性能差异:

    benchmark(sp_multiply_copy(A, nodes.status),
              sp_multiply_ref(A, nodes.status),
              multiplyR(A, nodes.status), order = "relative")[, 1:4]
    
    #                                test replications elapsed relative
    # 3        multiplyR(A, nodes.status)          100   1.240    1.000
    # 2  sp_multiply_ref(A, nodes.status)          100   2.766    2.231
    # 1 sp_multiply_copy(A, nodes.status)          100   3.141    2.533
    

    说到这里,我们回到第一点: 稀疏矩阵的Matrix函数经过高度优化,直接使用 C 可以在R/products.Rsrc/Csparse.csrc/dtrMatrix.c查看所述例程的示例。因此,Matrix操作效率会更高。

    现在, 表示无法在 C ++ 中获得速度。特别是,如果矩阵对象在 C ++ 中重复使用,用于乘法传递的实例化(例如&),那么它应该比调用{{Matrix更快。 1}}的乘法程序。