Eigen :: Cast稀疏矩阵,特别是行顺序或col顺序

时间:2018-05-24 20:52:17

标签: c++ c++11 casting eigen

我有一个内部函数,

Eigen::SparseMatrix<double> & M;

if (M.IsRowMajor)
     return my_func_template<Eigen::SparseMatrix<double,Eigen::RowMajor>&>(M,M.rows());

但是,这不会编译,因为编译器不相信MEigen::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大小的稀疏矩阵的顺序操作,其尺寸太难以表示密集矩阵形式,我将注意到一个主要的减速(这使得使用稀疏矩阵的目的开始于)如果我不编写可组合功能顺序不可知,并仅在需要时转换主顺序。

所以,除非我解决这个问题,否则我的行数和/或函数数量或多或少会开始变为组合。

1 个答案:

答案 0 :(得分:0)

正如我在第一篇评论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();
        }
    }
}

如果你想避免从行到列的转换(反之亦然),你应该写一个函数,它与外部维度相加,并在你的主函数中决定调用哪个函数。