Eigen :: Cast разреженная матрица, в частности, порядок строк или столбцов - PullRequest
0 голосов
/ 24 мая 2018

У меня есть внутренняя функция,

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>.Как преобразовать мою ссылку как, в частности, Eigen::SparseMatrix<double,Eigen::RowMajor>, в безопасную для типов среду C ++ 11?


Например:

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 из функции, которая не имеетt уже поменял мажорный порядок со значения по умолчанию Eigen::ColMajor на Eigen::RowMajor ...

Кроме того, если я работаю в порядке разреженных матриц размера mb с размерами, слишком громоздкими для представления в плотной матрицеформа, я собираюсь заметить значительное замедление (которое побуждает цель использовать разреженную матрицу для начала), если я не пишу компонуемые функции, которые не зависят от порядка , ипереход на мажорный порядок только при необходимости.

Итак, если я не решу для этого, мой счетчик строк и / или счетчик функций, более или менее, начнет идти комбинаторно.

1 Ответ

0 голосов
/ 27 мая 2018

Как я уже писал в своем первом комментарии, 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, чтобы принять константную ссылку, чтобы заставить работать неявное преобразование:

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

Если вы хотите избежать преобразования из строки в столбец -Major (и наоборот) вы должны написать функцию, которая суммирует по внешнему измерению и решить в вашей основной функции, какую функцию вызывать.

...