我正在运行的产品扩散研究中的关键步骤涉及稀疏矩阵与向量的乘法。下面的代码使用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中是否有更有效的乘法习惯用法?
答案 0 :(得分:1)
没有。这里记录的问题有两个方面:
Matrix
的使用 C 例程。关于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.R,src/Csparse.c
,src/dtrMatrix.c
查看所述例程的示例。因此,Matrix
操作效率会更高。
现在, 表示无法在 C ++ 中获得速度。特别是,如果矩阵对象在 C ++ 中重复使用,用于乘法传递的实例化(例如&
),那么它应该比调用{{Matrix
更快。 1}}的乘法程序。