Files
pip/libs/main/math/pimathmatrix.h
2025-02-27 21:26:29 +03:00

1636 lines
69 KiB
C++
Raw Permalink Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
//! \file pimathmatrix.h
//! \ingroup Math
//! \~\brief
//! \~english Math matrix
//! \~russian Математическая матрица
/*
PIP - Platform Independent Primitives
PIMathMatrix
Ivan Pelipenko peri4ko@yandex.ru, Andrey Bychkov work.a.b@yandex.ru
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef PIMATHMATRIX_H
#define PIMATHMATRIX_H
#include "pimathcomplex.h"
#include "pimathvector.h"
/// Matrix templated
#define PIMM_FOR \
for (uint r = 0; r < Rows; ++r) \
for (uint c = 0; c < Cols; ++c)
#define PIMM_FOR_C for (uint i = 0; i < Cols; ++i)
#define PIMM_FOR_R for (uint i = 0; i < Rows; ++i)
#pragma pack(push, 1)
//! \~english
//! \brief A class for fixed size and type matrix.
//! \tparam `Rows` rows number of matrix.
//! \tparam `Сols` columns number of matrix.
//! \tparam `Type` is the data type of the matrix. There are can be basic C++ language data and different classes where the arithmetic
//! operators(=, +=, -=, *=, /=, ==, !=, +, -, *, /)
//! of the C++ language are implemented
//! \~russian
//! \brief Класс для работы с матрицами фиксированного размера и типа данных.
//! \details В отличие от \a PIMathMatrix не занимается динамическим выделением памяти и связанными с этим операциями.
//! То есть он тривиально копируемый.
//! Содержит проверки времени компиляции на несоответствие размера при различных математических операциях,
//! что позволяет заранее выявлять ошибки.
//! \tparam `Rows` количество строк матрицы.
//! \tparam `Сols` количество столбцов матрицы.
//! \tparam `Type`тип данных матрицы. Здесь можеть быть базовый тип данных C++ или различные классы,
//! где реализованы арифметические операторы(=, +=, -=, *=, /=, ==, !=, +, -, *, /) языка C++.
template<uint Rows, uint Cols = Rows, typename Type = double>
class PIP_EXPORT PIMathMatrixT {
typedef PIMathMatrixT<Rows, Cols, Type> _CMatrix;
typedef PIMathMatrixT<Cols, Rows, Type> _CMatrixI;
typedef PIMathVectorT<Rows, Type> _CMCol;
typedef PIMathVectorT<Cols, Type> _CMRow;
static_assert(std::is_arithmetic<Type>::value || is_complex<Type>::value, "Type must be arithmetic or complex");
static_assert(Rows > 0, "Row count must be > 0");
static_assert(Cols > 0, "Column count must be > 0");
public:
//! \~english
//! \brief Constructs \a PIMathMatrixT that is filled by \a new_value.
//! \~russian
//! \brief Создает \a PIMathMatrixT и заполняет её из \a new_value.
PIMathMatrixT(const Type & new_value = Type()) { PIMM_FOR m[r][c] = new_value; }
//! \~english
//! \brief Contructs \a PIMathMatrixT from \a PIVector.
//! \~russian
//! \brief Создает \a PIMathMatrixT и заполняет её из \a PIVector.
PIMathMatrixT(const PIVector<Type> & val) {
assert(Rows * Cols == val.size());
int i = 0;
PIMM_FOR m[r][c] = val[i++];
}
//! \~english
//! \brief Contructs \a PIMathMatrixT from [C++11 initializer list](https://en.cppreference.com/w/cpp/utility/initializer_list).
//! \~russian
//! \brief Создает \a PIMathMatrixT и заполняет её из [списка инициализации
//! C++11](https://ru.cppreference.com/w/cpp/utility/initializer_list).
PIMathMatrixT(std::initializer_list<Type> init_list) {
assert(Rows * Cols == init_list.size());
int i = 0;
PIMM_FOR m[r][c] = init_list.begin()[i++];
}
//! \~english
//! \brief Сreates a matrix whose main diagonal is filled with ones and the remaining elements are zeros.
//! \return identity matrix of type \a PIMathMatrixT.
//! \~russian
//! \brief Создает матрицу, главная диагональ которой заполнена единицами, а остальные элементы — нулями.
//! \return единичная матрица типа \a PIMathMatrixT.
static PIMathMatrixT<Rows, Cols, Type> identity() {
PIMathMatrixT<Rows, Cols, Type> tm = PIMathMatrixT<Rows, Cols, Type>();
PIMM_FOR tm.m[r][c] = (c == r ? Type(1) : Type(0));
return tm;
}
//! \~english
//! \brief Method which returns number of columns in matrix.
//! \return type \a uint shows number of columns.
//! \~russian
//! \brief Метод возвращающий количество столбцов в матрице.
//! \return \a uint количество столбцов.
constexpr uint cols() const { return Cols; }
//! \~english
//! \brief Method which returns number of rows in matrix.
//! \return type uint shows number of rows.
//! \~russian
//! \brief Метод возвращающий количество строк в матрице.
//! \return \a uint количество строк.
constexpr uint rows() const { return Rows; }
//! \~english
//! \brief Method which returns the selected column in PIMathVectorT format.
//! \details If you enter an index out of the border of the matrix there will be "undefined behavior".
//! \param index is the number of the selected column.
//! \return column in PIMathVectorT format.
//! \~russian
//! \brief Метод возвращающий выбранную строку в формате \a PIMathVectorT.
//! \details Если вы введете индекс вне границ матрицы, то поведение не определено ("undefined behavior").
//! \param index номер выбранного столбца.
//! \return столбец в формате \a PIMathVectorT.
PIMathVectorT<Rows, Type> col(uint index) {
PIMathVectorT<Rows, Type> tv;
PIMM_FOR_R tv[i] = m[i][index];
return tv;
}
//! \brief Method which returns the selected row in PIMathVectorT format.
//! \details If you enter an index out of the border of the matrix there will be "undefined behavior".
//! \param index is the number of the selected row.
//! \return row in PIMathVectorT format.
//! \~russian
//! \brief Метод возвращающий выбранный столбец в формате \a PIMathVectorT.
//! \details Если вы введете индекс вне границ матрицы, то поведение не определено ("undefined behavior").
//! \param index номер выбранной строки.
//! \return строка в формате \a PIMathVectorT.
PIMathVectorT<Cols, Type> row(uint index) {
PIMathVectorT<Cols, Type> tv;
PIMM_FOR_C tv[i] = m[index][i];
return tv;
}
//! \~english
//! \brief Set the selected column in matrix.
//! \details If you enter an index out of the border of the matrix there will be "undefined behavior".
//! \param index is the number of the selected column.
//! \param v is a vector of the type \a PIMathVectorT<Rows, Type> that needs to fill the column.
//! \return matrix type \a PIMathMatrixT<Rows, Cols, Type>.
//! \~russian
//! \brief Определить выбранный столбец матрицы.
//! \details Если вы введете индекс вне границ матрицы, то поведение не определено ("undefined behavior").
//! \param index номер выбранного столбца.
//! \param v вектор типа \a PIMathVectorT<Rows, Type>, которым необходимо заполнить столбец.
//! \return матрица типа \a PIMathMatrixT<Rows, Cols, Type>.
PIMathMatrixT<Rows, Cols, Type> & setCol(uint index, const PIMathVectorT<Rows, Type> & v) {
PIMM_FOR_R m[i][index] = v[i];
return *this;
}
//! \~english
//! \brief Set the selected row in matrix.
//! \details If you enter an index out of the border of the matrix there will be "undefined behavior".
//! \param index is the number of the selected row.
//! \param v is a vector of the type PIMathVectorT<Cols, Type> that needs to fill the row.
//! \return matrix type PIMathMatrixT<Rows, Cols, Type>
//! \~russian
//! \brief Определить выбранную строку матрицы.
//! \details Если вы введете индекс вне границ матрицы, то поведение не определено ("undefined behavior").
//! \param index номер выбранной строки.
//! \param v вектор типа \a PIMathVectorT<Cols, Type>, которым необходимо заполнить строку.
//! \return матрица типа \a PIMathMatrixT<Rows, Cols, Type>.
PIMathMatrixT<Rows, Cols, Type> & setRow(uint index, const PIMathVectorT<Cols, Type> & v) {
PIMM_FOR_C m[index][i] = v[i];
return *this;
}
//! \~english
//! \brief Method which swaps the selected rows in a matrix.
//! \details If you enter an index out of the border of the matrix there will be "undefined behavior"
//! \param rf is the number of the first selected row
//! \param rs is the number of the second selected row
//! \return matrix type \a PIMathMatrixT<Rows, Cols, Type>
//! \~russian
//! \brief Метод, меняющий местами выбранные строки в матрице.
//! \details Если вы введете индекс вне границ матрицы, то поведение не определено ("undefined behavior").
//! \param rf номер первой выбранной строки.
//! \param rs номер второй выбранной строки.
//! \return матрица типа \a PIMathMatrixT<Rows, Cols, Type>.
PIMathMatrixT<Rows, Cols, Type> & swapRows(uint rf, uint rs) {
PIMM_FOR_C piSwap<Type>(m[rf][i], m[rs][i]);
return *this;
}
//! \~english
//! \brief Method which swaps the selected columns in a matrix.
//! \details If you enter an index out of the border of the matrix there will be "undefined behavior"
//! \param cf is the number of the first selected column
//! \param cs is the number of the second selected column
//! \return matrix type \a PIMathMatrixT<Rows, Cols, Type>
//! \~russian
//! \brief Метод, меняющий местами выбранные столбцы в матрице.
//! \details Если вы введете индекс вне границ матрицы, то поведение не определено ("undefined behavior").
//! \param rf номер первого выбранного столбца.
//! \param rs номер второго выбранного столбца.
//! \return матрица типа \a PIMathMatrixT<Rows, Cols, Type>.
PIMathMatrixT<Rows, Cols, Type> & swapCols(uint cf, uint cs) {
PIMM_FOR_R piSwap<Type>(m[i][cf], m[i][cs]);
return *this;
}
//! \~english
//! \brief Method which fills the matrix with selected value.
//! \param v is a parameter the type and value of which is selected and later filled into the matrix.
//! \return filled matrix type \a PIMathMatrixT<Rows, Cols, Type>.
//! \~russian
//! \brief Метод, заполняющий матрицу выбранным значением.
//! \param v параметр тип и значения, которого выбираются и заносятся в матрицу.
//! \return заполненная матрица типа \a PIMathMatrixT<Rows, Cols, Type>.
PIMathMatrixT<Rows, Cols, Type> & fill(const Type & v) {
PIMM_FOR m[r][c] = v;
return *this;
}
//! \~english
//! \brief Method which checks if matrix is square.
//! \return true if matrix is square, else false.
//! \~russian
//! \brief Метод, проверяющий является ли матрицей квадратной.
//! \return true если матрица квадратная, иначе false.
constexpr bool isSquare() const { return Rows == Cols; }
//! \~english
//! \brief Method which checks if main diagonal of matrix consists of ones and another elements are zeros.
//! \return true if matrix is identitied, else false.
//! \~russian
//! \brief Метод, проверяющий содержит ли главная диагональ единицы и все остальные поля нули.
//! \return true если матрица единичная, иначе false.
bool isIdentity() const {
PIMM_FOR if ((c == r) ? m[r][c] != Type(1) : m[r][c] != Type(0)) return false;
return true;
}
//! \~english
//! \brief Method which checks if every elements of matrix are zeros.
//! \return true if matrix is null, else false.
//! \~russian
//! \brief Метод, являются ли все элементы матрицы нулями.
//! \return true если матрица нулевая, иначе false.
bool isNull() const {
PIMM_FOR if (m[r][c] != Type(0)) return false;
return true;
}
//! \~english
//! \brief Read-only access to element by `row` number and `col` number.
//! \details If you enter an index out of the border of the matrix there will be "undefined behavior".
//! \param row matrix row number.
//! \param col matrix column number.
//! \return copy of element of matrix.
//! \~russian
//! \brief Доступ только для чтения к элементу по номеру \a строки `row` и номеру \a столбца `col`.
//! \details Если вы введете индекс вне границ матрицы, то поведение не определено ("undefined behavior").
//! \param row номер строки матрицы.
//! \param col номер столбца матрицы.
//! \return копия элемента матрицы.
Type at(uint row, uint col) const { return m[row][col]; }
//! \~english
//! \brief Full access to element by `row` number and `col` number.
//! \details If you enter an index out of the border of the matrix there will be "undefined behavior"
//! \param row matrix row number.
//! \param col matrix column number.
//! \return element of matrix
//! \~russian
//! \brief Полный доступ к элементу по номеру \a строки `row` и номеру \a столбца `col`.
//! \details Если вы введете индекс вне границ матрицы, то поведение не определено ("undefined behavior").
//! \param row номер строки матрицы.
//! \param col номер столбца матрицы.
//! \return элемент матрицы.
inline Type & element(uint row, uint col) { return m[row][col]; }
//! \~english
//! \brief Read-only access to element by `row` number and `col` number.
//! \details If you enter an index out of the border of the matrix there will be "undefined behavior".
//! \param row matrix row number.
//! \param col matrix column number.
//! \return copy of element of matrix.
//! \~russian
//! \brief Доступ только для чтения к элементу по номеру \a строки `row` и номеру \a столбца `col`.
//! \details Если вы введете индекс вне границ матрицы, то поведение не определено ("undefined behavior").
//! \param row номер строки матрицы.
//! \param col номер столбца матрицы.
//! \return копия элемента матрицы.
inline const Type & element(uint row, uint col) const { return m[row][col]; }
//! \~english
//! \brief Full access to the matrix row pointer.
//! \details If you enter an index out of the border of the matrix there will be "undefined behavior".
//! \param row matrix row number.
//! \return matrix row pointer
//! \~russian
//! \brief Полный доступ к указателю на строку матрицы.
//! \details Если вы введете индекс вне границ матрицы, то поведение не определено ("undefined behavior").
//! \param row номер строки матрицы.
//! \return указатель на строку матрицы.
Type * operator[](uint row) { return m[row]; }
//! \~english
//! \brief Read-only access to the matrix row pointer.
//! \details If you enter an index out of the border of the matrix there will be "undefined behavior".
//! \param row matrix row number.
//! \return matrix row pointer
//! \~russian
//! \brief Доступ только для чтения к указателю на строку матрицы.
//! \details Если вы введете индекс вне границ матрицы, то поведение не определено ("undefined behavior").
//! \param row номер строки матрицы.
//! \return указатель на строку матрицы.
const Type * operator[](uint row) const { return m[row]; }
//! \~english
//! \brief Matrix compare.
//! \param sm matrix for compare.
//! \return if matrices are equal true, else false.
//! \~russian
//! \brief Сравнение матриц.
//! \param sm матрица для сравнения.
//! \return если матрицы равны true, иначе false.
bool operator==(const PIMathMatrixT<Rows, Cols, Type> & sm) const {
PIMM_FOR if (m[r][c] != sm.m[r][c]) return false;
return true;
}
//! \~english
//! \brief Matrix negative compare.
//! \param sm matrix for compare.
//! \return if matrices are not equal true, else false.
//! \~russian
//! \brief Отрицательное сравнение матриц.
//! \param sm матрица для сравнения.
//! \return если матрицы не равны true, иначе false.
bool operator!=(const PIMathMatrixT<Rows, Cols, Type> & sm) const { return !(*this == sm); }
//! \~english
//! \brief Addition assignment with matrix `sm`.
//! \param sm matrix for the addition assigment.
//! \~russian
//! \brief Сложение с присваиванием с матрицей `sm`.
//! \param sm матрица для сложения с присваиванием.
void operator+=(const PIMathMatrixT<Rows, Cols, Type> & sm) { PIMM_FOR m[r][c] += sm.m[r][c]; }
//! \~english
//! \brief Subtraction assignment with matrix `sm`.
//! \param sm matrix for the subtraction assigment.
//! \~russian
//! \brief Вычитание с присваиванием с матрицей `sm`.
//! \param sm матрица для вычитания с присваиванием.
void operator-=(const PIMathMatrixT<Rows, Cols, Type> & sm) { PIMM_FOR m[r][c] -= sm.m[r][c]; }
//! \~english
//! \brief Multiplication assignment with value `v`.
//! \param v value for the multiplication assigment.
//! \~russian
//! \brief Умножение с присваиванием с матрицей `v`.
//! \param sm матрица для умножения с присваиванием.
void operator*=(const Type & v) { PIMM_FOR m[r][c] *= v; }
//! \~english
//! \brief Division assignment with value `v`.
//! \param v value for the division assigment.
//! \~russian
//! \brief Деление с присваиванием с матрицей `v`.
//! \param sm матрица для деления с присваиванием.
void operator/=(const Type & v) {
assert(std::abs(v) > PIMATHVECTOR_ZERO_CMP);
PIMM_FOR m[r][c] /= v;
}
//! \~english
//! \brief Negation operation
//! \return copy of the negative matrix
//! \~russian
//! \brief Операция отрицания
//! \return копия отрицательной матрицы
PIMathMatrixT<Rows, Cols, Type> operator-() const {
PIMathMatrixT<Rows, Cols, Type> tm;
PIMM_FOR tm.m[r][c] = -m[r][c];
return tm;
}
//! \~english
//! \brief Matrix addition.
//! \param sm is matrix term.
//! \return the result of matrix addition.
//! \~russian
//! \brief Матричное сложение.
//! \param sm матричное слагаемое.
//! \return результат матричного сложения.
PIMathMatrixT<Rows, Cols, Type> operator+(const PIMathMatrixT<Rows, Cols, Type> & sm) const {
PIMathMatrixT<Rows, Cols, Type> tm = PIMathMatrixT<Rows, Cols, Type>(*this);
PIMM_FOR tm.m[r][c] += sm.m[r][c];
return tm;
}
//! \~english
//! \brief Matrix substraction.
//! \param sm is matrix subtrahend.
//! \return the result of matrix substraction.
//! \~russian
//! \brief Матричная разность.
//! \param sm матричное вычитаемое.
//! \return результат матричной разности.
PIMathMatrixT<Rows, Cols, Type> operator-(const PIMathMatrixT<Rows, Cols, Type> & sm) const {
PIMathMatrixT<Rows, Cols, Type> tm = PIMathMatrixT<Rows, Cols, Type>(*this);
PIMM_FOR tm.m[r][c] -= sm.m[r][c];
return tm;
}
//! \~english
//! \brief Matrix multiplication by a constant.
//! \param v is value factor.
//! \return the result of matrix multiplication.
//! \~russian
//! \brief Умножение матрицы на константу.
//! \param v множитель.
//! \return результат произведения.
PIMathMatrixT<Rows, Cols, Type> operator*(const Type & v) const {
PIMathMatrixT<Rows, Cols, Type> tm = PIMathMatrixT<Rows, Cols, Type>(*this);
PIMM_FOR tm.m[r][c] *= v;
return tm;
}
//! \~english
//! \brief Division a matrix by a constant.
//! \param v is value divider.
//! \return the result of matrix division.
//! \~russian
//! \brief Деление матрицы на константу.
//! \param v делитель.
//! \return результат деления.
PIMathMatrixT<Rows, Cols, Type> operator/(const Type & v) const {
assert(std::abs(v) > PIMATHVECTOR_ZERO_CMP);
PIMathMatrixT<Rows, Cols, Type> tm = PIMathMatrixT<Rows, Cols, Type>(*this);
PIMM_FOR tm.m[r][c] /= v;
return tm;
}
//! \~english
//! \brief Calculate Determinant of the matrix.
//! \details Works only with square matrix, nonzero matrices and invertible matrix.
//! \param ok is a parameter with which we can find out if the method worked correctly.
//! \return matrix determinant.
//! \~russian
//! \brief Вычислить определитель матрицы.
//! \details Работает только с квадратными, ненулевыми и обратимыми матрицами.
//! \param ok это параметр, с помощью которого мы можем узнать, правильно ли сработал метод.
//! \return опеределитель матрицы.
Type determinant(bool * ok = 0) const {
PIMathMatrixT<Rows, Cols, Type> m(*this);
bool k;
Type ret = Type(0);
m.toUpperTriangular(&k);
if (ok) *ok = k;
if (!k) return ret;
ret = Type(1);
PIMM_FOR if (r == c) ret *= m[r][c];
return ret;
}
//! \~english
//! \brief Calculate the trace of a matrix.
//! \details Works only with square matrix.
//! \return matrix trace.
//! \~russian
//! \brief Вычислить след матрицы.
//! \details Работает только с квадратными матрицами.
//! \return след матрицы.
Type trace() const {
static_assert(Rows == Cols, "Works only with square matrix");
Type ret = Type(0);
for (uint i = 0; i < Cols; ++i) {
ret += m[i][i];
}
return ret;
}
//! \~english
//! \brief Transforming matrix to upper triangular.
//! \details Works only with square matrix, nonzero matrices and invertible matrix.
//! \param ok is a parameter with which we can find out if the method worked correctly.
//! \return a transformed upper triangular matrix.
//! \~russian
//! \brief Преобразование матрицы в верхнетреугольную.
//! \details Работает только с квадратными, ненулевыми и обратимыми матрицами.
//! \param ok это параметр, с помощью которого мы можем узнать, правильно ли сработал метод.
//! \return преобразованная верхнетреугольная матрицы.
PIMathMatrixT<Rows, Cols, Type> & toUpperTriangular(bool * ok = 0) {
static_assert(Rows == Cols, "Works only with square matrix");
PIMathMatrixT<Rows, Cols, Type> smat(*this);
bool ndet;
uint crow;
Type mul;
for (uint i = 0; i < Cols; ++i) {
ndet = true;
for (uint j = 0; j < Rows; ++j)
if (smat.m[i][j] != Type{}) ndet = false;
if (ndet) {
if (ok != 0) *ok = false;
return *this;
}
}
for (uint i = 0; i < Cols; ++i) {
crow = i;
while (smat.m[i][i] == Type{}) {
smat.swapRows(i, ++crow);
}
for (uint j = i + 1; j < Rows; ++j) {
mul = smat.m[i][j] / smat.m[i][i];
for (uint k = i; k < Cols; ++k)
smat.m[k][j] -= mul * smat.m[k][i];
}
if (i < Cols - 1) {
if (std::abs(smat.m[i + 1][i + 1]) < PIMATHVECTOR_ZERO_CMP) {
if (ok != 0) *ok = false;
return *this;
}
}
}
if (ok != 0) *ok = true;
memcpy(m, smat.m, sizeof(Type) * Cols * Rows);
return *this;
}
//! \~english
//! \brief Matrix inversion operation.
//! \details Works only with square matrix, nonzero matrices and invertible matrix.
//! \param ok is a parameter with which we can find out if the method worked correctly.
//! \return inverted matrix.
//! \~russian
//! \brief Операция обращения матрицы.
//! \details Работает только с квадратными, ненулевыми и обратимыми матрицами.
//! \param ok это параметр, с помощью которого мы можем узнать, правильно ли сработал метод.
//! \return обратная матрица.
PIMathMatrixT<Rows, Cols, Type> & invert(bool * ok = 0) {
static_assert(Rows == Cols, "Works only with square matrix");
PIMathMatrixT<Rows, Cols, Type> mtmp = PIMathMatrixT<Rows, Cols, Type>::identity(), smat(*this);
bool ndet;
uint crow;
Type mul, iddiv;
for (uint i = 0; i < Cols; ++i) {
ndet = true;
for (uint j = 0; j < Rows; ++j) {
if (std::abs(smat.m[i][j]) >= PIMATHVECTOR_ZERO_CMP) ndet = false;
}
if (ndet) {
if (ok != 0) *ok = false;
return *this;
}
}
for (uint i = 0; i < Cols; ++i) {
crow = i;
while (std::abs(smat.m[i][i]) < PIMATHVECTOR_ZERO_CMP) {
++crow;
smat.swapRows(i, crow);
mtmp.swapRows(i, crow);
}
for (uint j = i + 1; j < Rows; ++j) {
mul = smat.m[i][j] / smat.m[i][i];
for (uint k = i; k < Cols; ++k)
smat.m[k][j] -= mul * smat.m[k][i];
for (uint k = 0; k < Cols; ++k)
mtmp.m[k][j] -= mul * mtmp.m[k][i];
}
if (i < Cols - 1) {
if (std::abs(smat.m[i + 1][i + 1]) < PIMATHVECTOR_ZERO_CMP) {
if (ok != 0) *ok = false;
return *this;
}
}
iddiv = smat.m[i][i];
for (uint j = i; j < Cols; ++j)
smat.m[j][i] /= iddiv;
for (uint j = 0; j < Cols; ++j)
mtmp.m[j][i] /= iddiv;
}
for (uint i = Cols - 1; i > 0; --i) {
for (uint j = 0; j < i; ++j) {
mul = smat.m[i][j];
smat.m[i][j] -= mul;
for (uint k = 0; k < Cols; ++k)
mtmp.m[k][j] -= mtmp.m[k][i] * mul;
}
}
if (ok != 0) *ok = true;
memcpy(m, mtmp.m, sizeof(Type) * Cols * Rows);
return *this;
}
//! \~english
//! \brief Matrix inversion operation.
//! \details Works only with square matrix, nonzero matrices and invertible matrix.
//! \param ok is a parameter with which we can find out if the method worked correctly.
//! \return copy of inverted matrix.
//! \~russian
//! \brief Операция обращения матрицы.
//! \details Работает только с квадратными, ненулевыми и обратимыми матрицами.
//! \param ok это параметр, с помощью которого мы можем узнать, правильно ли сработал метод.
//! \return копия обратной матрицы.
PIMathMatrixT<Rows, Cols, Type> inverted(bool * ok = 0) const {
PIMathMatrixT<Rows, Cols, Type> tm(*this);
tm.invert(ok);
return tm;
}
//! \~english
//! \brief Matrix transposition operation.
//! \details Works only with square matrix.
//! \return copy of transposed matrix
//! \~russian
//! \brief Транспонирование матрицы.
//! \details Работает только с квадратными матрицами.
//! \return Копия транспонированной матрицы.
PIMathMatrixT<Cols, Rows, Type> transposed() const {
PIMathMatrixT<Cols, Rows, Type> tm;
PIMM_FOR tm[c][r] = m[r][c];
return tm;
}
//! \~english
//! \brief Matrix rotation operation.
//! \details Works only with 2x2 matrix.
//! \return rotated matrix.
//! \~russian
//! \brief Операция поворота матрицы.
//! \details Работает только с матрицами 2x2.
//! \return Эта повернутая матрица.
PIMathMatrixT<Rows, Cols, Type> & rotate(Type angle) {
static_assert(Rows == 2 && Cols == 2, "Works only with 2x2 matrix");
Type c = std::cos(angle);
Type s = std::sin(angle);
PIMathMatrixT<2u, 2u, Type> tm;
tm[0][0] = tm[1][1] = c;
tm[0][1] = -s;
tm[1][0] = s;
*this = *this * tm;
return *this;
}
//! \~english
//! \brief Matrix rotation operation.
//! \details Works only with 2x2 matrix.
//! \return copy of rotated matrix.
//! \~russian
//! \brief Операция поворота матрицы.
//! \details Работает только с матрицами 2x2.
//! \return Копия повернутой матрицы.
PIMathMatrixT<Rows, Cols, Type> rotated(Type angle) {
static_assert(Rows == 2 && Cols == 2, "Works only with 2x2 matrix");
PIMathMatrixT<Cols, Rows, Type> outm;
Type c = std::cos(angle);
Type s = std::sin(angle);
PIMathMatrixT<2u, 2u, Type> tm;
tm[0][0] = tm[1][1] = c;
tm[0][1] = -s;
tm[1][0] = s;
outm = outm * tm;
return outm;
}
//! \~english
//! \brief Returns this matrix with another element type.
//! \~russian
//! \brief Возвращает эту матрицу с другим типом элементов.
template<typename T>
PIMathMatrixT<Rows, Cols, T> toType() const {
PIMathMatrixT<Cols, Rows, T> ret;
PIMM_FOR ret[r][c] = element(r, c);
return ret;
}
//! \~english
//! \brief Returns the submatrix with size SubRows x SubCols. Elements takes from coordinates "row_offset" and "col_offset".
//! \details
//! \~russian
//! \brief Возвращает подматрицу с размерами SubRows x SubCols. Элементы берутся с координат "row_offset" и "col_offset".
//! \details Координаты могут быть отрицательными. Возвращаемая матрица может быть любого размера. Если исходные элементы выходят
//! за границы исходной матрицы, то в подматрице будут нули.
template<uint SubRows, uint SubCols = SubRows>
PIMathMatrixT<SubRows, SubCols, Type> submatrix(int row_offset = 0, int col_offset = 0) const {
PIMathMatrixT<SubRows, SubCols, Type> ret;
for (int r = 0; r < (int)SubRows; ++r) {
int sr = r + row_offset;
if (sr < 0 || sr >= (int)Rows) continue;
for (int c = 0; c < (int)SubCols; ++c) {
int sc = c + col_offset;
if (sc < 0 || sc >= (int)Cols) continue;
ret.element(r, c) = element(sr, sc);
}
}
return ret;
}
//! \~english
//! \brief Set the submatrix "m" in coordinates "row_index" and "col_index".
//! \details
//! \~russian
//! \brief Устанавливает подматрицу "m" в координаты "row_index" и "col_index".
//! \details Присваивает значения из матрицы "m" в прямоугольную область текущией матрицы, ограниченную
//! размерами "m", самой матрицы и границами, исходя из координат установки. Координаты могут быть отрицательными.
//! Матрица "m" может быть любого размера. Возвращает ссылку на эту матрицу.
template<uint SubRows, uint SubCols = SubRows>
PIMathMatrixT<Rows, Cols, Type> & setSubmatrix(int row_index, int col_index, const PIMathMatrixT<SubRows, SubCols, Type> & m) {
for (int r = 0; r < (int)SubRows; ++r) {
int sr = r + row_index;
if (sr < 0 || sr >= (int)Rows) continue;
for (int c = 0; c < (int)SubCols; ++c) {
int sc = c + col_index;
if (sc < 0 || sc >= (int)Cols) continue;
element(sr, sc) = m.element(r, c);
}
}
return *this;
}
private:
Type m[Rows][Cols];
};
#pragma pack(pop)
#ifdef PIP_STD_IOSTREAM
template<uint Rows, uint Cols, typename Type>
inline std::ostream & operator<<(std::ostream & s, const PIMathMatrixT<Rows, Cols, Type> & m) {
s << "{";
for (uint r = 0; r < Rows; ++r) {
for (uint c = 0; c < Cols; ++c) {
s << m[r][c];
if (c < Cols - 1 || r < Rows - 1) s << ", ";
}
if (r < Rows - 1) s << std::endl << " ";
}
s << "}";
return s;
}
#endif
//! \~english
//! \brief Inline operator for outputting the matrix to the console.
//! \param s \a PICout type.
//! \param the matrix type \a PIMathMatrix that we print to the console.
//! \return \a PIMathMatrix printed to the console.
//! \~russian
//! \brief Inline-оператор для вывода матрицы в консоль.
//! \param s типа \a PICout.
//! \param m типа \a PIMathMatrixT.
//! \return непечатанная в консоль \a PICout.
template<uint Rows, uint Cols, typename Type>
inline PICout operator<<(PICout s, const PIMathMatrixT<Rows, Cols, Type> & m) {
s.space();
s.saveAndSetControls(0);
s << "{";
for (uint r = 0; r < Rows; ++r) {
for (uint c = 0; c < Cols; ++c) {
s << m[r][c];
if (c < Cols - 1 || r < Rows - 1) s << ", ";
}
if (r < Rows - 1) s << PICoutManipulators::NewLine << " ";
}
s << "}";
s.restoreControls();
return s;
}
//! \~english
//! \brief Multiplying matrices by each other.
//! \param fm first matrix multiplier.
//! \param sm second matrix multiplier.
//! \return matrix that is the result of multiplication.
//! \~russian
//! \brief Умножение матриц друг на друга.
//! \param fm первый множитель-матрица.
//! \param sm второй множитель-матрица.
//! \return матрица, являющаяся результатом умножения.
template<uint CR, uint Rows0, uint Cols1, typename Type>
inline PIMathMatrixT<Rows0, Cols1, Type> operator*(const PIMathMatrixT<Rows0, CR, Type> & fm, const PIMathMatrixT<CR, Cols1, Type> & sm) {
PIMathMatrixT<Rows0, Cols1, Type> tm;
Type t;
for (uint j = 0; j < Rows0; ++j) {
for (uint i = 0; i < Cols1; ++i) {
t = Type(0);
for (uint k = 0; k < CR; ++k)
t += fm[j][k] * sm[k][i];
tm[j][i] = t;
}
}
return tm;
}
//! \~english
//! \brief Multiplying a matrix by a vector.
//! \param fm first matrix multiplier
//! \param sv second vector multiplier
//! \return vector that is the result of multiplication
//! \~russian
//! \brief Умножения матрицы на вектор.
//! \param fm первый множитель-матрица.
//! \param sv второй множитель-вектор.
//! \return вектор, являющийся результатом умножения.
template<uint Cols, uint Rows, typename Type>
inline PIMathVectorT<Rows, Type> operator*(const PIMathMatrixT<Rows, Cols, Type> & fm, const PIMathVectorT<Cols, Type> & sv) {
PIMathVectorT<Rows, Type> tv;
Type t;
for (uint j = 0; j < Rows; ++j) {
t = Type(0);
for (uint i = 0; i < Cols; ++i)
t += fm[j][i] * sv[i];
tv[j] = t;
}
return tv;
}
//! \~english
//! \brief Multiplying a vector by a matrix.
//! \param sv first vector multiplier
//! \param fm second matrix multiplier
//! \return vector that is the result of multiplication
//! \~russian
//! \brief Умножения вектора на матрицу.
//! \param sv второй множитель-вектор.
//! \param fm первый множитель-матрица.
//! \return вектор, являющийся результатом умножения.
template<uint Cols, uint Rows, typename Type>
inline PIMathVectorT<Cols, Type> operator*(const PIMathVectorT<Rows, Type> & sv, const PIMathMatrixT<Rows, Cols, Type> & fm) {
PIMathVectorT<Cols, Type> tv;
Type t;
for (uint j = 0; j < Cols; ++j) {
t = Type(0);
for (uint i = 0; i < Rows; ++i)
t += fm[i][j] * sv[i];
tv[j] = t;
}
return tv;
}
//! \~english
//! \brief Multiplying a value of type `Type` by a matrix.
//! \param x first multiplier of type `Type`.
//! \param v second matrix multiplier.
//! \return matrix that is the result of multiplication.
//! \~russian
//! \brief Умножение значения тип `Type` на матрицу.
//! \param x первый множитель типа `Type`.
//! \param v вторая множитель-матрица.
//! \return матрица, являющаяся результатом умножения.
template<uint Cols, uint Rows, typename Type>
inline PIMathMatrixT<Rows, Cols, Type> operator*(const Type & x, const PIMathMatrixT<Rows, Cols, Type> & v) {
return v * x;
}
typedef PIMathMatrixT<2u, 2u, int> PIMathMatrixT22i;
typedef PIMathMatrixT<3u, 3u, int> PIMathMatrixT33i;
typedef PIMathMatrixT<4u, 4u, int> PIMathMatrixT44i;
typedef PIMathMatrixT<2u, 2u, double> PIMathMatrixT22d;
typedef PIMathMatrixT<3u, 3u, double> PIMathMatrixT33d;
typedef PIMathMatrixT<4u, 4u, double> PIMathMatrixT44d;
template<typename Type>
class PIMathMatrix;
#undef PIMM_FOR
#undef PIMM_FOR_C
#undef PIMM_FOR_R
/// Matrix
#define PIMM_FOR \
for (uint r = 0; r < _V2D::rows_; ++r) \
for (uint c = 0; c < _V2D::cols_; ++c)
#define PIMM_FOR_A for (uint i = 0; i < _V2D::mat.size(); ++i)
#define PIMM_FOR_C for (uint i = 0; i < _V2D::cols_; ++i)
#define PIMM_FOR_R for (uint i = 0; i < _V2D::rows_; ++i)
//! \~english
//! \brief A class for dynamic size and fixed type matrix.
//! \tparam `Type` There are can be basic C++ language data and different classes where the arithmetic operators(=, +=, -=, *=, /=, ==, !=,
//! +, -, *, /) of the C++ language are implemented.
//! \~russian
//! \brief Класс для работы с матрицами динамического размера и фиксированного типа.
//! \tparam `Type` Здесь можеть быть базовый тип данных C++ или различные классы,
//! где реализованы арифметические операторы(=, +=, -=, *=, /=, ==, !=, +, -, *, /) языка C++.
template<typename Type>
class PIP_EXPORT PIMathMatrix: public PIVector2D<Type> {
typedef PIVector2D<Type> _V2D;
typedef PIMathMatrix<Type> _CMatrix;
public:
//! \~english
//! \brief Constructor of class \a PIMathMatrix, which creates a matrix.
//! \param cols is number of matrix column \a uint type.
//! \param rows is number of matrix row \a uint type.
//! \param f is type of matrix elements.
//! \~russian
//! \brief Конструктор класса \a PIMathMatrix, который создает матрицу.
//! \param cols количество столбов матрицы типа \a uint.
//! \param rows количество строк матрицы типа \a uint.
//! \param f тип элементов матрицы.
PIMathMatrix(const uint cols = 0, const uint rows = 0, const Type & f = Type()) { _V2D::resize(rows, cols, f); }
//! \~english
//! \brief Constructor of class \a PIMathMatrix, which creates a matrix
//! \param cols is number of matrix column \a uint type
//! \param rows is number of matrix row \a uint type
//! \param val is \a PIVector<Type> of matrix elements
//! \~russian
//! \brief Конструктор класса \a PIMathMatrix, который создает матрицу.
//! \param cols количество столбов матрицы типа \a uint.
//! \param rows количество строк матрицы типа \a uint.
//! \param val тип \a PIVector<Type> элементов матрицы.
PIMathMatrix(const uint cols, const uint rows, const PIVector<Type> & val) {
_V2D::resize(rows, cols);
int i = 0;
PIMM_FOR _V2D::element(r, c) = val[i++];
}
//! \~english
//! \brief Constructor of class \a PIMathMatrix, which creates a matrix.
//! \param val is PIVector<Type> of PIVector, which creates matrix.
//! \~russian
//! \brief Конструктор класса \a PIMathMatrix, который создает матрицу.
//! \param val тип \a PIVector<Type>, который создает матрицу.
PIMathMatrix(const PIVector<PIVector<Type>> & val) {
if (!val.isEmpty()) {
_V2D::resize(val.size(), val[0].size());
for (uint r = 0; r < _V2D::rows_; ++r) {
assert(val[r].size() == _V2D::cols_);
for (uint c = 0; c < _V2D::cols_; ++c)
_V2D::element(r, c) = val[r][c];
}
}
}
//! \~english
//! \brief Constructor of class \a PIMathMatrix, which creates a matrix.
//! \param val is \a PIVector2D<Type>, which creates matrix.
//! \~russian
//! \brief Конструктор класса \a PIMathMatrix, который создает матрицу.
//! \param val тип \a PIVector2D<Type>, который создает матрицу.
PIMathMatrix(const PIVector2D<Type> & val) {
if (!val.isEmpty()) {
_V2D::resize(val.rows(), val.cols());
PIMM_FOR _V2D::element(r, c) = val.element(r, c);
}
}
//! \~english
//! \brief Creates a matrix whose main diagonal is filled with ones and the remaining elements are zeros
//! \param cols is number of matrix column uint type
//! \param rows is number of matrix row uint type
//! \return identity matrix(cols, rows)
//! \~russian
//! \brief Создает матрицу, главная диагональ которой заполнена, а оставшиеся элементы - нулями.
//! \param cols количество столбов матрицы типа \a uint.
//! \param rows количество строк матрицы типа \a uint.
//! \return единичная матрица matrix(`cols`, `rows`)
static PIMathMatrix<Type> identity(const uint cols, const uint rows) {
PIMathMatrix<Type> tm(cols, rows);
for (uint r = 0; r < rows; ++r)
for (uint c = 0; c < cols; ++c)
tm.element(r, c) = (c == r ? Type(1) : Type(0));
return tm;
}
//! \~english
//! \brief Creates a row matrix of every element that is equal to every element of the vector
//! \param val is the vector type \a PIMathVector
//! \return row matrix of every element that is equal to every element of the vector
//! \~russian
//! \brief Создает матрицу-строку, каждый элемент которой равен каждому элементу вектора
//! \param val вектор типа \a PIMathVector
//! \return матрица-строка, каждый элемент которой равен каждому элементу вектора
static PIMathMatrix<Type> matrixRow(const PIMathVector<Type> & val) { return PIMathMatrix<Type>(val.size(), 1, val.toVector()); }
//! \~english
//! \brief Creates a column matrix of every element that is equal to every element of the vector
//! \param val is the vector type \a PIMathVector
//! \return column matrix of every element that is equal to every element of the vector
//! \~russian
//! \brief Создает матрицу-столбец, каждый элемент которой равен каждому элементу вектора
//! \param val вектор типа \a PIMathVector
//! \return матрица-столбец, каждый элемент которой равен каждому элементу вектора
static PIMathMatrix<Type> matrixCol(const PIMathVector<Type> & val) { return PIMathMatrix<Type>(1, val.size(), val.toVector()); }
//! \~english
//! \brief Set the selected column in matrix.
//! \details If there are more elements of the vector than elements in the column of the matrix
//! or index larger than the number of columns otherwise there will be "undefined behavior".
//! \param index is the number of the selected column.
//! \param v is a vector of the type \a PIMathVector<Type> that needs to fill the column.
//! \return matrix type \a PIMathMatrix<Type>
//! \~russian
//! \brief Определить выбранный столбец матрицы.
//! \details Если элементов в векторе больше, чем элементов в столбце матрицы
//! или индекс больше количества стобцов, то поведение не определено ("undefined behavior").
//! \param index номер выбранного столбца.
//! \param v вектор типа \a PIMathVector<Type>, которым нужно заполнить столбец.
//! \return матрица типа \a PIMathMatrix<Type>.
PIMathMatrix<Type> & setCol(uint index, const PIMathVector<Type> & v) {
assert(_V2D::rows() == v.size());
PIMM_FOR_R _V2D::element(i, index) = v[i];
return *this;
}
//! \~english
//! \brief Set the selected row in matrix.
//! \details If there are more elements of the vector than elements in the row of the matrix,
//! or index larger than the number of rows otherwise there will be "undefined behavior".
//! \param index is the number of the selected row.
//! \param v is a vector of the type \a PIMathVector<Type> that needs to fill the row.
//! \return matrix type \a PIMathMatrix<Type>.
//! \~russian
//! \brief Определить выбранную строку матрицы.
//! \details Если элементов в векторе больше, чем элементов в строке матрицы
//! или индекс больше количества стобцов, то поведение не определено ("undefined behavior").
//! \param index номер выбранной строки.
//! \param v вектор типа \a PIMathVector<Type>, которым нужно заполнить строку.
//! \return матрица типа \a PIMathMatrix<Type>.
PIMathMatrix<Type> & setRow(uint index, const PIMathVector<Type> & v) {
assert(_V2D::cols() == v.size());
PIMM_FOR_C _V2D::element(index, i) = v[i];
return *this;
}
//! \~english
//! \brief Method which swaps selected columns in a matrix.
//! \details You cannot use an index larger than the number of columns,
//! otherwise there will be "undefined behavior".
//! \param r0 is the number of the first selected column.
//! \param r1 is the number of the second selected column.
//! \return matrix type \a PIMathMatrix<Type>.
//! \~russian
//! \brief Метод меняющий местами выбранные строки в матрице.
//! \details Вы не можете использовать индекс, который больше количества столбцов,
//! иначе будет неопределенное повередение ("undefined behavior").
//! \param r0 номер первой выбранного стобца.
//! \param r1 номер второй выбранного столбца.
//! \return матрица типа \a PIMathMatrix<Type>.
PIMathMatrix<Type> & swapCols(uint r0, uint r1) {
PIMM_FOR_C piSwap<Type>(_V2D::element(i, r0), _V2D::element(i, r1));
return *this;
}
//! \~english
//! \brief Method which replace selected rows in a matrix.
//! \details You cannot use an index larger than the number of rows,
//! otherwise there will be "undefined behavior"
//! \param c0 is the number of the first selected row.
//! \param c1 is the number of the second selected row.
//! \return matrix type \a PIMathMatrix<Type>.
//! \~russian
//! \brief Метод меняющий местами выбранные строки в матрице.
//! \details Вы не можете использовать индекс, который больше количества строк,
//! иначе будет неопределенное повередение ("undefined behavior").
//! \param с0 номер первой выбранной строки.
//! \param с1 номер второй выбранной строки.
//! \return матрица типа \a PIMathMatrix<Type>.
PIMathMatrix<Type> & swapRows(uint c0, uint c1) {
PIMM_FOR_R piSwap<Type>(_V2D::element(c0, i), _V2D::element(c1, i));
return *this;
}
//! \~english
//! \brief Method which fills the matrix with selected value.
//! \param v is a parameter the type and value of which is selected and later filled into the matrix.
//! \return filled matrix type \a PIMathMatrix<Type>.
//! \~russian
//! \brief Метод заполняющий матрицу выбранным значением.
//! \param v параметр выбранного типа и значения, которым будет заполнена матрица.
//! \return заполненная матрица типа \a PIMathMatrix<Type>.
PIMathMatrix<Type> & fill(const Type & v) {
PIMM_FOR_A _V2D::mat[i] = v;
return *this;
}
//! \~english
//! \brief Method which checks if matrix is square.
//! \return true if matrix is square, else false.
//! \~russian
//! \brief Метод, проверющий является ли матрица квадратной.
//! \return true если матрица квадратная, иначе false.
bool isSquare() const { return _V2D::cols_ == _V2D::rows_; }
//! \~english
//! \brief Method which checks if main diagonal of matrix consists of ones and another elements are zeros.
//! \return true if matrix is identitied, else false.
//! \~russian
//! \brief Метод, проверяющий содержит ли главная диагональ единицы и все остальные поля нули.
//! \return true если матрица единичная, иначе false.
bool isIdentity() const {
PIMM_FOR if ((c == r) ? _V2D::element(r, c) != Type(1) : _V2D::element(r, c) != Type(0)) return false;
return true;
}
//! \~english
//! \brief Method which checks if every elements of matrix are zeros.
//! \return true if matrix is null, else false.
//! \~russian
//! \brief Метод, являются ли все элементы матрицы нулями.
//! \return true если матрица нулевая, иначе false.
bool isNull() const {
PIMM_FOR_A if (_V2D::mat[i] != Type(0)) return false;
return true;
}
//! \~english
//! \brief Method which checks if matrix is empty.
//! \return true if matrix is valid, else false.
//! \~russian
//! \brief Метод, который проверяет является ли матрица пустой.
//! \return true если матрица действительна, иначе false.
bool isValid() const { return !PIVector2D<Type>::isEmpty(); }
//! \~english
//! \brief Addition assignment with matrix `sm`.
//! \param sm matrix for the addition assigment.
//! \~russian
//! \brief Сложение с присваиванием с матрицей `sm`.
//! \param sm матрица для сложения с присваиванием.
void operator+=(const PIMathMatrix<Type> & sm) {
assert(_V2D::rows() == sm.rows());
assert(_V2D::cols() == sm.cols());
PIMM_FOR_A _V2D::mat[i] += sm.mat[i];
}
//! \~english
//! \brief Subtraction assignment with matrix `sm`.
//! \param sm matrix for the subtraction assigment.
//! \~russian
//! \brief Вычитание с присваиванием с матрицей `sm`.
//! \param sm матрица для вычитания с присваиванием.
void operator-=(const PIMathMatrix<Type> & sm) {
assert(_V2D::rows() == sm.rows());
assert(_V2D::cols() == sm.cols());
PIMM_FOR_A _V2D::mat[i] -= sm.mat[i];
}
//! \~english
//! \brief Multiplication assignment with value `v`.
//! \param v value for the multiplication assigment.
//! \~russian
//! \brief Умножение с присваиванием с матрицей `v`.
//! \param sm матрица для умножения с присваиванием.
void operator*=(const Type & v) { PIMM_FOR_A _V2D::mat[i] *= v; }
//! \~english
//! \brief Division assignment with value `v`.
//! \param v value for the division assigment.
//! \~russian
//! \brief Деление с присваиванием с матрицей `v`.
//! \param sm матрица для деления с присваиванием.
void operator/=(const Type & v) {
assert(piAbs<Type>(v) > PIMATHVECTOR_ZERO_CMP);
PIMM_FOR_A _V2D::mat[i] /= v;
}
//! \~english
//! \brief Negation operation
//! \return copy of the negative matrix
//! \~russian
//! \brief Операция отрицания
//! \return копия отрицательной матрицы
PIMathMatrix<Type> operator-() const {
PIMathMatrix<Type> tm(*this);
PIMM_FOR_A tm.mat[i] = -_V2D::mat[i];
return tm;
}
//! \~english
//! \brief Matrix addition.
//! \param sm is matrix term.
//! \return the result of matrix addition.
//! \~russian
//! \brief Матричное сложение.
//! \param sm матричное слагаемое.
//! \return результат матричного сложения.
PIMathMatrix<Type> operator+(const PIMathMatrix<Type> & sm) const {
PIMathMatrix<Type> tm(*this);
assert(tm.rows() == sm.rows());
assert(tm.cols() == sm.cols());
PIMM_FOR_A tm.mat[i] += sm.mat[i];
return tm;
}
//! \~english
//! \brief Matrix substraction.
//! \param sm is matrix subtrahend.
//! \return the result of matrix substraction.
//! \~russian
//! \brief Матричная разность.
//! \param sm матричное вычитаемое.
//! \return результат матричной разности.
PIMathMatrix<Type> operator-(const PIMathMatrix<Type> & sm) const {
PIMathMatrix<Type> tm(*this);
assert(tm.rows() == sm.rows());
assert(tm.cols() == sm.cols());
PIMM_FOR_A tm.mat[i] -= sm.mat[i];
return tm;
}
//! \~english
//! \brief Matrix multiplication.
//! \param v is value factor.
//! \return the result of matrix multiplication.
//! \~russian
//! \brief Матричное произведение.
//! \param v множитель.
//! \return результат произведения.
PIMathMatrix<Type> operator*(const Type & v) const {
PIMathMatrix<Type> tm(*this);
PIMM_FOR_A tm.mat[i] *= v;
return tm;
}
//! \~english
//! \brief Matrix division.
//! \param v is value divider.
//! \return the result of matrix division.
//! \~russian
//! \brief Матричное деление.
//! \param v делитель.
//! \return результат деления.
PIMathMatrix<Type> operator/(const Type & v) const {
assert(piAbs<Type>(v) > PIMATHVECTOR_ZERO_CMP);
PIMathMatrix<Type> tm(*this);
PIMM_FOR_A tm.mat[i] /= v;
return tm;
}
//! \~english
//! \brief Calculate Determinant of the matrix.
//! \details Works only with square matrix, nonzero matrices and invertible matrix.
//! \param ok is a parameter with which we can find out if the method worked correctly.
//! \return matrix determinant.
//! \~russian
//! \brief Вычислить определитель матрицы.
//! \details Работает только с квадратными, ненулевыми и обратимыми матрицами.
//! \param ok это параметр, с помощью которого мы можем узнать, правильно ли сработал метод.
//! \return опеределитель матрицы.
Type determinant(bool * ok = 0) const {
PIMathMatrix<Type> m(*this);
bool k;
m.toUpperTriangular(&k);
Type ret = Type(0);
if (ok) *ok = k;
if (!k) return ret;
ret = Type(1);
for (uint c = 0; c < _V2D::cols_; ++c)
for (uint r = 0; r < _V2D::rows_; ++r)
if (r == c) ret *= m.element(r, c);
return ret;
}
//! \~english
//! \brief Calculate the trace of a matrix.
//! \details Works only with square matrix matrix.
//! \return matrix trace.
//! \~russian
//! \brief Вычислить след матрицы.
//! \details Работает только с квадратными матрицами.
//! \return след матрицы.
Type trace() const {
assert(isSquare());
Type ret = Type(0);
for (uint i = 0; i < _V2D::cols_; ++i) {
ret += _V2D::element(i, i);
}
return ret;
}
//! \~english
//! \brief Transforming matrix to upper triangular.
//! \details Works only with square matrix, nonzero matrices and invertible matrix.
//! \param ok is a parameter with which we can find out if the method worked correctly.
//! \return copy of transformed upper triangular matrix.
//! \~russian
//! \brief Преобразование матрицы в верхнетреугольную.
//! \details Работает только с квадратными, ненулевыми и обратимыми матрицами.
//! \param ok это параметр, с помощью которого мы можем узнать, правильно ли сработал метод.
//! \return копия преобразованной верхнетреугольной матрицы.
PIMathMatrix<Type> & toUpperTriangular(bool * ok = 0) {
assert(isSquare());
PIMathMatrix<Type> smat(*this);
bool ndet;
uint crow;
Type mul;
for (uint i = 0; i < _V2D::cols_; ++i) {
ndet = true;
for (uint j = 0; j < _V2D::rows_; ++j)
if (smat.element(i, j) != 0) ndet = false;
if (ndet) {
if (ok != 0) *ok = false;
return *this;
}
}
for (uint i = 0; i < _V2D::cols_; ++i) {
crow = i;
while (smat.element(i, i) == Type(0))
smat.swapRows(i, ++crow);
for (uint j = i + 1; j < _V2D::rows_; ++j) {
mul = smat.element(i, j) / smat.element(i, i);
for (uint k = i; k < _V2D::cols_; ++k)
smat.element(k, j) -= mul * smat.element(k, i);
}
if (i < _V2D::cols_ - 1) {
if (PIMathFloatNullCompare(smat.element(i + 1, i + 1))) {
if (ok != 0) *ok = false;
return *this;
}
}
}
if (ok != 0) *ok = true;
_V2D::mat.swap(smat.mat);
return *this;
}
//! \~english
//! \brief Matrix inversion operation.
//! \details Works only with square matrix, nonzero matrices and invertible matrix.
//! \param ok is a parameter with which we can find out if the method worked correctly.
//! \return inverted matrix.
//! \~russian
//! \brief Операция обращения матрицы.
//! \details Работает только с квадратными, ненулевыми и обратимыми матрицами.
//! \param ok это параметр, с помощью которого мы можем узнать, правильно ли сработал метод.
//! \return обратная матрица.
PIMathMatrix<Type> & invert(bool * ok = 0, PIMathVector<Type> * sv = 0) {
assert(isSquare());
PIMathMatrix<Type> mtmp = PIMathMatrix<Type>::identity(_V2D::cols_, _V2D::rows_), smat(*this);
bool ndet;
uint crow;
Type mul, iddiv;
for (uint i = 0; i < _V2D::cols_; ++i) {
ndet = true;
for (uint j = 0; j < _V2D::rows_; ++j)
if (smat.element(i, j) != Type(0)) ndet = false;
if (ndet) {
if (ok != 0) *ok = false;
return *this;
}
}
for (uint i = 0; i < _V2D::cols_; ++i) {
crow = i;
while (smat.element(i, i) == Type(0)) {
++crow;
smat.swapRows(i, crow);
mtmp.swapRows(i, crow);
if (sv != 0) sv->swapElements(i, crow);
}
for (uint j = i + 1; j < _V2D::rows_; ++j) {
mul = smat.element(i, j) / smat.element(i, i);
for (uint k = i; k < _V2D::cols_; ++k)
smat.element(k, j) -= mul * smat.element(k, i);
for (uint k = 0; k < _V2D::cols_; ++k)
mtmp.element(k, j) -= mul * mtmp.element(k, i);
if (sv != 0) (*sv)[j] -= mul * (*sv)[i];
}
if (i < _V2D::cols_ - 1) {
if (PIMathFloatNullCompare(smat.element(i + 1, i + 1))) {
if (ok != 0) *ok = false;
return *this;
}
}
iddiv = smat.element(i, i);
for (uint j = i; j < _V2D::cols_; ++j)
smat.element(j, i) /= iddiv;
for (uint j = 0; j < _V2D::cols_; ++j)
mtmp.element(j, i) /= iddiv;
if (sv != 0) (*sv)[i] /= iddiv;
}
for (uint i = _V2D::cols_ - 1; i > 0; --i) {
for (uint j = 0; j < i; ++j) {
mul = smat.element(i, j);
smat.element(i, j) -= mul;
for (uint k = 0; k < _V2D::cols_; ++k)
mtmp.element(k, j) -= mul * mtmp.element(k, i);
if (sv != 0) (*sv)[j] -= mul * (*sv)[i];
}
}
if (ok != 0) *ok = true;
PIVector2D<Type>::swap(mtmp);
return *this;
}
//! \~english
//! \brief Matrix inversion operation.
//! \details Works only with square matrix, nonzero matrices and invertible matrix.
//! \param ok is a parameter with which we can find out if the method worked correctly.
//! \return copy of inverted matrix.
//! \~russian
//! \brief Операция обращения матрицы.
//! \details Работает только с квадратными, ненулевыми и обратимыми матрицами.
//! \param ok это параметр, с помощью которого мы можем узнать, правильно ли сработал метод.
//! \return копия обратной матрицы.
PIMathMatrix<Type> inverted(bool * ok = 0) const {
PIMathMatrix<Type> tm(*this);
tm.invert(ok);
return tm;
}
//! \~english
//! \brief Matrix transposition operation.
//! \details Works only with square matrix matrix.
//! \return copy of transposed matrix
//! \~russian
//! \brief Транспонирование матрицы.
//! \details Работает только с квадратными матрицами.
//! \return копия транспонированной матрицы.
PIMathMatrix<Type> transposed() const {
PIMathMatrix<Type> tm(_V2D::rows_, _V2D::cols_);
PIMM_FOR tm.element(c, r) = _V2D::element(r, c);
return tm;
}
};
#ifdef PIP_STD_IOSTREAM
template<typename Type>
inline std::ostream & operator<<(std::ostream & s, const PIMathMatrix<Type> & m) {
s << "{";
for (uint r = 0; r < m.rows(); ++r) {
for (uint c = 0; c < m.cols(); ++c) {
s << m.element(r, c);
if (c < m.cols() - 1 || r < m.rows() - 1) s << ", ";
}
if (r < m.rows() - 1) s << std::endl << " ";
}
s << "}";
return s;
}
#endif
//! \~english
//! \brief Inline operator for outputting the matrix to the console.
//! \param s \a PICout type.
//! \param the matrix type \a PIMathMatrix that we print to the console.
//! \return \a PIMathMatrix printed to the console.
//! \~russian
//! \brief Inline-оператор для вывода матрицы в консоль.
//! \param s типа \a PICout.
//! \param m типа \a PIMathMatrixT.
//! \return непечатанная в консоль \a PICout.
template<typename Type>
inline PICout operator<<(PICout s, const PIMathMatrix<Type> & m) {
s.space();
s.saveAndSetControls(0);
s << "Matrix{";
for (uint r = 0; r < m.rows(); ++r) {
for (uint c = 0; c < m.cols(); ++c) {
s << m.element(r, c);
if (c < m.cols() - 1 || r < m.rows() - 1) s << ", ";
}
if (r < m.rows() - 1) s << PICoutManipulators::NewLine << " ";
}
s << "}";
s.restoreControls();
return s;
}
//! \~english
//! \brief Inline operator for serializing a matrix into a \a PIBinaryStream.
//! \param s \a PIBinaryStream type.
//! \param v \a PIMathMatrix type.
//! \~russian
//! \brief Inline-оператор для сериализации матрицы в \a PIBinaryStream.
//! \param s типа \a PIBinaryStream.
//! \param v типа \a PIMathMatrix.
template<typename P, typename T>
inline PIBinaryStream<P> & operator<<(PIBinaryStream<P> & s, const PIMathMatrix<T> & v) {
s << (const PIVector2D<T> &)v;
return s;
}
//! \~english
//! \brief Inline operator to deserialize matrix from \a PIByteArray.
//! \param s \a PIBinaryStream type.
//! \param v \a PIMathMatrix type.
//! \~russian
//! \brief Inline-оператор для сериализации матрицы в \a PIByteArray.
//! \param s типа \a PIBinaryStream.
//! \param v типа \a PIMathMatrix.
template<typename P, typename T>
inline PIBinaryStream<P> & operator>>(PIBinaryStream<P> & s, PIMathMatrix<T> & v) {
s >> (PIVector2D<T> &)v;
return s;
}
//! \~english
//! \brief Multiplying matrices by each other.
//! \details If you enter an index out of the border of the matrix there will be "undefined behavior".
//! \param fm first matrix multiplier.
//! \param sm second matrix multiplier.
//! \return matrix that is the result of multiplication.
//! \~russian
//! \brief Умножение матриц друг на друга.
//! \details Если вы введете индекс вне границ матрицы, то поведение не определено ("undefined behavior").
//! \param fm первый множитель-матрица.
//! \param sm вторая множитель-матрица.
//! \return матрица, являющаяся результатом умножения.
template<typename Type>
inline PIMathMatrix<Type> operator*(const PIMathMatrix<Type> & fm, const PIMathMatrix<Type> & sm) {
assert(fm.cols() == sm.rows());
PIMathMatrix<Type> tm(sm.cols(), fm.rows());
Type t;
for (uint j = 0; j < fm.rows(); ++j) {
for (uint i = 0; i < sm.cols(); ++i) {
t = Type(0);
for (uint k = 0; k < fm.cols(); ++k)
t += fm.element(j, k) * sm.element(k, i);
tm.element(j, i) = t;
}
}
return tm;
}
//! \~english
//! \brief Multiplying a matrix by a vector.
//! \details If you enter an index out of the border of the matrix there will be "undefined behavior".
//! \param fm first matrix multiplier
//! \param sv second vector multiplier
//! \return vector that is the result of multiplication
//! \~russian
//! \brief Умножения матрицы на вектор.
//! \details Если вы введете индекс вне границ матрицы, то поведение не определено ("undefined behavior").
//! \param fm первый множитель-матрица.
//! \param sv второй множитель-вектор.
//! \return вектор, являющийся результатом умножения.
template<typename Type>
inline PIMathVector<Type> operator*(const PIMathMatrix<Type> & fm, const PIMathVector<Type> & sv) {
assert(fm.cols() == sv.size());
PIMathVector<Type> tv(fm.rows());
Type t;
for (uint j = 0; j < fm.rows(); ++j) {
t = Type(0);
for (uint i = 0; i < fm.cols(); ++i)
t += fm.element(j, i) * sv[i];
tv[j] = t;
}
return tv;
}
//! \~english
//! \brief Multiplying a vector by a matrix.
//! \details If you enter an index out of the border of the matrix there will be "undefined behavior".
//! \param sv first vector multiplier
//! \param fm second matrix multiplier
//! \return vector that is the result of multiplication
//! \~russian
//! \brief Умножения вектора на матрицу.
//! \details Если вы введете индекс вне границ матрицы, то поведение не определено ("undefined behavior").
//! \param sv второй множитель-вектор.
//! \param fm первый множитель-матрица.
//! \return вектор, являющийся результатом умножения.
template<typename Type>
inline PIMathVector<Type> operator*(const PIMathVector<Type> & sv, const PIMathMatrix<Type> & fm) {
PIMathVector<Type> tv(fm.cols());
assert(fm.rows() == sv.size());
Type t;
for (uint j = 0; j < fm.cols(); ++j) {
t = Type(0);
for (uint i = 0; i < fm.rows(); ++i)
t += fm.element(i, j) * sv[i];
tv[j] = t;
}
return tv;
}
//! \~english
//! \brief Multiplying a value of type `Type` by a matrix.
//! \param x first multiplier of type `Type`.
//! \param v second matrix multiplier.
//! \return matrix that is the result of multiplication.
//! \~russian
//! \brief Умножение значения тип `Type` на матрицу.
//! \param x первый множитель типа `Type`.
//! \param v второй множитель-матрица.
//! \return матрица, являющаяся результатом умножения.
template<typename Type>
inline PIMathMatrix<Type> operator*(const Type & x, const PIMathMatrix<Type> & v) {
return v * x;
}
typedef PIMathMatrix<int> PIMathMatrixi;
typedef PIMathMatrix<double> PIMathMatrixd;
//! \~english
//! \brief Searching hermitian matrix.
//! \param m conjugate transpose matrix.
//! \return result of the hermitian.
//! \~russian
//! \brief Поиск эрмитовой матрицы.
//! \param m сопряженная транспонированная матрица.
//! \return результат преобразования.
template<typename T>
PIMathMatrix<complex<T>> hermitian(const PIMathMatrix<complex<T>> & m) {
PIMathMatrix<complex<T>> ret(m);
for (uint r = 0; r < ret.rows(); ++r)
for (uint c = 0; c < ret.cols(); ++c)
ret.element(r, c).imag(-(ret.element(r, c).imag()));
return ret.transposed();
}
#undef PIMM_FOR
#undef PIMM_FOR_A
#undef PIMM_FOR_C
#undef PIMM_FOR_R
#endif // PIMATHMATRIX_H