Eigen:: 将稀疏矩阵转换为行顺序或列顺序
Eigen:: Cast sparse matrix as, specifically, row order or col order
我有一个内部函数,
Eigen::SparseMatrix<double> & M;
if (M.IsRowMajor)
return my_func_template<Eigen::SparseMatrix<double,Eigen::RowMajor>&>(M,M.rows());
但是,这不会编译,因为编译器不相信 M
是一个 Eigen::SparseMatrix<double,Eigen::RowMajor>
。在 C++11 的类型安全环境中,我如何将我的引用具体转换为 Eigen::SparseMatrix<double,Eigen::RowMajor>
?
例如:
typedef Eigen::SparseMatrix<double> Smat;
typedef Eigen::SparseMatrix<double,Eigen::RowMajor> RMSmat;
typedef Eigen::SparseMatrix<double,Eigen::ColMajor> CMSmat;
enum direction { row, col};
template<class Mat>
vector<double> sum_along_inner(Mat &M){
vector<double> sums(M.innerSize(),0);
for(auto i = 0; i < M.outerSize(); i++){
for(typename M::InnerIterator it(M,i); it;++it){
sums[i] += it.value();
}
}
}
vector<double> sum_along_axis(Smat &M, direction dir){
// If I could solve this problem,
//
// I could also function off these if components,
// and re-use them for other order-dependent functions I write
// so that my top level functions are only about 2-4 lines long
if(dir == direction::row){
if(M.IsRowMajor)
return sum_along_inner<RMSmat>((my question) M);
//else
RMsmat Mrowmajor = M;
return sum_along_inner<RMSmat>(Mrowmajor);
}
else {
if(!M.IsRowMajor)
return sum_along_inner<CMSmat>(M);
// else
CMSmat Mcolmajor = M;
return sum_along_inner<CMSmat>((my_question) Mcolmajor);
}
}
如果我做的不只是 sum_along_axis
,那么代码在行数、可读性等方面的复杂性是需要的两倍 如果我能解决我要问的这个问题。
否则,我无法抽象循环,我必须对主要列和主要行重复它...因为我不能假设我不会从一个函数中调用 sum_along_axis
尚未将主要顺序从默认 Eigen::ColMajor
交换为 Eigen::RowMajor
...
此外,如果我在 mb 大小的稀疏矩阵的数量级上操作,这些矩阵的维度太笨重而无法以密集矩阵形式表示,我会注意到一个主要的减速(这违背了使用稀疏矩阵来表示的目的) begin with) 如果我不写 可组合 函数,这些函数是 order agnostic,并且仅在需要时才转换 major-order。
所以,除非我解决这个问题,否则我的行数 and/or 函数计数或多或少会开始组合。
正如我在第一条评论中所写,M.IsRowMajor
永远是错误的。这是因为 Eigen::SparseMatrix
总是有两个模板参数,其中第二个默认为 Eigen::ColMajor
如果你想写一个接受行主矩阵和列主矩阵的函数,你需要写这样的东西
template<int mode>
vector<double> sum_along_axis(Eigen::SparseMatrix<double,mode> const &M, direction dir)
if(dir == direction::row){
return sum_along_inner<RMSmat>(M); // implicit conversion if necessary
}
else {
return sum_along_inner<CMSmat>(M); // implicit conversion if necessary
}
}
您需要重写 sum_along_inner
以接受 const 引用以使隐式转换起作用:
template<class Mat>
vector<double> sum_along_inner(Mat const &M){
vector<double> sums(M.outerSize(),0); // sums needs to have size M.outerSize()
for(auto i = 0; i < M.outerSize(); i++){
for(typename M::InnerIterator it(M,i); it;++it){
sums[i] += it.value();
}
}
}
如果您想避免从行优先到列优先的转换(反之亦然),您应该编写一个沿外部维度求和的函数,并在您的主函数中决定调用哪个函数。
我有一个内部函数,
Eigen::SparseMatrix<double> & M;
if (M.IsRowMajor)
return my_func_template<Eigen::SparseMatrix<double,Eigen::RowMajor>&>(M,M.rows());
但是,这不会编译,因为编译器不相信 M
是一个 Eigen::SparseMatrix<double,Eigen::RowMajor>
。在 C++11 的类型安全环境中,我如何将我的引用具体转换为 Eigen::SparseMatrix<double,Eigen::RowMajor>
?
例如:
typedef Eigen::SparseMatrix<double> Smat;
typedef Eigen::SparseMatrix<double,Eigen::RowMajor> RMSmat;
typedef Eigen::SparseMatrix<double,Eigen::ColMajor> CMSmat;
enum direction { row, col};
template<class Mat>
vector<double> sum_along_inner(Mat &M){
vector<double> sums(M.innerSize(),0);
for(auto i = 0; i < M.outerSize(); i++){
for(typename M::InnerIterator it(M,i); it;++it){
sums[i] += it.value();
}
}
}
vector<double> sum_along_axis(Smat &M, direction dir){
// If I could solve this problem,
//
// I could also function off these if components,
// and re-use them for other order-dependent functions I write
// so that my top level functions are only about 2-4 lines long
if(dir == direction::row){
if(M.IsRowMajor)
return sum_along_inner<RMSmat>((my question) M);
//else
RMsmat Mrowmajor = M;
return sum_along_inner<RMSmat>(Mrowmajor);
}
else {
if(!M.IsRowMajor)
return sum_along_inner<CMSmat>(M);
// else
CMSmat Mcolmajor = M;
return sum_along_inner<CMSmat>((my_question) Mcolmajor);
}
}
如果我做的不只是 sum_along_axis
,那么代码在行数、可读性等方面的复杂性是需要的两倍 如果我能解决我要问的这个问题。
否则,我无法抽象循环,我必须对主要列和主要行重复它...因为我不能假设我不会从一个函数中调用 sum_along_axis
尚未将主要顺序从默认 Eigen::ColMajor
交换为 Eigen::RowMajor
...
此外,如果我在 mb 大小的稀疏矩阵的数量级上操作,这些矩阵的维度太笨重而无法以密集矩阵形式表示,我会注意到一个主要的减速(这违背了使用稀疏矩阵来表示的目的) begin with) 如果我不写 可组合 函数,这些函数是 order agnostic,并且仅在需要时才转换 major-order。
所以,除非我解决这个问题,否则我的行数 and/or 函数计数或多或少会开始组合。
正如我在第一条评论中所写,M.IsRowMajor
永远是错误的。这是因为 Eigen::SparseMatrix
总是有两个模板参数,其中第二个默认为 Eigen::ColMajor
如果你想写一个接受行主矩阵和列主矩阵的函数,你需要写这样的东西
template<int mode>
vector<double> sum_along_axis(Eigen::SparseMatrix<double,mode> const &M, direction dir)
if(dir == direction::row){
return sum_along_inner<RMSmat>(M); // implicit conversion if necessary
}
else {
return sum_along_inner<CMSmat>(M); // implicit conversion if necessary
}
}
您需要重写 sum_along_inner
以接受 const 引用以使隐式转换起作用:
template<class Mat>
vector<double> sum_along_inner(Mat const &M){
vector<double> sums(M.outerSize(),0); // sums needs to have size M.outerSize()
for(auto i = 0; i < M.outerSize(); i++){
for(typename M::InnerIterator it(M,i); it;++it){
sums[i] += it.value();
}
}
}
如果您想避免从行优先到列优先的转换(反之亦然),您应该编写一个沿外部维度求和的函数,并在您的主函数中决定调用哪个函数。