Работа с плотными и разреженными матрицами - PullRequest
0 голосов
/ 01 июня 2018

Я пишу функцию C ++, которая работает с матрицей, передается в качестве аргумента и хотела бы, чтобы код работал с различными типами матриц (например, Boost разреженных матриц, std :: vectors of std :: vectors).Мой текущий подход состоит в том, чтобы определить перегруженные методы для базовых манипуляций с различными типами матриц, предоставить единый интерфейс для различных типов матриц и определить мою функцию как функцию шаблона, которая использует только эти перегруженные методы

#include <boost/numeric/ublas/matrix_sparse.hpp>
#include <iostream>

typedef std::vector<double> vec;
typedef std::vector<vec> mat;
typedef boost::numeric::ublas::compressed_matrix<double, boost::numeric::ublas::row_major> spmat;

namespace matrix
{
    inline void set(spmat & input, u_int i, u_int j, double val)
    {
        input(i, j) = val;
    }

    inline void set(mat & input, u_int i, u_int j, double val)
    {
        input[i][j] = val;
    }

    inline u_int size1(const mat & input)
    {
        return input.size();
    }

    inline u_int size2(const mat & input)
    {
        return input[0].size();
    }

    inline u_int size1(const spmat & input)
    {
        return input.size1();
    }

    inline u_int size2(const spmat & input)
    {
        return input.size2();
    }

    inline double get(const spmat & input, u_int i, u_int j)
    {
        return input(i, j);
    }

    inline double get(const mat & input, u_int i, u_int j)
    {
        return input[i][j];
    }
}

Для простых задач этот подход, похоже, работает.В настоящее время, однако, я пытаюсь написать функцию, которая должна перебирать все записи, в случае плотной матрицы, или только ненулевые записи, в случае разреженной матрицы.Я знаю, как сделать это для каждого случая индивидуально, но хотел бы иметь только одну реализацию, которая работает в обоих случаях.Каков был бы стандартный способ достижения этого?

1 Ответ

0 голосов
/ 01 июня 2018

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

template<class Func>
void forMatrixEntries(const VecOfVecMatrix& mat, Func&& func)
{
    for (auto& row : mat.getData())
        for (auto& elem : row)
            func(elem); // You could track and pass the indices if you want.
}

template<class Func>
void forMatrixEntries(const CompressedSparseMatrix& mat, Func&& func)
{
    for (auto& elem : mat.getElements())
        func(elem); // You could track and pass the indices if you want.
}

(Это моглотак же как и функции-члены, чтобы они могли легче получать доступ к внутренним объектам - ваш выбор).Затем вы можете использовать их унифицированным способом:

template<class Mat>
void scale(const Mat& mat, double factor)
{
    forMatrixEntries(mat, [factor](double& elem) {
        elem *= factor;
    });
}

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...