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

如果您想避免从行优先到列优先的转换(反之亦然),您应该编写一个沿外部维度求和的函数,并在您的主函数中决定调用哪个函数。