Stack Overflow на русском Asked by CodePenguin32 on February 12, 2021
Может быть, вопрос покажется глупым, а автор вопроса – ленивым простофилей, но имеются ли в С++ библиотеки для удобной работы с матрицами(умножение матриц прежде всего, дабы не изобретать свои корявые велосипеды,)
как например, NumPy в Pytnon?
Вопрос нормальный и не глупый(если возник вопрос, глупо только не искать ответ). В стандарте нет, но можете написать свой класс матрицы такой, какой вам удобно. Например такой класс:
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
Get help from others!
Recent Answers
Recent Questions
© 2024 TransWikia.com. All rights reserved. Sites we Love: PCI Database, UKBizDB, Menu Kuliner, Sharing RPP