12#include "include/matrix.h"
14#include "include/complex_number.h"
43auto safe_sqrt(T value) ->
44 typename std::conditional_t<std::is_arithmetic_v<T>, T,
double>
46 if constexpr (std::is_floating_point_v<T>) {
47 return std::sqrt(value);
48 }
else if constexpr (std::is_arithmetic_v<T>) {
49 return static_cast<T
>(std::sqrt(
static_cast<double>(value)));
52 return std::sqrt(value.magnitude());
86auto safe_abs(T value) ->
87 typename std::conditional_t<std::is_arithmetic_v<T>, T,
double>
89 if constexpr (std::is_floating_point_v<T>) {
90 return std::abs(value);
91 }
else if constexpr (std::is_arithmetic_v<T>) {
92 return static_cast<T
>(std::abs(
static_cast<double>(value)));
95 return std::abs(value.magnitude());
100double getAbsoluteValue(
const T& value)
102 if constexpr (std::is_arithmetic_v<T>) {
104 return std::abs(
static_cast<double>(value));
115 if (mat.empty() || mat[0].empty()) {
116 throw std::invalid_argument(
"Matrix cannot be empty");
120 cols = mat[0].size();
123 for (
const auto& row : mat) {
124 if (row.size() != cols) {
125 throw std::invalid_argument(
126 "All matrix rows must have the same number of columns");
136 if (row < 0 || row >= rows || column < 0 || column >= cols) {
137 throw std::out_of_range(
138 std::string(
"Matrix index out of bounds\n") +
"[row]: "
139 + std::to_string(row) +
" [col]: " + std::to_string(column) +
"\n"
140 +
"[dimension]: " + std::to_string(rows) +
"x" + std::to_string(cols));
142 return data[row][column];
148 if (row < 0 || row >= rows || column < 0 || column >= cols) {
149 throw std::out_of_range(
150 std::string(
"Matrix index out of bounds\n") +
"[row]: "
151 + std::to_string(row) +
" [col]: " + std::to_string(column) +
"\n"
152 +
"[dimension]: " + std::to_string(rows) +
"x" + std::to_string(cols));
154 return data[row][column];
160 if (rows != other.rows || cols != other.cols) {
161 throw std::invalid_argument(
"Matrix dimensions must match for addition");
165 for (
int i = 0; i < rows; ++i) {
166 for (
int j = 0; j < cols; ++j) {
167 result(i, j) = data[i][j] + other(i, j);
176 if (rows != other.rows || cols != other.cols) {
177 throw std::invalid_argument(
"Matrix dimensions must match for subtraction");
181 for (
int i = 0; i < rows; ++i) {
182 for (
int j = 0; j < cols; ++j) {
183 result(i, j) = data[i][j] - other(i, j);
192 if (cols != other.rows) {
193 throw std::invalid_argument(
194 "Matrix dimensions incompatible for multiplication");
198 for (
int i = 0; i < rows; ++i) {
199 for (
int j = 0; j < other.cols; ++j) {
201 for (
int k = 0; k < cols; ++k) {
202 sum += data[i][k] * other(k, j);
214 for (
int i = 0; i < rows; ++i) {
215 for (
int j = 0; j < cols; ++j) {
216 result(i, j) = data[i][j] * scalar;
225 std::vector<std::vector<T>> matrix = data;
226 int n = matrix.size();
227 int m = matrix[0].size();
228 const double EPS = 1E-9;
230 std::vector<bool> row_selected(n,
false);
232 for (
int i = 0; i < m; ++i) {
234 for (j = 0; j < n; ++j) {
235 if (!row_selected[j] && abs(matrix[j][i]) > EPS) {
241 row_selected[j] =
true;
242 for (
int p = i + 1; p < m; ++p) {
243 matrix[j][p] /= matrix[j][i];
245 for (
int k = 0; k < n; ++k) {
246 if (k != j && abs(matrix[k][i]) > EPS) {
247 for (
int p = i + 1; p < m; ++p) {
248 matrix[k][p] -= (matrix[j][p] * matrix[k][i]);
260 if (getRows() != getCols()) {
264 int rows = getRows();
265 for (
int i = 0; i < rows; i++) {
266 for (
int j = 0; j < i; j++) {
267 if (data[i][j] != data[j][i]) {
279 throw std::invalid_argument(
280 "Determinant is only defined for square matrices");
288 return data[0][0] * data[1][1] - data[0][1] * data[1][0];
292 auto [L, U] = LUDecomposition();
295 for (
int i = 0; i < rows; ++i) {
306 throw std::invalid_argument(
"Inverse is only defined for square matrices");
309 T det = determinant();
310 if (safe_abs(det) < 1e-12) {
311 throw std::runtime_error(
"Matrix is singular (determinant is zero)");
316 result[0][0] = T {1} / data[0][0];
322 T invDet = T {1} / det;
323 result(0, 0) = data[1][1] * invDet;
324 result(0, 1) = -data[0][1] * invDet;
325 result(1, 0) = -data[1][0] * invDet;
326 result(1, 1) = data[0][0] * invDet;
334 for (
int i = 0; i < rows; ++i) {
335 for (
int j = 0; j < cols; ++j) {
336 augmented(i, j) = data[i][j];
337 augmented(i, j + cols) = (i == j) ? T {1} : T {};
342 for (
int i = 0; i < rows; ++i) {
345 for (
int k = i + 1; k < rows; ++k) {
346 if (safe_abs(augmented(k, i)) > safe_abs(augmented(maxRow, i))) {
353 for (
int j = 0; j < 2 * cols; ++j) {
354 std::swap(augmented(i, j), augmented(maxRow, j));
359 T pivot = augmented(i, i);
360 if (safe_abs(pivot) < 1e-12) {
361 throw std::runtime_error(
"Matrix is singular");
364 for (
int j = 0; j < 2 * cols; ++j) {
365 augmented(i, j) /= pivot;
369 for (
int k = 0; k < rows; ++k) {
371 T factor = augmented(k, i);
372 for (
int j = 0; j < 2 * cols; ++j) {
373 augmented(k, j) -= factor * augmented(i, j);
381 for (
int i = 0; i < rows; ++i) {
382 for (
int j = 0; j < cols; ++j) {
383 result(i, j) = augmented(i, j + cols);
394 for (
int i = 0; i < rows; ++i) {
395 for (
int j = 0; j < cols; ++j) {
396 result(j, i) = data[i][j];
406 throw std::invalid_argument(
"Adjoint requires a square matrix.");
415 for (
int i = 0; i < rows; i++) {
416 for (
int j = 0; j < cols; j++) {
419 T cofactor = ((i + j) % 2 == 0) ? det : (det * (T(-1)));
420 adj(j, i) = cofactor;
430 throw std::invalid_argument(
431 "Eigenvalues are only defined for square matrices");
436 T trace = data[0][0] + data[1][1];
437 T det = data[0][0] * data[1][1] - data[0][1] * data[1][0];
438 T discriminant = trace * trace - T {4} * det;
440 std::vector<T> eigenvals(2);
441 if (discriminant >= 0) {
442 T sqrtDisc = safe_sqrt(discriminant);
443 eigenvals[0] = (trace + sqrtDisc) / T {2};
444 eigenvals[1] = (trace - sqrtDisc) / T {2};
447 eigenvals[0] = trace / T {2};
448 eigenvals[1] = trace / T {2};
455 std::vector<T> eigenvals;
458 const int maxIter = 1000;
459 const double tolerance = 1e-10;
461 for (
int ev = 0; ev < std::min(rows, 3);
463 std::vector<T> v(rows, T {1});
465 for (
int iter = 0; iter < maxIter; ++iter) {
466 std::vector<T> Av(rows, T {});
467 for (
int i = 0; i < rows; ++i) {
468 for (
int j = 0; j < cols; ++j) {
469 Av[i] += A(i, j) * v[j];
475 for (
int i = 0; i < rows; ++i) {
476 norm += Av[i] * Av[i];
478 norm = safe_sqrt(norm);
480 if (norm < tolerance) {
484 for (
int i = 0; i < rows; ++i) {
490 for (
int i = 0; i < rows; ++i) {
491 diff += (Av[i] - v[i]) * (Av[i] - v[i]);
496 if (safe_sqrt(diff) < tolerance) {
504 for (
int i = 0; i < rows; ++i) {
505 for (
int j = 0; j < cols; ++j) {
506 eigenval += v[i] * A(i, j) * v[j];
508 vNorm += v[i] * v[i];
511 eigenvals.push_back(eigenval);
514 for (
int i = 0; i < rows; ++i) {
515 for (
int j = 0; j < cols; ++j) {
516 A(i, j) -= eigenval * v[i] * v[j];
536 throw std::invalid_argument(
"LU decomposition requires a square matrix");
542 for (
int i = 0; i < rows - 1; ++i) {
543 for (
int j = i + 1; j < rows; ++j) {
544 if (safe_abs(U(i, i)) < 1e-12) {
545 throw std::runtime_error(
546 "Matrix is singular - cannot perform LU decomposition");
549 T factor = U(j, i) / U(i, i);
552 for (
int k = i; k < cols; ++k) {
553 U(j, k) -= factor * U(i, k);
569 for (
int j = 0; j < cols; ++j) {
571 std::vector<T> v(rows);
572 for (
int i = 0; i < rows; ++i) {
573 v[i] = (*this)(i, j);
577 for (
int k = 0; k < j; ++k) {
579 for (
int i = 0; i < rows; ++i) {
580 dot += Q(i, k) * v[i];
584 for (
int i = 0; i < rows; ++i) {
585 v[i] -= dot * Q(i, k);
591 for (
int i = 0; i < rows; ++i) {
594 norm = safe_sqrt(norm);
598 for (
int i = 0; i < rows; ++i) {
599 Q(i, j) = v[i] / norm;
603 for (
int i = 0; i < rows; ++i) {
614 return c.magnitude();
622 for (
int i = 0; i < rows; ++i) {
623 for (
int j = 0; j < cols; ++j) {
625 double val = abs(data[i][j]);
629 return std::sqrt(sum);
636 if (rows == 0 || cols == 0) {
643 double maxEigenval = 0.0;
644 for (
const auto& val : eigenvals) {
645 double absVal = getAbsoluteValue(val);
646 if (absVal > maxEigenval) {
647 maxEigenval = absVal;
651 return std::sqrt(maxEigenval);
657 if (rows <= 1 || cols <= 1) {
658 throw std::invalid_argument(
"Matrix too small for minor");
664 for (
int i = 0; i < rows; ++i) {
670 for (
int j = 0; j < cols; ++j) {
674 minor(minorRow, minorCol) = data[i][j];
686 std::ostringstream oss;
688 for (
int i = 0; i < rows; ++i) {
693 for (
int j = 0; j < cols; ++j) {
709 throw std::invalid_argument(
"Identity matrix size must be positive");
713 for (
int i = 0; i < n; ++i) {
714 result(i, i) = T {1};
723 std::vector<T> r(rows, 0);
724 for (
int i = 0; i < rows; ++i) {
725 for (
int j = 0; j < cols; ++j) {
726 r[i] += data[i][j] * v[j];
736 for (
int i = 0; i < a.size(); ++i) {
745 return std::sqrt((
double)dot(v, v));
769 if (row_start < 0 || row_end > rows || col_start < 0 || col_end > cols) {
770 throw std::out_of_range(
"Submatrix indices out of bounds");
772 if (row_start >= row_end || col_start >= col_end) {
773 throw std::invalid_argument(
"Invalid submatrix range");
776 int sub_rows = row_end - row_start;
777 int sub_cols = col_end - col_start;
781 for (
int i = 0; i < sub_rows; ++i) {
782 for (
int j = 0; j < sub_cols; ++j) {
783 result(i, j) = (*this)(row_start + i, col_start + j);
793 std::vector<T>& alpha,
794 std::vector<T>& beta,
802 std::vector<T> q(n, 1);
805 std::vector<T> q_prev(n, 0);
807 for (
int j = 0; j < m; ++j) {
811 for (
int i = 0; i < n; ++i) {
812 v[i] -= beta[j - 1] * q_prev[i];
815 alpha[j] = dot(q, v);
817 for (
int i = 0; i < n; ++i) {
818 v[i] -= alpha[j] * q[i];
822 for (
int i = 0; i < n; ++i) {
829 if (beta[j] < 1e-10) {
838 for (
int i = 0; i < n; ++i) {
839 q[i] = v[i] / beta[j];
848 const std::vector<T>& beta,
852 for (
int i = 0; i < m; ++i) {
855 Tm(i, i - 1) = beta[i - 1];
858 Tm(i, i + 1) = beta[i];
867 int m = std::min(rows, 20);
868 std::vector<T> alpha, beta;
871 lanczos(m, alpha, beta, Ql);
874 int actual_m = alpha.size();
875 Matrix<T> Tm = buildTridiagonal(alpha, beta, actual_m);
879 for (
int i = 0; i < 100; ++i) {
888 for (
int k = 0; k < actual_m; ++k) {
889 for (
int i = 0; i < rows; ++i) {
890 for (
int j = 0; j < actual_m; ++j) {
891 result(i, k) += Ql(i, j) * V(j, k);
901 if (r <= 0 || c <= 0) {
902 throw std::invalid_argument(
"Matrix dimensions must be positive");
911 if (r <= 0 || c <= 0) {
912 throw std::invalid_argument(
"Matrix dimensions must be positive");
916 for (
int i = 0; i < r; ++i) {
917 for (
int j = 0; j < c; ++j) {
918 result(i, j) = T {1};
A templated matrix class supporting various linear algebra operations.
Matrix< T > submatrix(int row_start, int row_end, int col_start, int col_end) const
Extracts a submatrix from specified row and column ranges.
Matrix< T > eigenvectors() const
Computes the eigenvectors of the matrix.
std::vector< T > matVec(const std::vector< T > &v) const
Performs matrix-vector multiplication.
T rank() const
Computes the rank of the matrix.
Matrix< T > getMinor(int row, int col) const
Gets the minor matrix by removing a specified row and column.
double norm(const std::vector< T > &v) const
Computes the Euclidean (L2) norm of a vector.
double spectralNorm() const
Computes the spectral norm (2-norm) of the matrix.
Matrix< T > operator*(const Matrix< T > &other) const
Matrix multiplication.
std::pair< Matrix< T >, Matrix< T > > QRDecomposition() const
Performs QR decomposition of the matrix using Gram-Schmidt orthogonalization.
void lanczos(int m, std::vector< T > &alpha, std::vector< T > &beta, Matrix< T > &Q) const
Performs the Lanczos algorithm for tridiagonalization.
Matrix< T > operator-(const Matrix< T > &other) const
Matrix subtraction.
std::string toString() const
Converts the matrix to a formatted string representation.
Matrix< T > transpose() const
Computes the transpose of the matrix.
T dot(const std::vector< T > &a, const std::vector< T > &b) const
Computes the dot product of two vectors.
double frobeniusNorm() const
Computes the Frobenius norm of the matrix.
Matrix< T > adjoint() const
Computes the adjoint (adjugate) matrix.
static Matrix< T > ones(int r, int c)
Creates an r × c matrix filled with ones.
void normalize(std::vector< T > &v) const
Normalizes a vector to unit length (in-place).
std::pair< Matrix< T >, Matrix< T > > LUDecomposition() const
Performs LU decomposition of the matrix.
Matrix()
Default constructor creating an empty 0×0 matrix.
Matrix< T > buildTridiagonal(const std::vector< T > &alpha, const std::vector< T > &beta, int m) const
Constructs a tridiagonal matrix from diagonal and off-diagonal elements.
static Matrix< T > zeros(int r, int c)
Creates an r × c matrix filled with zeros.
Matrix< T > inverse() const
Computes the inverse of the matrix.
std::vector< T > eigenvalues() const
Computes the eigenvalues of the matrix.
T & operator()(int row, int column)
Accesses matrix element at specified position (non-const).
Matrix< T > operator+(const Matrix< T > &other) const
Matrix addition.
static Matrix< T > identity(int n)
Creates an n × n identity matrix.
T determinant() const
Computes the determinant of the matrix.
bool isSymmetric() const
Checks if the matrix is symmetric.