diff options
Diffstat (limited to 'libprakipp/include/prakmatrix.hpp')
-rw-r--r-- | libprakipp/include/prakmatrix.hpp | 185 |
1 files changed, 0 insertions, 185 deletions
diff --git a/libprakipp/include/prakmatrix.hpp b/libprakipp/include/prakmatrix.hpp deleted file mode 100644 index 87b38b4..0000000 --- a/libprakipp/include/prakmatrix.hpp +++ /dev/null @@ -1,185 +0,0 @@ -#pragma once - -#include "prakcommon.hpp" - -#include <cstring> -#include <iomanip> -#include <ostream> -#include <vector> - -namespace prak { - -struct dimension_error : public std::logic_error { - explicit dimension_error(const char *what): std::logic_error(what) {} -}; - -/// A class to represent a matrix. Works as an extension to std::vector, so all methods of std::vector are available on this class -/// BIG TODO: replave `throw` with `std::optional` return type -template <typename T> -struct matrix : public std::vector<T> { - size_t rows, cols; - size_t feq_precision = 10; - const T &SUBSCR_OPRTR(size_t row, size_t col) const { - return this->at(row * cols + col); - } - T &SUBSCR_OPRTR(size_t row, size_t col) { - return this->at(row * cols + col); - } - matrix(void) = default; - matrix(struct matrix<T> &&) = default; - matrix(const struct matrix<T> &) = default; - struct matrix<T> &operator=(const struct matrix<T> &) = default; - explicit matrix(size_t rows, size_t cols, T def) - : rows{rows}, cols{cols}, std::vector<T>(rows * cols, def) {} - explicit matrix(size_t rows, size_t cols, T *data = nullptr) - : rows{rows}, cols{cols}, std::vector<T>(rows * cols) { - if (data != nullptr) std::memcpy(this->data(), data, rows * cols); - } - explicit matrix (size_t rows, size_t cols, std::vector<T> &&data) noexcept(false) - : rows{rows}, cols{cols}, std::vector<T>(std::move(data)) { - if (this->size() != rows * cols) throw std::out_of_range("data.size() != rows*cols"); - } - /// add 2 matrixes - struct matrix<T> operator+(const struct matrix<T> &other) noexcept(false) { - if (other.rows != rows || other.cols != cols) - throw dimension_error("matrix add: dimensions of 'other' do not match dimensions of 'this'"); - struct matrix<T> ret(rows, cols); - for (size_t i = 0; i < this->size(); ++i) { - ret.data()[i] = this->data()[i] + other.data()[i]; - } - return ret; - } - /// perform matrix multiplication - struct matrix<T> operator*(const struct matrix<T> &other) noexcept(false) { - if (cols != other.rows) - throw dimension_error("Matrix mul: 'other.rows' does not match 'this.cols'"); - struct matrix<T> ret(rows, other.cols, T{}); - for (size_t i = 0; i < rows; ++i) { - for (size_t j = 0; j < other.cols; ++j) { - for (size_t k = 0; k < cols; ++k) - ret.SUBSCR_OPRTR(i, j) += SUBSCR_OPRTR(i, k) * other.SUBSCR_OPRTR(k, j); - } - } - return ret; - } - /// multiply matrix by a vector [other.size() x 1] - std::enable_if<std::is_arithmetic_v<T>, std::vector<T>> - operator*(const std::vector<T> &other) noexcept(false) { - if (cols != other.size()) throw dimension_error("Matrix mul: 'other.rows' does not match 'this.cols'"); - std::vector<T> ret(rows, T{}); - for (size_t row = 0; row < rows; ++rows) { - for (size_t k = 0; k < cols; ++k) - ret[row] += SUBSCR_OPRTR(row, k) * other[k]; - } - return ret; - } - /// multiply matrix by a scalar - template <typename Arg> - std::enable_if_t<std::is_arithmetic_v<Arg>, struct matrix<T>> - operator*(const Arg other) const { - struct matrix<T> ret(rows, cols); - for (size_t i = 0; i < this->size(); ++i) - ret.data()[i] = this->data()[i] * other; - return ret; - } - /// Tries to find an inverse of the matrix by using gaussian elimination - /// TODO: handle the case where the inverse does not exist - std::enable_if_t<std::is_floating_point_v<T>, std::optional<struct matrix<T>>> - inv(void) const noexcept(false) { - if (rows != cols) throw dimension_error("Matrix must be square to be inverted"); - struct matrix<T> gaussian(rows, cols * 2, T{}); - for (size_t row = 0; row < rows; ++row) { - std::memcpy(gaussian.data() + (row * cols * 2 ), this->data() + row * cols, cols * sizeof (T)); - gaussian.data()[row * cols * 2 + cols + row] = 1; - } - for (size_t row = 0; row < rows; ++row) { - T &fst_row_v = gaussian.SUBSCR_OPRTR(row, row); - bool row_found = true; - if (fequal<T>(fst_row_v, 0, feq_precision)) row_found = gaussian.find_suitable_row(row); - if (!row_found) return std::nullopt; - gaussian.mul_row(row, 1/gaussian.SUBSCR_OPRTR(row, row)); - for (size_t pr_row = 0; pr_row < rows; ++pr_row) { - if (row == pr_row) continue; - T& row_n_v = gaussian.SUBSCR_OPRTR(pr_row, row); - if (fequal<T>(row_n_v, 0, feq_precision)) continue; - gaussian.muladd_row(row, pr_row, -row_n_v/fst_row_v); - } - } - struct matrix<T> ret(rows, cols); - for (size_t row = 0; row < rows; ++row) { - std::memcpy(ret.data() + row * cols, gaussian.data() + row * 2*cols + cols, cols * sizeof (T)); - } - return ret; - - } - struct matrix<T> tr(void) const { - struct matrix<T> ret(cols, rows); - for (size_t row = 0; row < rows; ++row) - for (size_t col = 0; col < cols; ++col) - ret.SUBSCR_OPRTR(col, row) = SUBSCR_OPRTR(row, col); - return ret; - } - /// swaps rows `r1`, `r2` - void swap_rows(size_t r1, size_t r2) { - T* tmpbuf = new T[cols]; - size_t rowsize = cols * sizeof (T); - std::memcpy(tmpbuf, this->data() + cols * r1, rowsize); - std::memcpy(this->data() + cols * r1, this->data() + cols * r2, rowsize); - std::memcpy(this->data() + cols * r2, tmpbuf, rowsize); - delete[] tmpbuf; - } - /// multiplies `r_src` row by number `mul` and adds it ro row `r_dest` - void muladd_row(size_t r_src, size_t r_dest, T mul) { - for (size_t col = 0; col < cols; ++col) { - size_t r_src_ofs = cols * r_src + col; - size_t r_dest_ofs = cols * r_dest + col; - this->data()[r_dest_ofs] += this->data()[r_src_ofs] * mul; - } - } - /// multiplies a row by a number - void mul_row(size_t r1, T mul) { - for (size_t ind = r1 * cols; ind < (r1 + 1) * cols; ++ind) - this->data()[ind] *= mul; - } - /// finds a row that contains non-zero number at index [row = i > `row`, column=`row`]. - /// will only search for the rows below `row` and swap them - /// returns whether the swap occured (whether the row was found) - bool find_suitable_row(size_t row) { - for (size_t i = row + 1; i < rows; ++i) { - if (SUBSCR_OPRTR(i, row) != 0) { - swap_rows(i, row); - return true; - } - } - return false; - } - - static struct matrix<T> identity(size_t rank) { - struct matrix<T> ret(rank, rank); - for (size_t i = 0; i < rank * rank; i += (rank + 1)) { - ret.data()[i] = 1; - } - return ret; - } - - std::ostream &print(std::ostream &out = std::cout, size_t width = 10) const { - for (size_t row = 0; row < rows; ++row) { - for (size_t col = 0; col < cols; ++col) - out << "|" << std::setw(width) << SUBSCR_OPRTR(row, col); - std::cout << "|\n"; - } - return out; - } -}; - -template<typename T> -void operator/(const int x, const struct matrix<T> &m) { - std::cout << __PRETTY_FUNCTION__ << std::endl; -} - -template <typename T> -std::ostream &operator<<(std::ostream &out, const struct matrix<T> &m) { - return m.print(out); -} - -} // namespace prak |