Matrix multiplication in Rcpp

后端 未结 3 1966
爱一瞬间的悲伤
爱一瞬间的悲伤 2020-12-29 10:12

First of all, I am a novice user so forget my general ignorance. I am looking for a faster alternative to the %*% operator in R. Even though older posts suggest the use of R

相关标签:
3条回答
  • 2020-12-29 10:45

    The following approach can also be used :

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

    With this approach, we use the operator %*% of R.

    0 讨论(0)
  • 2020-12-29 10:52

    I would encourage to try to work out your issues with RcppArmadillo. Using it is as simple as this example also created by calling RcppArmadillo.package.skeleton():

    // another simple example: outer product of a vector, 
    // returning a matrix
    //
    // [[Rcpp::export]]
    arma::mat rcpparma_outerproduct(const arma::colvec & x) {
        arma::mat m = x * x.t();
        return m;
    }
    
    // and the inner product returns a scalar
    //
    // [[Rcpp::export]]
    double rcpparma_innerproduct(const arma::colvec & x) {
        double v = arma::as_scalar(x.t() * x);
        return v;
    }
    

    There is actually more code in the example but this should give you an idea.

    0 讨论(0)
  • 2020-12-29 10:57

    There are good reasons to rely on existing libraries / packages for standard tasks. The routines in the libraries are

    • optimized
    • thoroughly tested
    • a good means to keep the code compact, human-readable, and easy to maintain.

    Therefore I think that using RcppArmadillo or RcppEigen should be preferable here. However, to answer your question, below is a possible Rcpp code to perform a matrix multiplication:

    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;
    }')
    

    Let's test it:

    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
    

    Hope this helps.


    As benchmark tests show, the above Rcpp code is slower than R's built-in %*% operator. I assume that, while my Rcpp code can certainly be improved, it will be hard to beat the optimized code behind %*% in terms of performance:

    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
    
    0 讨论(0)
提交回复
热议问题