Rcpp特征稀疏矩阵cbind

Rcpp特征稀疏矩阵cbind,r,matrix,eigen,rcpp,R,Matrix,Eigen,Rcpp,我正在研究Rcpp(特征值)中的一个算法,该算法需要矩阵的cbind等价物。我发现R的cbind非常快,而使用Eigen非常慢。我想找到一种方法来优化这个函数,这样我就可以在Rcpp中保留我的算法。到目前为止,我已经找到了另一个,但它适用于稠密矩阵上的cbind #include <RcppEigen.h> // [[Rcpp::depends(RcppEigen)]] using namespace Rcpp; using namespace Eigen; // [[Rcpp:

我正在研究Rcpp(特征值)中的一个算法,该算法需要矩阵的cbind等价物。我发现R的cbind非常快,而使用Eigen非常慢。我想找到一种方法来优化这个函数,这样我就可以在Rcpp中保留我的算法。到目前为止,我已经找到了另一个,但它适用于稠密矩阵上的cbind

#include <RcppEigen.h>
// [[Rcpp::depends(RcppEigen)]]

using namespace Rcpp;
using namespace Eigen;

// [[Rcpp::export]]
Eigen::SparseMatrix<double> RcppMatrixCbind(Eigen::MappedSparseMatrix<double>& matrix1,
                                            Eigen::MappedSparseMatrix<double>& matrix2) {

  SparseMatrix<double> out(matrix1.rows(), matrix1.cols() + matrix2.cols());
  std::vector<Triplet<double> > tripletList;
  tripletList.reserve(matrix1.nonZeros() + matrix2.nonZeros());
  for (int k = 0; k < matrix1.outerSize(); ++k)
  {
    for (MappedSparseMatrix<double>::InnerIterator it(matrix1, k); it; ++it)
    {
      tripletList.push_back(Triplet<double>(it.row(), it.col(), it.value()));
    }
  }
  for (int k = 0; k < matrix2.outerSize(); ++k)
  {
    for (MappedSparseMatrix<double>::InnerIterator it(matrix2, k); it; ++it)
    {
      tripletList.push_back(Triplet<double>(it.row(), it.col() + matrix1.cols(), it.value()));
    }
  }
  out.setFromTriplets(tripletList.begin(), tripletList.end());
  return out;
}

/*** R
require(Matrix)
x = rsparsematrix(10000, 500, .1)
system.time(foo <- cbind(x,x))
system.time(bar <- RcppMatrixCbind(x, x))
  */
#包括
//[[Rcpp::depends(RcppEigen)]]
使用名称空间Rcpp;
使用名称空间特征;
//[[Rcpp::导出]]
Eigen::SparseMatrix RCPPMatrixBind(Eigen::MappedSparseMatrix和matrix1,
本征::MappedSparseMatrix和matrix2){
SPARSAMTRIX out(matrix1.rows(),matrix1.cols()+matrix2.cols());
std::向量三元组列表;
tripleList.reserve(matrix1.nonZeros()+matrix2.nonZeros());
对于(int k=0;k时间(foo这实际上更多的是一个特征问题:如何扩展稀疏矩阵

您在解决方案中所做的是逐个元素地执行所有操作,并且很可能一个专用的分块操作可以打败它。这就是我们在
矩阵
解决方案中所看到的,转到高效代码,可能来自CHOLMD

我快速查看了Eigen文档。它警告:

关于读取访问,稀疏矩阵公开了与密集矩阵相同的API来访问子矩阵,如块、列和行。有关详细介绍,请参阅块操作。但是,出于性能原因,写入子稀疏矩阵的限制要大得多,目前仅限连续的列集(对应行)列MAJURE(和行MAJURE)的SparseMatrix是可写的。此外,此信息必须在编译时已知,而不包括
block(…)
corner*(…)
等方法

但是我们很幸运,因为blocky中的
cbind()

// [[Rcpp::export]]
Eigen::SparseMatrix<double>
RcppMatrixCb2(Eigen::MappedSparseMatrix<double>& matrix1,
              Eigen::MappedSparseMatrix<double>& matrix2) {

  SparseMatrix<double> out(matrix1.rows(), matrix1.cols() + matrix2.cols());

  out.leftCols(matrix1.cols()) = matrix1; 
  out.rightCols(matrix2.cols()) = matrix2; 
  return out;
}
我的完整文件如下。它在两个函数中都缺少测试:我们需要确保矩阵1和矩阵2具有相同的行

// cf https://stackoverflow.com/questions/45875668/rcpp-eigen-sparse-matrix-cbind

#include <RcppEigen.h>
// [[Rcpp::depends(RcppEigen)]]

using namespace Rcpp;
using namespace Eigen;

// [[Rcpp::export]]
Eigen::SparseMatrix<double> RcppMatrixCbind(Eigen::MappedSparseMatrix<double>& matrix1,
                                            Eigen::MappedSparseMatrix<double>& matrix2) {

  SparseMatrix<double> out(matrix1.rows(), matrix1.cols() + matrix2.cols());
  std::vector<Triplet<double> > tripletList;
  tripletList.reserve(matrix1.nonZeros() + matrix2.nonZeros());
  for (int k = 0; k < matrix1.outerSize(); ++k) {
    for (MappedSparseMatrix<double>::InnerIterator it(matrix1, k); it; ++it) {
      tripletList.push_back(Triplet<double>(it.row(), it.col(), it.value()));
    }
  }
  for (int k = 0; k < matrix2.outerSize(); ++k) {
    for (MappedSparseMatrix<double>::InnerIterator it(matrix2, k); it; ++it) {
      tripletList.push_back(Triplet<double>(it.row(), it.col() + matrix1.cols(), it.value()));
    }
  }
  out.setFromTriplets(tripletList.begin(), tripletList.end());
  return out;
}

// [[Rcpp::export]]
Eigen::SparseMatrix<double> RcppMatrixCb2(Eigen::MappedSparseMatrix<double>& matrix1,
                                          Eigen::MappedSparseMatrix<double>& matrix2) {

  SparseMatrix<double> out(matrix1.rows(), matrix1.cols() + matrix2.cols());

  out.leftCols(matrix1.cols()) = matrix1; 
  out.rightCols(matrix2.cols()) = matrix2; 
  return out;
}


/*** R
require(Matrix)
set.seed(42)
x = rsparsematrix(10000, 500, .1)
library(rbenchmark)
benchmark(Matrix=cbind(x,x), 
          prevSol=RcppMatrixCbind(x,x), 
          newSol=RcppMatrixCb2(x,x),
          order="relative")[,1:4]
*/
//cfhttps://stackoverflow.com/questions/45875668/rcpp-eigen-sparse-matrix-cbind
#包括
//[[Rcpp::depends(RcppEigen)]]
使用名称空间Rcpp;
使用名称空间特征;
//[[Rcpp::导出]]
Eigen::SparseMatrix RCPPMatrixBind(Eigen::MappedSparseMatrix和matrix1,
本征::MappedSparseMatrix和matrix2){
SPARSAMTRIX out(matrix1.rows(),matrix1.cols()+matrix2.cols());
std::向量三元组列表;
tripleList.reserve(matrix1.nonZeros()+matrix2.nonZeros());
对于(int k=0;k
这实际上更像是一个本征问题:如何展开稀疏矩阵

您在解决方案中所做的是逐个元素地执行所有操作,并且很可能一个专用的分块操作可以打败它。这就是我们在
矩阵
解决方案中所看到的,转到高效代码,可能来自CHOLMD

我快速查看了Eigen文档。它警告:

关于读取访问,稀疏矩阵公开了与密集矩阵相同的API来访问子矩阵,如块、列和行。有关详细介绍,请参阅块操作。但是,出于性能原因,写入子稀疏矩阵的限制要大得多,目前仅限连续的列集(对应行)列MAJURE(和行MAJURE)的SparseMatrix是可写的。此外,此信息必须在编译时已知,而不包括
block(…)
corner*(…)
等方法

但是我们很幸运,因为blocky中的
cbind()

// [[Rcpp::export]]
Eigen::SparseMatrix<double>
RcppMatrixCb2(Eigen::MappedSparseMatrix<double>& matrix1,
              Eigen::MappedSparseMatrix<double>& matrix2) {

  SparseMatrix<double> out(matrix1.rows(), matrix1.cols() + matrix2.cols());

  out.leftCols(matrix1.cols()) = matrix1; 
  out.rightCols(matrix2.cols()) = matrix2; 
  return out;
}
我的完整文件如下。它在两个函数中都缺少测试:我们需要确保矩阵1和矩阵2具有相同的行

// cf https://stackoverflow.com/questions/45875668/rcpp-eigen-sparse-matrix-cbind

#include <RcppEigen.h>
// [[Rcpp::depends(RcppEigen)]]

using namespace Rcpp;
using namespace Eigen;

// [[Rcpp::export]]
Eigen::SparseMatrix<double> RcppMatrixCbind(Eigen::MappedSparseMatrix<double>& matrix1,
                                            Eigen::MappedSparseMatrix<double>& matrix2) {

  SparseMatrix<double> out(matrix1.rows(), matrix1.cols() + matrix2.cols());
  std::vector<Triplet<double> > tripletList;
  tripletList.reserve(matrix1.nonZeros() + matrix2.nonZeros());
  for (int k = 0; k < matrix1.outerSize(); ++k) {
    for (MappedSparseMatrix<double>::InnerIterator it(matrix1, k); it; ++it) {
      tripletList.push_back(Triplet<double>(it.row(), it.col(), it.value()));
    }
  }
  for (int k = 0; k < matrix2.outerSize(); ++k) {
    for (MappedSparseMatrix<double>::InnerIterator it(matrix2, k); it; ++it) {
      tripletList.push_back(Triplet<double>(it.row(), it.col() + matrix1.cols(), it.value()));
    }
  }
  out.setFromTriplets(tripletList.begin(), tripletList.end());
  return out;
}

// [[Rcpp::export]]
Eigen::SparseMatrix<double> RcppMatrixCb2(Eigen::MappedSparseMatrix<double>& matrix1,
                                          Eigen::MappedSparseMatrix<double>& matrix2) {

  SparseMatrix<double> out(matrix1.rows(), matrix1.cols() + matrix2.cols());

  out.leftCols(matrix1.cols()) = matrix1; 
  out.rightCols(matrix2.cols()) = matrix2; 
  return out;
}


/*** R
require(Matrix)
set.seed(42)
x = rsparsematrix(10000, 500, .1)
library(rbenchmark)
benchmark(Matrix=cbind(x,x), 
          prevSol=RcppMatrixCbind(x,x), 
          newSol=RcppMatrixCb2(x,x),
          order="relative")[,1:4]
*/
//cfhttps://stackoverflow.com/questions/45875668/rcpp-eigen-sparse-matrix-cbind
#包括
//[[Rcpp::depends(RcppEigen)]]
使用名称空间Rcpp;
使用名称空间特征;
//[[Rcpp::导出]]
Eigen::SparseMatrix RCPPMatrixBind(Eigen::MappedSparseMatrix和matrix1,
本征::MappedSparseMatrix和matrix2){
SPARSAMTRIX out(matrix1.rows(),matrix1.cols()+matrix2.cols());
std::向量三元组列表;
tripleList.reserve(matrix1.nonZeros()+matrix2.nonZeros());
对于(int k=0;k