TransWikia.com

Библиотеки С++ для удобной работы с матрицами

Stack Overflow на русском Asked by CodePenguin32 on February 12, 2021

Может быть, вопрос покажется глупым, а автор вопроса – ленивым простофилей, но имеются ли в С++ библиотеки для удобной работы с матрицами(умножение матриц прежде всего, дабы не изобретать свои корявые велосипеды,)
как например, NumPy в Pytnon?

One Answer

Вопрос нормальный и не глупый(если возник вопрос, глупо только не искать ответ). В стандарте нет, но можете написать свой класс матрицы такой, какой вам удобно. Например такой класс:

template < typename Tp>
class My_Matrix {
private:
    //тип указателья с проверкой диапазона для прохода по матрице как proxy type
    using PTR = typename stdext::checked_array_iterator<Tp*>;
protected:  
    using Rep = std::valarray<Tp>;
    size_t x, y;
    Rep v;
    
public:
    using value_type = Tp;          
    explicit My_Matrix(const size_t row, const size_t column, const Tp& val = Tp()) noexcept
        : x(row == 0 ? 1 : row), y(column == 0 ? 1 : column), v(Rep(val, x* y)) {}
    template < class In >
    My_Matrix& assign(In first, In last) noexcept
    {
        size_t i{};
        while (first != last && i != x * y) 
            v[i++] = *first++;      
        return *this;
    }   

    //выполнить некоторое действие с элементами
    My_Matrix& apply(const std::function<value_type()>& op)
    {
        std::generate(std::begin(v), std::end(v), op); 
        return *this;
    }
    My_Matrix& apply(value_type(*pf)(value_type))
    {
        v = v.apply(pf);
        return *this;
    }
    //циклический позиционный сдвиг элементов влево или вправо 
    My_Matrix& ciclic_shift(const int n) noexcept
    {
        v = v.cshift(n);
        return *this;
    }
    //транспонированная матрица
    [[nodiscard]] My_Matrix 
        transpose() noexcept
    {
        My_Matrix m(y, x);
        m.v[std::gslice(0, { x, y }, { 1, x })] = v;
        return m;
    }   
    
    //для получения элемента по индексу
    [[nodiscard]] PTR
        operator[](const size_t index)
    {
        return index >= x ? PTR{ std::begin(v), x * y, index * y }
        : PTR{ &v[index * y], y };
    }
    //некоторый срез матрицы(общий и одинарный)
    std::gslice_array<value_type>
        operator[](const std::gslice& g) { return v[g]; }
    std::slice_array<value_type>
        operator[](const std::slice& s) { return v[s]; }

    //для выполнения действий со строкой и столбцом
    std::slice_array<value_type>
        row(size_t index) noexcept
    {
        if (index >= x)
            index = x - 1;
        return operator[](std::slice(index* y, y, 1));
    }
    std::slice_array<value_type>
        column(size_t index) noexcept
    {
        if (index >= y)
            index = y - 1;
        return operator[](std::slice(index, x, y));
    }

    //получить строку и столбец в std::valarray
    [[nodiscard]] Rep
        get_row(const size_t index) const noexcept
    {
        return v[std::slice((index % x) * y, y, 1)];
    }
    [[nodiscard]] Rep
        get_column(const size_t col) const noexcept
    {
        return v[std::slice(col % y, x, y)];
    }

    //количество строк и столбцов
    [[nodiscard]] std::pair<size_t, size_t>
        size() const noexcept
    {
        return std::make_pair(x, y);
    }

    //умножение и сложение матриц
    [[nodiscard]] My_Matrix
        operator *(const My_Matrix& m) const
    {
        My_Matrix tm(x, m.y);
        if (y == m.x) {
            for (size_t i = 0; i < x; ++i)
                for (size_t j = 0; j < m.y; ++j) {
                    //умножение элементов строк на элементы столбцов
                    Rep t = get_row(i) * m.get_column(j);
                    //присвоить сумму произведений
                    tm.v[i * m.y + j] = t.sum();
                }
        }
        return tm;
    }
    void  operator +=(const My_Matrix& m)
    {
        if (size() == m.size())
            v += m.v;
        else
            std::cerr << "ntInappropriate matrix sizes for operation plus.nt"
            << "Matrix values have not changedn";
    }
    operator Rep() { return v; }

    friend std::ostream& operator <<(std::ostream& os, const My_Matrix& m)
    {
        for (size_t i = 0; i < m.v.size(); ++i) {
            if (!(i % m.y))
                os << 'n';
            os << std::fixed << std::setprecision(2)
                << std::setw(8) << std::left << m.v[i];
        }
        return os;
    }
};

Можете еще и добавить другие функциональности:

//матрица интегральных типов и типа, определенный как Extra_type
using Extra_type = std::string;

//class  Matrix extends My_Matrix
template < typename Tp>
class Matrix : public My_Matrix<Tp>{
    static_assert(std::is_arithmetic<Tp>()
        || std::is_base_of<Extra_type, Tp>(),
        "matrix element must have integral or base element type."); 
public:             
    explicit Matrix(const size_t row, const size_t column, const Tp& val = Tp()) noexcept
        : My_Matrix<Tp>(row, column, val) {}
     
    //std::gslice(старт, {количество строк, столбцов }, {шаг строк, шаг столбцов})
    //если количество и шаги заданы как std::valarray<size_t>(3),
    //то первые аргументы это количество таких матриц и шаги соответственно
    [[nodiscard]] Matrix
        subMatrix(const std::gslice& g) const noexcept
    {
        //размер массива количеств
        const std::valarray<size_t> vs = g.size();
        const size_t sz = vs.size(),
            first = (sz == 2) ? 1 : vs[0];
        Matrix t(first * vs[sz - 2], vs[sz - 1]);
        t.v = (this->v)[g];
        return t;
    }   
};

Осталось только подключать подходящие файлы и делать почти любую операцию с матрицами, легко и очень быстро:

const size_t rc = 5;
Matrix<char> m(rc, rc, 'a');
// a ... y
m.apply(([]() { static int k = 0; return 'a' + k++; }));
cout << m << 'n'
    /*первая строка  будет последней */
    << m.ciclic_shift(rc) << 'n'
    /*выведим транспонированную матрицу*/
    << m.transpose() << 'n'
    /*Берем  субматрицу 2 * 3, стартовый элемент под интексом 2,
      шаг столбцов 2,  шагом 1 от старта  вторая строка */
    << m.subMatrix({ 2, {2, 3}, {1, 2} }) << 'n';
///вторую строку заменим  значениями второго столбца
m.row(1) = m.get_column(1); 
cout << m;
// выведим  некий элемент
cout << m[1][1];
//присвоим значение элементам через один(шаг 2, 5 штук)
 m[{0, 5, 2}] = '+';
//и т.д. и т.п.

Answered by AR Hovsepyan on February 12, 2021

Add your own answers!

Ask a Question

Get help from others!

© 2024 TransWikia.com. All rights reserved. Sites we Love: PCI Database, UKBizDB, Menu Kuliner, Sharing RPP