C++ Rcpp中的矩阵乘法

C++ Rcpp中的矩阵乘法,c++,r,rcpp,C++,R,Rcpp,首先,我是一个新手,所以请忘记我的无知。我正在寻找一个比R中的%*%操作符更快的替代方法。尽管以前的帖子建议使用RcppArmadillo,但我已经尝试了2个小时使RcppArmadillo工作,但没有成功。我总是遇到词汇问题,产生“意想不到的…”错误。我发现Rcpp中的以下功能可以正常工作: library(Rcpp) func <- ' NumericMatrix mmult( NumericMatrix m , NumericMatrix v, bool byrow=true )

首先,我是一个新手,所以请忘记我的无知。我正在寻找一个比R中的%*%操作符更快的替代方法。尽管以前的帖子建议使用RcppArmadillo,但我已经尝试了2个小时使RcppArmadillo工作,但没有成功。我总是遇到词汇问题,产生“意想不到的…”错误。我发现Rcpp中的以下功能可以正常工作:

library(Rcpp)
func <- '
NumericMatrix mmult( NumericMatrix m , NumericMatrix v, bool  byrow=true )
{
  if( ! m.nrow() == v.nrow() ) stop("Non-conformable arrays") ;
  if( ! m.ncol() == v.ncol() ) stop("Non-conformable arrays") ;

  NumericMatrix out(m) ;

  for (int i = 0; i < m.nrow(); i++) 
  {
  for (int j = 0; j < m.ncol(); j++) 
  {
  out(i,j)=m(i,j) * v(i,j) ;
  }
  }
  return out ;
}
'
库(Rcpp)

func我鼓励您尝试与Rcpaparmadillo解决您的问题。使用它与此示例一样简单,调用
RcppArmadillo.package.skeleton()


示例中实际上有更多的代码,但这应该给您一个想法。

有充分的理由依赖现有的库/包来完成标准任务。库中的例程是

  • 优化
  • 彻底测试
  • 这是保持代码紧凑、可读性好、易于维护的好方法
因此,我认为在这里使用RcppArmadillo或RcppEigen应该更可取。然而,为了回答您的问题,下面是一个可能的Rcpp代码,用于执行矩阵乘法:

library(Rcpp)
cppFunction('NumericMatrix mmult(const NumericMatrix& m1, const NumericMatrix& m2){
if (m1.ncol() != m2.nrow()) stop ("Incompatible matrix dimensions");
NumericMatrix out(m1.nrow(),m2.ncol());
NumericVector rm1, cm2;
for (size_t i = 0; i < m1.nrow(); ++i) {
    rm1 = m1(i,_);
    for (size_t j = 0; j < m2.ncol(); ++j) {
      cm2 = m2(_,j);
      out(i,j) = std::inner_product(rm1.begin(), rm1.end(), cm2.begin(), 0.);              
    }
  }
return out;
}')

也可以使用以下方法:

NumericMatrix mmult(NumericMatrix m, NumericMatrix v)
{
  Environment base("package:base");
  Function mat_Mult = base["%*%"];
  return(mat_Mult(m, v));
}

通过这种方法,我们使用了R

的运算符%*%。该注释部分不正确,因为RcppEigen不依赖于Egeng的系统副本,而是提供了自己的副本,与其他R软件包类似。啊,感谢您的澄清,@Dirkedelbuettel。很高兴知道。我以为是包装纸谢谢你的回答,德克。这是调用“RcppArmadillo.package.skeleton()”后在第一行中得到的结果:错误:在“/”中出现意外的“/”。安装了Rcpp和RcppArmadillo包,我按照说明进行了操作。您需要以包(和目录)名称为参数:
RcppArmadillo.package.skeleton(“mypackage”)
。再次感谢您,Dirk。我仍然会犯同样的错误。诸如“rcpp\u hello\u world”之类的命令请参见:谢谢RHertel,非常有趣。C++语法对我来说是一个挑战。我已经成功地用RcppEigen击败了%*%,请参阅我第一篇文章中的编辑。很好。正如我在第一次评论和回答中所说,使用RcppEigen是一种好方法——特别是如果您不想自己编写算法。无需重新发明车轮;-)
library(Rcpp)
cppFunction('NumericMatrix mmult(const NumericMatrix& m1, const NumericMatrix& m2){
if (m1.ncol() != m2.nrow()) stop ("Incompatible matrix dimensions");
NumericMatrix out(m1.nrow(),m2.ncol());
NumericVector rm1, cm2;
for (size_t i = 0; i < m1.nrow(); ++i) {
    rm1 = m1(i,_);
    for (size_t j = 0; j < m2.ncol(); ++j) {
      cm2 = m2(_,j);
      out(i,j) = std::inner_product(rm1.begin(), rm1.end(), cm2.begin(), 0.);              
    }
  }
return out;
}')
A <- matrix(c(1:6),ncol=2)
B <- matrix(c(0:7),nrow=2)
mmult(A,B)
#     [,1] [,2] [,3] [,4]
#[1,]    4   14   24   34
#[2,]    5   19   33   47
#[3,]    6   24   42   60
identical(mmult(A,B), A %*% B)
#[1] TRUE
library(microbenchmark)
set.seed(123)    
M1 <- matrix(rnorm(1e4),ncol=100)
M2 <- matrix(rnorm(1e4),nrow=100)
identical(M1 %*% M2, mmult(M1,M2))
#[1] TRUE
res <- microbenchmark(
             mmult(M1,M2),
             M1 %*% M2,
             times=1000L)
#> res 
#Unit: microseconds
#          expr      min        lq      mean    median        uq      max neval cld
# mmult(M1, M2) 1466.855 1484.8535 1584.9509 1494.0655 1517.5105 2699.643  1000   b
#     M1 %*% M2  602.053  617.9685  687.6863  621.4335  633.7675 2774.954  1000  a
NumericMatrix mmult(NumericMatrix m, NumericMatrix v)
{
  Environment base("package:base");
  Function mat_Mult = base["%*%"];
  return(mat_Mult(m, v));
}