19 #ifndef THEORETICA_ALGEBRA_H
20 #define THEORETICA_ALGEBRA_H
22 #include "../complex/complex_types.h"
23 #include "../core/core_traits.h"
24 #include "../core/error.h"
43 template<
typename Matrix>
48 for (
unsigned int i = 0; i < m.rows(); ++i)
49 for (
unsigned int j = 0; j < m.cols(); ++j)
50 m(i, j) = (Type) (i == j ?
nan() : 0);
61 template<
typename Vector>
66 for (
unsigned int i = 0; i < v.size(); ++i)
76 template<
typename Matrix>
81 for (
unsigned int i = 0; i < m.rows(); ++i)
82 for (
unsigned int j = 0; j < m.cols(); ++j)
83 m(i, j) = (Type) (i == j ? 1 : 0);
92 template<
typename Matrix>
97 for (
unsigned int i = 0; i < m.rows(); ++i)
98 for (
unsigned int j = 0; j < m.cols(); ++j)
108 template<
typename Vector>
113 for (
unsigned int i = 0; i < v.size(); ++i)
124 template<
typename Matrix1,
typename Matrix2>
125 inline Matrix1&
mat_copy(Matrix1& dest,
const Matrix2& src) {
127 dest.resize(src.rows(), src.cols());
129 for (
unsigned int i = 0; i < src.rows(); ++i)
130 for (
unsigned int j = 0; j < src.cols(); ++j)
131 dest(i, j) = src(i, j);
142 template<
typename Vector1,
typename Vector2>
143 inline Vector1&
vec_copy(Vector1& dest,
const Vector2& src) {
145 dest.resize(src.size());
147 for (
unsigned int i = 0; i < src.size(); ++i)
160 template<
typename Matrix>
161 inline Matrix&
mat_swap_rows(Matrix& A,
unsigned int row1,
unsigned int row2) {
165 if (row1 >= A.rows()) {
166 TH_MATH_ERROR(
"algebra::mat_swap_rows", row1, INVALID_ARGUMENT);
170 if (row2 >= A.rows()) {
171 TH_MATH_ERROR(
"algebra::mat_swap_rows", row2, INVALID_ARGUMENT);
178 for (
unsigned int j = 0; j < A.cols(); ++j) {
180 const Type tmp = A(row1, j);
182 A(row1, j) = A(row2, j);
196 template<
typename Matrix>
197 inline Matrix&
mat_swap_cols(Matrix& A,
unsigned int col1,
unsigned int col2) {
201 if (col1 >= A.cols()) {
202 TH_MATH_ERROR(
"algebra::mat_swap_cols", col1, INVALID_ARGUMENT);
206 if (col2 >= A.cols()) {
207 TH_MATH_ERROR(
"algebra::mat_swap_cols", col2, INVALID_ARGUMENT);
214 for (
unsigned int i = 0; i < A.cols(); ++i) {
216 const Type tmp = A(i, col1);
218 A(i, col1) = A(i, col2);
232 template<
typename Matrix,
typename Type = matrix_element_t<Matrix>>
235 const unsigned int count =
min(A.rows(), A.cols());
237 for (
unsigned int i = 0; i < count; ++i)
251 template<
typename Type>
263 template<
typename Type>
274 template<
typename Vector>
280 for (
unsigned int i = 1; i < v.size(); ++i)
291 template<
typename Vector>
292 inline auto norm(
const Vector& v) {
301 template<
typename Vector>
308 const auto m =
norm(v);
316 for (
unsigned int i = 0; i < r.size(); ++i)
326 template<
typename Vector>
329 const auto m =
norm(v);
337 for (
unsigned int i = 0; i < v.size(); ++i)
350 template<
typename Vector1,
typename Vector2>
351 inline auto dot(
const Vector1& v,
const Vector2& w) {
353 if(v.size() != w.size()) {
361 for (
unsigned int i = 1; i < v.size(); ++i)
372 template<
typename Vector1,
typename Vector2>
373 inline Vector1
cross(
const Vector1& v1,
const Vector2& v2) {
379 TH_MATH_ERROR(
"algebra::cross", v1.size(), INVALID_ARGUMENT);
385 TH_MATH_ERROR(
"algebra::cross", v2.size(), INVALID_ARGUMENT);
390 v3[0] = v1[1] * v2[2] - v1[2] * v2[1];
391 v3[1] = v1[2] * v2[0] - v1[0] * v2[2];
392 v3[2] = v1[0] * v2[1] - v1[1] * v2[0];
402 template<
typename Matrix,
typename MatrixT = Matrix>
406 res.resize(m.cols(), m.rows());
408 for (
unsigned int i = 0; i < m.rows(); ++i)
409 for (
unsigned int j = 0; j < m.cols(); ++j)
419 template<
typename Matrix>
422 if(m.rows() != m.cols()) {
423 TH_MATH_ERROR(
"algebra::make_transposed", m.rows(), INVALID_ARGUMENT);
428 for (
unsigned int i = 0; i < m.rows(); ++i) {
429 for (
unsigned int j = 0; j < i; ++j) {
431 const auto buff = m(i, j);
447 template<
typename Matrix1,
typename Matrix2>
448 inline Matrix1&
transpose(Matrix1& dest,
const Matrix2& src) {
452 if(src.rows() != dest.cols()) {
453 TH_MATH_ERROR(
"algebra::transpose", src.rows(), INVALID_ARGUMENT);
458 if(src.cols() != dest.rows()) {
459 TH_MATH_ERROR(
"algebra::transpose", src.cols(), INVALID_ARGUMENT);
465 for (
unsigned int i = 0; i < src.rows(); ++i)
466 for (
unsigned int j = 0; j < src.cols(); ++j)
467 dest(j, i) = src(i, j);
477 template<
typename Matrix,
typename MatrixT = Matrix>
481 res.resize(m.cols(), m.rows());
483 for (
unsigned int i = 0; i < m.rows(); ++i)
484 for (
unsigned int j = 0; j < m.cols(); ++j)
496 template<
typename Matrix>
499 if(m.rows() != m.cols()) {
500 TH_MATH_ERROR(
"algebra::hermitian", m.rows(), INVALID_ARGUMENT);
505 for (
unsigned int i = 0; i < m.rows(); ++i) {
506 for (
unsigned int j = 0; j < i; ++j) {
508 const auto buff = m(i, j);
525 template<
typename Matrix1,
typename Matrix2>
526 inline Matrix1&
hermitian(Matrix1& dest,
const Matrix2& src) {
530 if(src.rows() != dest.cols()) {
531 TH_MATH_ERROR(
"algebra::hermitian", src.rows(), INVALID_ARGUMENT);
536 if(src.cols() != dest.rows()) {
537 TH_MATH_ERROR(
"algebra::hermitian", src.cols(), INVALID_ARGUMENT);
543 for (
unsigned int i = 0; i < src.rows(); ++i)
544 for (
unsigned int j = 0; j < src.cols(); ++j)
554 template<
typename Matrix>
555 inline auto trace(
const Matrix& m) {
558 const size_t n =
min(m.rows(), m.cols());
560 for (
unsigned int i = 1; i < n; ++i)
572 template<
typename Matrix>
576 const size_t n =
min(m.rows(), m.cols());
578 for (
unsigned int i = 1; i < n; ++i)
589 template<
typename Field,
typename Matrix>
592 for (
unsigned int i = 0; i < m.rows(); ++i)
593 for (
unsigned int j = 0; j < m.cols(); ++j)
606 template<
typename Field,
typename Matrix1,
typename Matrix2>
607 inline Matrix1&
mat_scalmul(Matrix1& dest, Field a,
const Matrix2& src) {
609 if(src.rows() != dest.rows()) {
610 TH_MATH_ERROR(
"algebra::mat_scalmul", src.rows(), INVALID_ARGUMENT);
615 if(src.cols() != dest.cols()) {
616 TH_MATH_ERROR(
"algebra::mat_scalmul", src.cols(), INVALID_ARGUMENT);
621 for (
unsigned int i = 0; i < src.rows(); ++i)
622 for (
unsigned int j = 0; j < src.cols(); ++j)
623 dest(i, j) = a * src(i, j);
633 template<
typename Field,
typename Vector>
636 for (
unsigned int i = 0; i < v.size(); ++i)
649 template<
typename Field,
typename Vector1,
typename Vector2>
650 inline Vector1&
vec_scalmul(Vector1& dest, Field a,
const Vector2& src) {
652 if(src.size() != dest.size()) {
653 TH_MATH_ERROR(
"algebra::vec_scalmul", src.size(), INVALID_ARGUMENT);
658 for (
unsigned int i = 0; i < src.size(); ++i)
659 dest[i] = a * src[i];
674 template<
typename Matrix,
typename Vector>
677 if(v.size() != A.cols()) {
678 TH_MATH_ERROR(
"algebra::apply_transform", v.size(), INVALID_ARGUMENT);
684 res.resize(v.size());
687 for (
unsigned int i = 0; i < A.rows(); ++i)
688 for (
unsigned int j = 0; j < A.cols(); ++j)
689 res[i] += A(i, j) * v[j];
701 template<
typename Matrix,
typename Vector>
702 inline Vector
transform(
const Matrix& A,
const Vector& v) {
705 res.resize(v.size());
707 if(v.size() != A.cols()) {
708 TH_MATH_ERROR(
"algebra::transform", v.size(), INVALID_ARGUMENT);
715 for (
unsigned int i = 0; i < A.rows(); ++i)
716 for (
unsigned int j = 0; j < A.cols(); ++j)
717 res[i] += A(i, j) * v[j];
730 template<
typename Matrix,
typename Vector1,
typename Vector2>
731 inline Vector1&
transform(Vector1& res,
const Matrix& A,
const Vector2& v) {
733 if(v.size() != A.cols()) {
734 TH_MATH_ERROR(
"algebra::transform", v.size(), INVALID_ARGUMENT);
739 if(res.size() != v.size()) {
740 TH_MATH_ERROR(
"algebra::transform", res.size(), INVALID_ARGUMENT);
747 for (
unsigned int i = 0; i < A.rows(); ++i)
748 for (
unsigned int j = 0; j < A.cols(); ++j)
749 res[i] += A(i, j) * v[j];
763 template<
typename Matrix1,
typename Matrix2>
764 inline Matrix2&
mat_sum(Matrix1& A,
const Matrix2& B) {
766 if(A.rows() != B.rows()) {
767 TH_MATH_ERROR(
"algebra::mat_sum", A.rows(), INVALID_ARGUMENT);
772 if(A.cols() != B.cols()) {
773 TH_MATH_ERROR(
"algebra::mat_sum", A.cols(), INVALID_ARGUMENT);
778 for (
unsigned int i = 0; i < A.rows(); ++i)
779 for (
unsigned int j = 0; j < A.cols(); ++j)
780 A(i, j) = A(i, j) + B(i, j);
791 template<
typename Matrix1,
typename Matrix2,
typename Matrix3>
792 inline Matrix1&
mat_sum(Matrix1& res,
const Matrix2& A,
const Matrix3& B) {
794 if(A.rows() != B.rows()) {
795 TH_MATH_ERROR(
"algebra::mat_sum", A.rows(), INVALID_ARGUMENT);
800 if(A.cols() != B.cols()) {
801 TH_MATH_ERROR(
"algebra::mat_sum", A.cols(), INVALID_ARGUMENT);
806 if(res.rows() != A.rows()) {
807 TH_MATH_ERROR(
"algebra::mat_sum", res.rows(), INVALID_ARGUMENT);
812 if(res.cols() != A.cols()) {
813 TH_MATH_ERROR(
"algebra::mat_sum", res.cols(), INVALID_ARGUMENT);
818 for (
unsigned int i = 0; i < A.rows(); ++i)
819 for (
unsigned int j = 0; j < A.cols(); ++j)
820 res(i, j) = A(i, j) + B(i, j);
831 template<
typename Matrix1,
typename Matrix2>
832 inline Matrix2&
mat_diff(Matrix1& A,
const Matrix2& B) {
834 if(A.rows() != B.rows()) {
835 TH_MATH_ERROR(
"algebra::mat_diff", A.rows(), INVALID_ARGUMENT);
840 if(A.cols() != B.cols()) {
841 TH_MATH_ERROR(
"algebra::mat_diff", A.cols(), INVALID_ARGUMENT);
846 for (
unsigned int i = 0; i < A.rows(); ++i)
847 for (
unsigned int j = 0; j < A.cols(); ++j)
848 A(i, j) = A(i, j) - B(i, j);
859 template<
typename Matrix1,
typename Matrix2,
typename Matrix3>
860 inline Matrix1&
mat_diff(Matrix1& res,
const Matrix2& A,
const Matrix3& B) {
862 if(A.rows() != B.rows()) {
863 TH_MATH_ERROR(
"algebra::mat_diff", A.rows(), INVALID_ARGUMENT);
868 if(A.cols() != B.cols()) {
869 TH_MATH_ERROR(
"algebra::mat_diff", A.cols(), INVALID_ARGUMENT);
874 if(res.rows() != A.rows()) {
875 TH_MATH_ERROR(
"algebra::mat_diff", res.rows(), INVALID_ARGUMENT);
880 if(res.cols() != A.cols()) {
881 TH_MATH_ERROR(
"algebra::mat_diff", res.cols(), INVALID_ARGUMENT);
886 for (
unsigned int i = 0; i < A.rows(); ++i)
887 for (
unsigned int j = 0; j < A.cols(); ++j)
888 res(i, j) = A(i, j) - B(i, j);
900 template<
typename Field1,
typename Matrix1,
typename Field2,
typename Matrix2>
902 Field1 alpha, Matrix1& A, Field2
beta,
const Matrix2& B) {
904 if(A.rows() != B.rows()) {
905 TH_MATH_ERROR(
"algebra::mat_lincomb", A.rows(), INVALID_ARGUMENT);
910 if(A.cols() != B.cols()) {
911 TH_MATH_ERROR(
"algebra::mat_lincomb", A.cols(), INVALID_ARGUMENT);
916 for (
unsigned int i = 0; i < A.rows(); ++i)
917 for (
unsigned int j = 0; j < A.cols(); ++j)
918 A(i, j) = A(i, j) * alpha + B(i, j) *
beta;
933 template<
typename Matrix1,
typename Field1,
typename Matrix2,
934 typename Field2,
typename Matrix3>
936 Matrix1& res, Field1 alpha,
const Matrix2& A, Field2
beta,
const Matrix3& B) {
938 if(A.rows() != B.rows()) {
939 TH_MATH_ERROR(
"algebra::mat_lincomb", A.rows(), INVALID_ARGUMENT);
944 if(A.cols() != B.cols()) {
945 TH_MATH_ERROR(
"algebra::mat_lincomb", A.cols(), INVALID_ARGUMENT);
950 if(res.rows() != A.rows()) {
951 TH_MATH_ERROR(
"algebra::mat_lincomb", res.rows(), INVALID_ARGUMENT);
956 if(res.cols() != A.cols()) {
957 TH_MATH_ERROR(
"algebra::mat_lincomb", res.cols(), INVALID_ARGUMENT);
962 for (
unsigned int i = 0; i < A.rows(); ++i)
963 for (
unsigned int j = 0; j < A.cols(); ++j)
964 res(i, j) = A(i, j) * alpha + B(i, j) *
beta;
976 template<
typename Matrix1,
typename Matrix2,
typename Matrix3 = Matrix1>
977 inline Matrix3
mat_mul(
const Matrix1& A,
const Matrix2& B) {
980 R.resize(A.rows(), B.cols());
982 if(A.cols() != B.rows()) {
983 TH_MATH_ERROR(
"algebra::mat_mul", A.cols(), INVALID_ARGUMENT);
990 for (
unsigned int i = 0; i < A.rows(); ++i)
991 for (
unsigned int j = 0; j < B.cols(); ++j)
992 for (
unsigned int k = 0; k < A.cols(); ++k)
993 R(i, j) += A(i, k) * B(k, j);
1006 template<
typename Matrix1,
typename Matrix2,
typename Matrix3>
1007 inline Matrix1&
mat_mul(Matrix1& R,
const Matrix2& A,
const Matrix3& B) {
1009 if(R.rows() != A.rows()) {
1010 TH_MATH_ERROR(
"algebra::mat_mul", R.rows(), INVALID_ARGUMENT);
1015 if(R.cols() != B.cols()) {
1016 TH_MATH_ERROR(
"algebra::mat_mul", R.cols(), INVALID_ARGUMENT);
1021 if(A.cols() != B.rows()) {
1022 TH_MATH_ERROR(
"algebra::mat_mul", A.cols(), INVALID_ARGUMENT);
1029 for (
unsigned int i = 0; i < A.rows(); ++i)
1030 for (
unsigned int j = 0; j < B.cols(); ++j)
1031 for (
unsigned int k = 0; k < A.cols(); ++k)
1032 R(i, j) += A(i, k) * B(k, j);
1048 template<
typename Matrix1,
typename Matrix2,
typename Matrix3 = Matrix1>
1052 R.resize(A.cols(), B.cols());
1054 if(A.rows() != B.rows()) {
1055 TH_MATH_ERROR(
"algebra::mat_transpose_mul", A.rows(), INVALID_ARGUMENT);
1061 for (
unsigned int i = 0; i < R.rows(); ++i)
1062 for (
unsigned int j = 0; j < R.cols(); ++j)
1063 for (
unsigned int k = 0; k < A.rows(); ++k)
1064 R(i, j) += A(k, i) * B(k, j);
1080 template<
typename Matrix1,
typename Matrix2,
typename Matrix3 = Matrix1>
1084 R.resize(A.rows(), B.rows());
1086 if(A.cols() != B.cols()) {
1087 TH_MATH_ERROR(
"algebra::mat_mul_transpose", A.rows(), INVALID_ARGUMENT);
1093 for (
unsigned int i = 0; i < R.rows(); ++i)
1094 for (
unsigned int j = 0; j < R.cols(); ++j)
1095 for (
unsigned int k = 0; k < A.cols(); ++k)
1096 R(i, j) += A(i, k) * B(j, k);
1108 template<
typename Matrix1,
typename Matrix2>
1112 if(A.rows() != B.rows() || A.cols() != B.cols())
1115 for (
unsigned int i = 0; i < A.rows(); ++i) {
1116 for (
unsigned int j = 0; j < A.cols(); ++j) {
1118 const auto diff =
abs(A(i, j) - B(i, j));
1120 if(diff > tolerance ||
is_nan(diff))
1134 template<
typename Vector1,
typename Vector2>
1135 inline Vector2&
vec_sum(Vector1& v1,
const Vector2& v2) {
1137 if(v1.size() != v2.size()) {
1138 TH_MATH_ERROR(
"algebra::vec_sum", v1.size(), INVALID_ARGUMENT);
1143 for (
unsigned int i = 0; i < v1.size(); ++i)
1144 v1[i] = v1[i] + v2[i];
1155 template<
typename Vector1,
typename Vector2,
typename Vector3>
1156 inline Vector1&
vec_sum(Vector1& res,
const Vector2& v1,
const Vector3& v2) {
1158 if(v1.size() != v2.size()) {
1159 TH_MATH_ERROR(
"algebra::vec_sum", v1.size(), INVALID_ARGUMENT);
1164 if(res.size() != v1.size()) {
1165 TH_MATH_ERROR(
"algebra::vec_sum", res.size(), INVALID_ARGUMENT);
1170 for (
unsigned int i = 0; i < v1.size(); ++i)
1171 res[i] = v1[i] + v2[i];
1182 template<
typename Vector1,
typename Vector2>
1183 inline Vector2&
vec_diff(Vector1& v1,
const Vector2& v2) {
1185 if(v1.size() != v2.size()) {
1186 TH_MATH_ERROR(
"algebra::vec_diff", v1.size(), INVALID_ARGUMENT);
1191 for (
unsigned int i = 0; i < v1.size(); ++i)
1192 v1[i] = v1[i] - v2[i];
1203 template<
typename Vector1,
typename Vector2,
typename Vector3>
1204 inline Vector1&
vec_diff(Vector1& res,
const Vector2& v1,
const Vector3& v2) {
1206 if(v1.size() != v2.size()) {
1207 TH_MATH_ERROR(
"algebra::vec_diff", v1.size(), INVALID_ARGUMENT);
1212 if(res.size() != v1.size()) {
1213 TH_MATH_ERROR(
"algebra::vec_diff", res.size(), INVALID_ARGUMENT);
1218 for (
unsigned int i = 0; i < v1.size(); ++i)
1219 res[i] = v1[i] - v2[i];
1231 template<
typename Matrix>
1233 return (m.rows() == m.cols());
1242 template<
typename Matrix>
1245 for (
unsigned int i = 0; i < m.rows(); ++i)
1246 for (
unsigned int j = 0; j < m.cols(); ++j)
1247 if(i != j &&
abs(m(i, j)) > tolerance)
1258 template<
typename Matrix>
1264 for (
unsigned int i = 0; i < m.rows(); ++i)
1265 for (
unsigned int j = 0; j < m.cols(); ++j)
1266 if(
abs(m(i, j) - m(j, i)) > tolerance)
1278 template<
typename Matrix>
1284 for (
unsigned int i = 0; i < m.rows(); ++i)
1285 for (
unsigned int j = i + 1; j < m.cols(); ++j)
1286 if (
abs(m(i, j)) > tolerance)
1298 template<
typename Matrix>
1304 for (
unsigned int i = 0; i < m.rows(); ++i)
1305 for (
unsigned int j = 0; j < i; ++j)
1306 if (
abs(m(i, j)) > tolerance)
1322 template<
typename Matrix, enable_matrix<Matrix> = true>
1325 long unsigned int n = 0;
1327 for (
unsigned int i = 0; i < A.rows(); ++i)
1328 for (
unsigned int j = 0; j < A.cols(); ++j)
1329 if (
abs(A(i, j)) > tolerance)
1332 return (
real(n) / A.rows()) / A.cols();
1345 template<
typename Matrix, enable_matrix<Matrix> = true>
1348 return 1.0 -
density(A, tolerance);
1362 template<
typename Matrix1,
typename Matrix2,
typename Matrix3>
1366 unsigned int err = 0;
1369 L.resize(A.rows(), A.cols());
1370 U.resize(A.rows(), A.cols());
1375 if (A.rows() != L.rows())
1378 if (A.cols() != L.cols())
1381 if (A.rows() != U.rows())
1384 if (A.cols() != U.cols())
1388 TH_MATH_ERROR(
"algebra::decompose_lu", err, INVALID_ARGUMENT);
1396 for (
unsigned int i = 0; i < A.rows(); ++i)
1397 L(i, i) = (Type) 1.0;
1400 for(
unsigned int i = 0; i < A.rows(); ++i) {
1402 for(
unsigned int j = 0; j < A.rows(); ++j) {
1406 for(
unsigned int k = 0; k < i; ++k)
1410 for(
unsigned int j = i + 1; j < A.rows(); ++j) {
1414 for(
unsigned int k = 0; k < i; ++k)
1431 template<
typename Matrix>
1435 TH_MATH_ERROR(
"algebra::decompose_lu_inplace", A.rows(), INVALID_ARGUMENT);
1440 for(
unsigned int j = 0; j < A.cols(); ++j) {
1442 for(
unsigned int i = j + 1; i < A.rows(); ++i) {
1446 for(
unsigned int k = j + 1; k < A.rows(); ++k)
1461 template<
typename Matrix>
1465 L.resize(A.rows(), A.cols());
1469 TH_MATH_ERROR(
"algebra::decompose_cholesky", A.rows(), INVALID_ARGUMENT);
1474 TH_MATH_ERROR(
"algebra::decompose_cholesky",
false, INVALID_ARGUMENT);
1480 for (
unsigned int i = 0; i < A.cols(); ++i) {
1482 for (
unsigned int j = 0; j <= i; ++j) {
1486 for (
unsigned int k = 1; k < j; ++k)
1491 const Type sqr_diag = A(j, j) -
sum;
1495 TH_MATH_ERROR(
"algebra::decompose_cholesky", sqr_diag, INVALID_ARGUMENT);
1499 L(i, j) =
sqrt(sqr_diag);
1503 L(i, j) = (A(i, j) -
sum) / L(j, j);
1517 template<
typename Matrix>
1523 TH_MATH_ERROR(
"algebra::decompose_cholesky_inplace", A.rows(), INVALID_ARGUMENT);
1528 TH_MATH_ERROR(
"algebra::decompose_cholesky_inplace",
false, INVALID_ARGUMENT);
1533 for (
unsigned int k = 0; k < A.rows(); ++k) {
1535 A(k, k) =
sqrt(A(k, k));
1537 for (
unsigned int i = k + 1; i < A.rows(); ++i)
1538 A(i, k) = A(i, k) / A(k, k);
1540 for (
unsigned int j = k + 1; j < A.rows(); ++j)
1541 for (
unsigned int i = j; i < A.cols(); ++i)
1546 for (
unsigned int i = 0; i < A.rows(); ++i)
1547 for (
unsigned int j = i + 1; j < A.rows(); ++j)
1548 A(i, j) = Type(0.0);
1563 template<
typename Matrix,
typename Vector>
1571 TH_MATH_ERROR(
"algebra::solve_triangular_lower",
false, INVALID_ARGUMENT);
1575 if (b.size() != L.rows()) {
1576 TH_MATH_ERROR(
"algebra::solve_triangular_lower", b.size(), INVALID_ARGUMENT);
1581 for (
unsigned int i = 0; i < L.cols(); ++i) {
1583 Type
sum = L(i, 0) * x[0];
1585 for (
unsigned int j = 1; j < i; ++j)
1586 sum += L(i, j) * x[j];
1589 TH_MATH_ERROR(
"algebra::solve_triangular_lower", L(i, i), DIV_BY_ZERO);
1593 x[i] = (b[i] -
sum) / L(i, i);
1605 template<
typename Matrix,
typename Vector>
1613 TH_MATH_ERROR(
"solve_triangular_upper",
false, INVALID_ARGUMENT);
1617 if (b.size() != U.rows()) {
1618 TH_MATH_ERROR(
"solve_triangular_upper", b.size(), INVALID_ARGUMENT);
1622 if (U.rows() == 1) {
1623 x[0] = b[0] / U(0, 0);
1628 for (
int i = U.rows() - 1; i >= 0; --i) {
1630 Type
sum = U(i, i + 1) * x[i + 1];
1632 for (
unsigned int j = i + 2; j < U.cols(); ++j)
1633 sum += U(i, j) * x[j];
1636 TH_MATH_ERROR(
"solve_triangular_upper", U(i, i), DIV_BY_ZERO);
1640 x[i] = (b[i] -
sum) / U(i, i);
1654 template<
typename Matrix,
typename Vector>
1664 err.resize(b.size());
1680 template<
typename Matrix,
typename Vector>
1684 TH_MATH_ERROR(
"algebra::solve_lu_inplace", A.rows(), INVALID_ARGUMENT);
1688 if (A.rows() != b.size()) {
1689 TH_MATH_ERROR(
"algebra::solve_lu_inplace", A.rows(), INVALID_ARGUMENT);
1696 for (
unsigned int i = 1; i < A.rows(); ++i) {
1698 Type
sum = Type(0.0);
1700 for (
unsigned int j = 0; j < i; ++j)
1701 sum += A(i, j) * b[j];
1707 for (
int i = A.rows() - 1; i >= 0; --i) {
1709 Type
sum = Type(0.0);
1711 for (
unsigned int j = i + 1; j < A.rows(); ++j)
1712 sum += A(i, j) * b[j];
1714 b[i] = (b[i] -
sum) / A(i, i);
1728 template<
typename Matrix,
typename Vector>
1749 template<
typename Matrix1,
typename Matrix2,
typename Vector>
1750 inline Vector
solve_lu(
const Matrix1& L,
const Matrix2& U,
const Vector& b) {
1755 TH_MATH_ERROR(
"algebra::solve_lu", L.rows(), INVALID_ARGUMENT);
1760 TH_MATH_ERROR(
"algebra::solve_lu", U.rows(), INVALID_ARGUMENT);
1764 if (L.rows() != U.rows()) {
1765 TH_MATH_ERROR(
"algebra::solve_lu", U.rows(), INVALID_ARGUMENT);
1769 if (b.size() != L.rows()) {
1770 TH_MATH_ERROR(
"algebra::solve_lu", b.size(), INVALID_ARGUMENT);
1777 for (
unsigned int i = 1; i < L.rows(); ++i) {
1779 Type1
sum = Type1(0.0);
1781 for (
unsigned int j = 0; j < i; ++j)
1782 sum += L(i, j) * x[j];
1790 for (
int i = U.rows() - 1; i >= 0; --i) {
1792 Type2
sum = Type2(0.0);
1794 for (
unsigned int j = i + 1; j < U.rows(); ++j)
1795 sum += U(i, j) * x[j];
1802 x[i] = (x[i] -
sum) / U(i, i);
1817 template<
typename Matrix,
typename Vector>
1823 TH_MATH_ERROR(
"algebra::solve_cholesky", L.rows(), INVALID_ARGUMENT);
1827 if (L.rows() != b.size()) {
1828 TH_MATH_ERROR(
"algebra::solve_cholesky", b.size(), INVALID_ARGUMENT);
1835 for (
unsigned int i = 0; i < L.rows(); ++i) {
1837 Type
sum = Type(0.0);
1839 for (
unsigned int j = 0; j < i; ++j)
1840 sum += L(i, j) * x[j];
1842 x[i] = (x[i] -
sum) / L(i, i);
1846 for (
int i = L.rows() - 1; i >= 0; --i) {
1848 Type
sum = Type(0.0);
1850 for (
unsigned int j = i + 1; j < L.rows(); ++j)
1851 sum += L(j, i) * x[j];
1853 x[i] = (x[i] -
sum) / L(i, i);
1866 template<
typename Matrix,
typename Vector>
1867 inline Vector
solve(
const Matrix& A,
const Vector& b) {
1882 template<
typename Matrix1,
typename Matrix2>
1883 inline Matrix1&
inverse(Matrix1& dest,
const Matrix2& src) {
1885 if(src.rows() != src.cols()) {
1886 TH_MATH_ERROR(
"algebra::inverse", src.rows(), INVALID_ARGUMENT);
1891 if(dest.rows() != src.rows()) {
1892 TH_MATH_ERROR(
"algebra::inverse", dest.rows(), INVALID_ARGUMENT);
1897 if(dest.cols() != src.cols()) {
1898 TH_MATH_ERROR(
"algebra::inverse", dest.cols(), INVALID_ARGUMENT);
1907 A.resize(src.rows(), src.cols());
1908 dest.resize(src.rows(), src.cols());
1913 for (
unsigned int i = 0; i < src.rows(); ++i) {
1917 if(A(i, i) == (Type) 0) {
1922 for (
unsigned int j = i + 1; j < src.rows(); ++j) {
1926 if(A(j, i) != (Type) 0) {
1928 for (
unsigned int k = 0; k < src.rows(); ++k) {
1930 dest(i, k) += dest(j, k);
1939 TH_MATH_ERROR(
"algebra::inverse", flag, IMPOSSIBLE_OPERATION);
1945 auto inv_pivot = ((Type) 1.0) / A(i, i);
1949 for (
unsigned int j = 0; j < src.rows(); ++j) {
1957 const auto coeff = A(j, i) * inv_pivot;
1959 for (
unsigned int k = 0; k < src.rows(); ++k) {
1960 A(j, k) -= coeff * A(i, k);
1961 dest(j, k) -= coeff * dest(i, k);
1966 for (
unsigned int j = 0; j < src.rows(); ++j) {
1967 A(i, j) *= inv_pivot;
1968 dest(i, j) *= inv_pivot;
1982 template<
typename Matrix,
typename MatrixInv = Matrix>
1985 res.resize(m.rows(), m.cols());
1996 template<
typename Matrix>
1999 if(m.rows() != m.cols()) {
2000 TH_MATH_ERROR(
"algebra::invert", m.rows(), INVALID_ARGUMENT);
2007 tmp.resize(m.rows(), m.cols());
2023 template<
typename Matrix>
2024 inline auto det(
const Matrix& A) {
2045 template<
typename Matrix,
typename Vector>
2048 const auto p =
dot(x, x);
2071 template<
typename Matrix,
typename Vector>
2073 const Matrix& A,
const Vector& x,
2083 if (x.size() != A.rows()) {
2084 TH_MATH_ERROR(
"eigenvalue_power", x.size(), INVALID_ARGUMENT);
2097 for (i = 1; i <= max_iter; ++i) {
2104 if (
norm(x_curr - x_prev) <= tolerance ||
2105 norm(x_curr + x_prev) <= tolerance)
2115 return dot(x_curr, A * x_curr);
2132 template<
typename Matrix,
typename Vector1,
typename Vector2 = Vector1>
2134 const Matrix& A,
const Vector1& x, Vector2& v,
2144 if (x.size() != A.rows()) {
2145 TH_MATH_ERROR(
"eigenpair_power", x.size(), INVALID_ARGUMENT);
2149 if (v.size() != x.size()) {
2150 TH_MATH_ERROR(
"eigenpair_power", v.size(), INVALID_ARGUMENT);
2163 for (i = 1; i <= max_iter; ++i) {
2170 if (
norm(x_curr - x_prev) <= tolerance ||
2171 norm(x_curr + x_prev) <= tolerance)
2184 return dot(x_curr, A * x_curr);
2199 template<
typename Matrix,
typename Vector>
2201 const Matrix& A,
const Vector& x,
2212 if (A.rows() != x.size()) {
2213 TH_MATH_ERROR(
"eigenvalue_inverse", x.size(), INVALID_ARGUMENT);
2223 Vector x_curr = x_prev;
2229 for (i = 1; i <= max_iter; ++i) {
2237 if (
norm(x_curr - x_prev) <= tolerance ||
2238 norm(x_curr + x_prev) <= tolerance)
2244 TH_MATH_ERROR(
"eigenvalue_inverse", i, NO_ALGO_CONVERGENCE);
2249 return dot(x_curr, A * x_curr);
2266 template<
typename Matrix,
typename Vector1,
typename Vector2>
2268 const Matrix& A,
const Vector1& x, Vector2& v,
2278 if (A.rows() != x.size()) {
2279 TH_MATH_ERROR(
"eigenpair_inverse", x.size(), INVALID_ARGUMENT);
2289 Vector1 x_curr = x_prev;
2295 for (i = 1; i <= max_iter; ++i) {
2303 if (
norm(x_curr - x_prev) <= tolerance ||
2304 norm(x_curr + x_prev) <= tolerance)
2318 return dot(x_curr, A * x_curr);
2338 template<
typename Matrix,
typename Vector,
typename T = matrix_element_t<Matrix>>
2340 const Matrix& A,
const T& lambda,
const Vector& x,
2349 if (A.rows() != x.size()) {
2350 TH_MATH_ERROR(
"eigenvector_inverse", x.size(), INVALID_ARGUMENT);
2364 Vector v_curr = v_prev;
2370 for (i = 1; i <= max_iter; ++i) {
2378 if (
norm(v_curr - v_prev) <= tolerance ||
2379 norm(v_curr + v_prev) <= tolerance)
2385 TH_MATH_ERROR(
"eigenvector_inverse", i, NO_ALGO_CONVERGENCE);
2406 template<
typename Matrix,
typename Vector,
typename T = matrix_element_t<Matrix>>
2408 const Matrix& A,
const T& lambda,
const Vector& x,
2418 if (A.rows() != x.size()) {
2419 TH_MATH_ERROR(
"eigenvalue_rayleigh", x.size(), INVALID_ARGUMENT);
2427 Type lambda_prev = lambda;
2428 Type lambda_curr = lambda;
2435 for (i = 1; i <= max_iter; ++i) {
2439 lambda_prev = lambda_curr;
2453 if (
norm(x_curr - x_prev) <= tolerance ||
2454 norm(x_curr + x_prev) <= tolerance)
2459 TH_MATH_ERROR(
"eigenvalue_rayleigh", i, NO_ALGO_CONVERGENCE);
2482 template<
typename Matrix,
typename Vector1,
typename Vector2,
2485 const Matrix& A,
const T& lambda,
const Vector1& x, Vector2& v,
2495 if (A.rows() != x.size()) {
2496 TH_MATH_ERROR(
"eigenpair_rayleigh", x.size(), INVALID_ARGUMENT);
2504 Type lambda_prev = lambda;
2505 Type lambda_curr = lambda;
2512 for (i = 1; i <= max_iter; ++i) {
2516 lambda_prev = lambda_curr;
2530 if (
norm(x_curr - x_prev) <= tolerance ||
2531 norm(x_curr + x_prev) <= tolerance)
2536 TH_MATH_ERROR(
"eigenpair_rayleigh", i, NO_ALGO_CONVERGENCE);
Complex number in algebraic form .
Definition: complex.h:26
#define TH_MATH_ERROR(F_NAME, VALUE, EXCEPTION)
TH_MATH_ERROR is a macro which throws exceptions or modifies errno (depending on which compiling opti...
Definition: error.h:219
Matrix2 & mat_lincomb(Field1 alpha, Matrix1 &A, Field2 beta, const Matrix2 &B)
Compute the linear combination of two matrices and store the result in the first matrix.
Definition: algebra.h:901
bool is_lower_triangular(const Matrix &m, real tolerance=ALGEBRA_ELEMENT_TOL)
Returns whether the matrix is lower triangular.
Definition: algebra.h:1279
Matrix & mat_zeroes(Matrix &m)
Overwrite a matrix with all zeroes.
Definition: algebra.h:93
Vector1 cross(const Vector1 &v1, const Vector2 &v2)
Compute the cross product between two tridimensional vectors.
Definition: algebra.h:373
Matrix & make_identity(Matrix &m)
Overwrite a matrix with the identity matrix.
Definition: algebra.h:77
Matrix3 mat_transpose_mul(const Matrix1 &A, const Matrix2 &B)
Multiply the transpose of a matrix by another matrix, equivalent to the operation .
Definition: algebra.h:1049
auto eigenpair_power(const Matrix &A, const Vector1 &x, Vector2 &v, real tolerance=ALGEBRA_EIGEN_TOL, unsigned int max_iter=ALGEBRA_EIGEN_ITER)
Find the biggest eigenvalue in module of a square matrix and its corresponding eigenvector (eigenpai...
Definition: algebra.h:2133
Matrix & make_transposed(Matrix &m)
Transpose the given matrix.
Definition: algebra.h:420
Matrix & make_hermitian(Matrix &m)
Compute the hermitian of a given matrix and overwrite it.
Definition: algebra.h:497
Vector & make_normalized(Vector &v)
Normalize a given vector overwriting it.
Definition: algebra.h:327
Matrix & decompose_lu_inplace(Matrix &A)
Decompose a square matrix to two triangular matrices, L and U where L is lower and U is upper,...
Definition: algebra.h:1432
bool is_square(const Matrix &m)
Returns whether the matrix is square.
Definition: algebra.h:1232
Matrix & mat_shift_diagonal(Matrix &A, const Type &sigma)
Shift the diagonal of a matrix by the given amount, overwriting the matrix itself,...
Definition: algebra.h:233
auto eigenvalue_power(const Matrix &A, const Vector &x, real tolerance=ALGEBRA_EIGEN_TOL, unsigned int max_iter=ALGEBRA_EIGEN_ITER)
Find the biggest eigenvalue in module of a square matrix using the power method (Von Mises iteration...
Definition: algebra.h:2072
auto trace(const Matrix &m)
Compute the trace of the given matrix.
Definition: algebra.h:555
auto eigenpair_inverse(const Matrix &A, const Vector1 &x, Vector2 &v, real tolerance=ALGEBRA_EIGEN_TOL, unsigned int max_iter=ALGEBRA_EIGEN_ITER)
Find the eigenvalue with the smallest inverse of a square matrix and its corresponding eigenvector,...
Definition: algebra.h:2267
Vector2 & vec_sum(Vector1 &v1, const Vector2 &v2)
Sum two vectors and store the result in the first vector.
Definition: algebra.h:1135
bool is_symmetric(const Matrix &m, real tolerance=ALGEBRA_ELEMENT_TOL)
Returns whether the matrix is symmetric.
Definition: algebra.h:1259
Vector solve(const Matrix &A, const Vector &b)
Solve the linear system , finding using the best available algorithm.
Definition: algebra.h:1867
bool mat_equals(const Matrix1 &A, const Matrix2 &B, real tolerance=10 *MACH_EPSILON)
Checks whether two matrices are equal.
Definition: algebra.h:1109
Vector & vec_error(Vector &v)
Overwrite the given vector with the error vector with NaN values.
Definition: algebra.h:62
Matrix & mat_scalmul(Field a, Matrix &m)
Multiply a matrix by a scalar of any compatible type.
Definition: algebra.h:590
Vector transform(const Matrix &A, const Vector &v)
Returns the matrix transformation of a vector.
Definition: algebra.h:702
bool is_upper_triangular(const Matrix &m, real tolerance=ALGEBRA_ELEMENT_TOL)
Returns whether the matrix is upper triangular.
Definition: algebra.h:1299
bool is_diagonal(const Matrix &m, real tolerance=10 *MACH_EPSILON)
Returns whether the matrix is diagonal.
Definition: algebra.h:1243
real density(const Matrix &A, real tolerance=1E-12)
Compute the density of a matrix, counting the proportion of non-zero (bigger in module than the given...
Definition: algebra.h:1323
Vector eigenvector_inverse(const Matrix &A, const T &lambda, const Vector &x, real tolerance=ALGEBRA_EIGEN_TOL, unsigned int max_iter=ALGEBRA_EIGEN_ITER)
Find the eigenvector associated with a given approximated eigenvalue using the inverse power method.
Definition: algebra.h:2339
void decompose_lu(const Matrix1 &A, Matrix2 &L, Matrix3 &U)
Decompose a square matrix to two triangular matrices, L and U where L is lower and U is upper,...
Definition: algebra.h:1363
Matrix2 & mat_sum(Matrix1 &A, const Matrix2 &B)
Sum two matrices and store the result in the first matrix.
Definition: algebra.h:764
Vector solve_lu(Matrix A, Vector b)
Solve the linear system , finding .
Definition: algebra.h:1729
real sparsity(const Matrix &A, real tolerance=1E-12)
Compute the sparsity of a matrix, counting the proportion of zero (smaller in module than the given t...
Definition: algebra.h:1346
Vector solve_triangular(const Matrix &T, const Vector &b)
Solve the linear system for triangular .
Definition: algebra.h:1655
Matrix decompose_cholesky(const Matrix &A)
Decompose a symmetric positive definite matrix into a triangular matrix so that using Cholesky decom...
Definition: algebra.h:1462
auto dot(const Vector1 &v, const Vector2 &w)
Computes the dot product between two vectors, using the Hermitian form if needed.
Definition: algebra.h:351
Matrix3 mat_mul(const Matrix1 &A, const Matrix2 &B)
Multiply two matrices and store the result in the first matrix, equivalent to the operation .
Definition: algebra.h:977
Matrix1 & mat_copy(Matrix1 &dest, const Matrix2 &src)
Copy a matrix by overwriting another.
Definition: algebra.h:125
auto pair_inner_product(const Type &v_i, const Type &w_i)
Compute the contribution of the inner product between a pair of elements of two vectors,...
Definition: algebra.h:252
auto diagonal_product(const Matrix &m)
Compute the product of the elements of the main diagonal of a generic matrix.
Definition: algebra.h:573
auto eigenvalue_rayleigh(const Matrix &A, const T &lambda, const Vector &x, real tolerance=ALGEBRA_EIGEN_TOL, unsigned int max_iter=ALGEBRA_EIGEN_ITER)
Compute an eigenvalue of a square matrix using the Rayleigh quotient iteration method.
Definition: algebra.h:2407
Matrix & mat_error(Matrix &m)
Overwrite the given matrix with the error matrix with NaN values on the diagonal and zeroes everywher...
Definition: algebra.h:44
auto eigenpair_rayleigh(const Matrix &A, const T &lambda, const Vector1 &x, Vector2 &v, real tolerance=ALGEBRA_EIGEN_TOL, unsigned int max_iter=ALGEBRA_EIGEN_ITER)
Compute an eigenvalue of a square matrix and its corresponding eigenvector (eigenpair) using the Rayl...
Definition: algebra.h:2484
auto rayleigh_quotient(const Matrix &A, const Vector &x)
Compute the Rayleigh quotient of a vector with respect to a matrix.
Definition: algebra.h:2046
auto sqr_norm(const Vector &v)
Returns the square of the Euclidean/Hermitian norm of the given vector.
Definition: algebra.h:275
auto det(const Matrix &A)
Compute the determinant of a square matrix.
Definition: algebra.h:2024
Matrix & invert(Matrix &m)
Invert the given matrix and overwrite it.
Definition: algebra.h:1997
Vector solve_triangular_lower(const Matrix &L, const Vector &b)
Solve the linear system for lower triangular .
Definition: algebra.h:1564
Matrix1 & inverse(Matrix1 &dest, const Matrix2 &src)
Invert the given matrix.
Definition: algebra.h:1883
Matrix3 mat_mul_transpose(const Matrix1 &A, const Matrix2 &B)
Multiply a matrix by the transpose of another matrix, equivalent to the operation .
Definition: algebra.h:1081
Matrix2 & mat_diff(Matrix1 &A, const Matrix2 &B)
Subtract two matrices and store the result in the first matrix.
Definition: algebra.h:832
MatrixT hermitian(const Matrix &m)
Returns the hermitian of the given matrix.
Definition: algebra.h:478
Vector & vec_scalmul(Field a, Vector &v)
Multiply a vector by a scalar of any compatible type.
Definition: algebra.h:634
Vector solve_triangular_upper(const Matrix &U, const Vector &b)
Solve the linear system for upper triangular .
Definition: algebra.h:1606
Vector & apply_transform(const Matrix &A, Vector &v)
Apply a matrix transformation to a vector and store the result in the vector.
Definition: algebra.h:675
Vector & solve_lu_inplace(const Matrix &A, Vector &b)
Solve the linear system , finding , where the matrix A has already undergone in-place LU decompositio...
Definition: algebra.h:1681
Vector1 & vec_copy(Vector1 &dest, const Vector2 &src)
Copy a vector by overwriting another.
Definition: algebra.h:143
Vector2 & vec_diff(Vector1 &v1, const Vector2 &v2)
Subtract two vectors and store the result in the first vector.
Definition: algebra.h:1183
Vector & vec_zeroes(Vector &v)
Overwrite a vector with all zeroes.
Definition: algebra.h:109
Matrix & decompose_cholesky_inplace(Matrix &A)
Decompose a symmetric positive definite matrix in-place, overwriting the starting matrix,...
Definition: algebra.h:1518
Vector solve_cholesky(const Matrix &L, const Vector &b)
Solve a linear system defined by a symmetric positive definite matrix, using the Cholesky decomposit...
Definition: algebra.h:1818
Matrix & mat_swap_cols(Matrix &A, unsigned int col1, unsigned int col2)
Swap two columns of a matrix, given the matrix and the two indices of the columns.
Definition: algebra.h:197
auto norm(const Vector &v)
Returns the Euclidean/Hermitian norm of the given vector.
Definition: algebra.h:292
Matrix & mat_swap_rows(Matrix &A, unsigned int row1, unsigned int row2)
Swap two rows of a matrix, given the matrix and the two indices of the rows.
Definition: algebra.h:161
Vector normalize(const Vector &v)
Returns the normalized vector.
Definition: algebra.h:302
auto eigenvalue_inverse(const Matrix &A, const Vector &x, real tolerance=ALGEBRA_EIGEN_TOL, unsigned int max_iter=ALGEBRA_EIGEN_ITER)
Find the eigenvalue with the smallest inverse of a square matrix, using the inverse power method wit...
Definition: algebra.h:2200
MatrixT transpose(const Matrix &m)
Returns the transpose of the given matrix.
Definition: algebra.h:403
real beta(real x1, real x2)
Beta special function of real argument.
Definition: special.h:141
Main namespace of the library which contains all functions and objects.
Definition: algebra.h:27
double real
A real number, defined as a floating point type.
Definition: constants.h:188
auto min(const Vector &X)
Finds the minimum value inside a dataset.
Definition: dataset.h:351
dual2 sqrt(dual2 x)
Compute the square root of a second order dual number.
Definition: dual2_functions.h:54
bool is_nan(const T &x)
Check whether a generic variable is (equivalent to) a NaN number.
Definition: error.h:70
dual2 abs(dual2 x)
Compute the absolute value of a second order dual number.
Definition: dual2_functions.h:183
std::remove_reference_t< decltype(std::declval< Structure >()(0, 0))> matrix_element_t
Extract the type of a matrix (or any doubly indexable container) from its operator().
Definition: core_traits.h:140
std::remove_reference_t< decltype(std::declval< Structure >()[0])> vector_element_t
Extract the type of a vector (or any indexable container) from its operator[].
Definition: core_traits.h:134
constexpr real ALGEBRA_ELEMENT_TOL
Tolerance for the elements of matrices.
Definition: constants.h:260
auto sum(const Vector &X)
Compute the sum of a vector of real values using pairwise summation to reduce round-off error.
Definition: dataset.h:219
dual2 conjugate(dual2 x)
Return the conjugate of a second order dual number.
Definition: dual2_functions.h:35
constexpr real MACH_EPSILON
Machine epsilon for the real type.
Definition: constants.h:197
constexpr real E
The Euler mathematical constant (e)
Definition: constants.h:227
constexpr real ALGEBRA_EIGEN_ITER
Maximum number of iterations for eigensolvers.
Definition: constants.h:266
real nan()
Return a quiet NaN number in floating point representation.
Definition: error.h:54
constexpr real ALGEBRA_EIGEN_TOL
Tolerance for eigensolvers.
Definition: constants.h:263