UFO 1.0.0
An Efficient Probabilistic 3D Mapping Framework That Embraces the Unknown
Loading...
Searching...
No Matches
mat.hpp
1
41#ifndef UFO_NUMERIC_MAT_HPP
42#define UFO_NUMERIC_MAT_HPP
43
44// UFO
45#include <ufo/numeric/vec.hpp>
46
47// STL
48#include <algorithm>
49#include <array>
50#include <cmath>
51#include <concepts>
52#include <cstddef>
53#include <format>
54#include <functional>
55#include <limits>
56#include <numbers>
57#include <optional>
58#include <ostream>
59#include <ranges>
60#include <span>
61#include <type_traits>
62#include <utility>
63
69namespace ufo
70{
71// Forward declaration
72template <std::size_t Rows, std::size_t Cols, class T>
73struct Mat;
74
75/**************************************************************************************
76| |
77| Concepts |
78| |
79**************************************************************************************/
80
85template <class T>
86concept Matrix = requires(T const& t) {
87 []<std::size_t R, std::size_t C, class U>(Mat<R, C, U> const&) {}(t);
88};
89
94template <class M>
95concept SquareMatrix = Matrix<M> && (M::rows() == M::cols());
96
101template <class M>
102concept InvertibleMatrix = SquareMatrix<M> && std::floating_point<typename M::value_type>;
103
112template <std::size_t Rows, std::size_t Cols, class T>
113struct Mat {
114 using value_type = T;
115 using size_type = std::size_t;
116 using row_type = Vec<Cols, T>;
117 using col_type = Vec<Rows, T>;
118
119 std::array<row_type, Rows> fields{};
120
122 constexpr Mat() noexcept = default;
123
129 template <std::convertible_to<T>... Args>
130 requires(sizeof...(Args) == Rows * Cols)
131 explicit(sizeof...(Args) == 1) constexpr Mat(Args... args) noexcept
132 {
133 auto elements = std::array<T, Rows * Cols>{static_cast<T>(args)...};
134 for (std::size_t r = 0; r < Rows; ++r) {
135 for (std::size_t c = 0; c < Cols; ++c) {
136 fields[r][c] = elements[r * Cols + c];
137 }
138 }
139 }
140
145 [[nodiscard]] static consteval Mat zeros() noexcept { return {}; }
146
151 [[nodiscard]] static consteval Mat identity() noexcept
152 requires(Rows == Cols)
153 {
154 Mat m{};
155 for (std::size_t i = 0; i < Rows; ++i) {
156 m[i][i] = T(1);
157 }
158 return m;
159 }
160
165 [[nodiscard]] static consteval Mat ones() noexcept
166 {
167 Mat m{};
168 for (auto& row : m.fields) {
169 std::ranges::fill(row.fields, T(1));
170 }
171 return m;
172 }
173
179 template <std::convertible_to<row_type>... Rs>
180 requires(sizeof...(Rs) == Rows)
181 constexpr Mat(Rs&&... rs) noexcept
182 : fields{static_cast<row_type>(std::forward<Rs>(rs))...}
183 {
184 }
185
193 template <class U>
194 constexpr explicit(!std::is_same_v<T, U>) Mat(Mat<Rows, Cols, U> const& other) noexcept
195 {
196 std::ranges::transform(other.fields, fields.begin(),
197 [](auto const& row) { return row_type(row); });
198 }
199
206 template <std::size_t R2, std::size_t C2>
207 requires(R2 != Rows || C2 != Cols)
208 constexpr explicit Mat(Mat<R2, C2, T> const& other) noexcept
209 {
210 // Copy overlapping region, leave rest as zero
211 auto const max_r = std::min(Rows, R2);
212 auto const max_c = std::min(Cols, C2);
213 for (std::size_t r = 0; r < max_r; ++r) {
214 for (std::size_t c = 0; c < max_c; ++c) {
215 fields[r][c] = other.fields[r][c];
216 }
217 }
218 }
219
220 /**************************************************************************************
221 | |
222 | Accessors |
223 | |
224 **************************************************************************************/
225
232 constexpr auto& operator[](this auto& self, size_type r, size_type c) noexcept
233 {
234 return self.fields[r][c];
235 }
236
242 constexpr auto& operator[](this auto& self, size_type i) noexcept
243 {
244 return self.fields[i];
245 }
246
254 constexpr auto& at(this auto& self, size_type r, size_type c)
255 {
256 if (r >= Rows || c >= Cols) [[unlikely]] {
257 throw std::out_of_range("Matrix index out of bounds");
258 }
259 return self.fields[r][c];
260 }
261
267 [[nodiscard]] constexpr row_type const& row(size_type r) const noexcept
268 {
269 return fields[r];
270 }
271
277 [[nodiscard]] constexpr col_type col(size_type c) const noexcept
278 {
279 col_type result{};
280 for (std::size_t r = 0; r < Rows; ++r) {
281 result[r] = fields[r][c];
282 }
283 return result;
284 }
285
290 [[nodiscard]] constexpr auto begin(this auto& self) noexcept
291 {
292 return self.fields.begin();
293 }
294
299 [[nodiscard]] constexpr auto end(this auto& self) noexcept { return self.fields.end(); }
300
305 [[nodiscard]] constexpr auto data(this auto& self) noexcept
306 {
307 return self.fields.data();
308 }
309
314 [[nodiscard]] static constexpr std::size_t rows() noexcept { return Rows; }
315
320 [[nodiscard]] static constexpr std::size_t cols() noexcept { return Cols; }
321
326 [[nodiscard]] static constexpr std::size_t size() noexcept { return Rows * Cols; }
327
333 constexpr bool operator==(Mat const&) const = default;
334
335 /**************************************************************************************
336 | |
337 | Essential Operations |
338 | |
339 **************************************************************************************/
340
345 [[nodiscard]] constexpr T trace() const noexcept
346 requires(Rows == Cols)
347 {
348 T result{};
349 for (std::size_t i = 0; i < Rows; ++i) {
350 result += fields[i][i];
351 }
352 return result;
353 }
354
359 [[nodiscard]] constexpr T frobenius_norm() const noexcept
360 {
361 T sum{};
362 for (auto const& row : fields) {
363 for (auto const& elem : row.fields) {
364 sum += elem * elem;
365 }
366 }
367 return std::sqrt(sum);
368 }
369
375 [[nodiscard]] constexpr bool isNearZero(T epsilon = std::numeric_limits<T>::epsilon() *
376 T(100)) const noexcept
377 requires std::floating_point<T>
378 {
379 return frobenius_norm() < epsilon;
380 }
381
389 [[nodiscard]] constexpr T conditionNumber() const noexcept
390 requires InvertibleMatrix<Mat>
391 {
392 // Estimate using Frobenius norm (rough approximation)
393 auto inv = inverse(*this);
394 return frobenius_norm() * inv.frobenius_norm();
395 }
396
403 [[nodiscard]] constexpr std::optional<Mat> safe_inverse(
404 T epsilon = std::numeric_limits<T>::epsilon() * T(1000)) const noexcept
405 requires InvertibleMatrix<Mat>
406 {
407 auto det = determinant(*this);
408 if (std::abs(det) < epsilon) {
409 return std::nullopt;
410 }
411 return inverse(*this);
412 }
413
418 [[nodiscard]] constexpr auto flat_view(this auto& self) noexcept
419 {
420 return std::span{self.data()->data(), Rows * Cols};
421 }
422
432 template <std::size_t R2>
433 [[nodiscard]] constexpr auto block(std::size_t start_row,
434 std::size_t start_col) const noexcept
436 requires(R2 <= Rows && R2 <= Cols)
437 {
438 Mat<R2, R2, T> result{};
439 for (std::size_t r = 0; r < R2; ++r) {
440 for (std::size_t c = 0; c < R2; ++c) {
441 result[r][c] = fields[start_row + r][start_col + c];
442 }
443 }
444 return result;
445 }
446
453 template <std::predicate<T> Pred>
454 [[nodiscard]] constexpr bool all_of(Pred&& pred) const noexcept
455 {
456 return std::ranges::all_of(flat_view(), std::forward<Pred>(pred));
457 }
458
465 template <std::predicate<T> Pred>
466 [[nodiscard]] constexpr bool any_of(Pred&& pred) const noexcept
467 {
468 return std::ranges::any_of(flat_view(), std::forward<Pred>(pred));
469 }
470
477 template <class UnaryOp>
478 [[nodiscard]] constexpr Mat transform(UnaryOp&& op) const noexcept
479 {
480 Mat result{};
481 std::ranges::transform(flat_view(), result.flat_view().begin(),
482 std::forward<UnaryOp>(op));
483 return result;
484 }
485
490 [[nodiscard]] static constexpr bool is_column_major() noexcept { return false; }
491
496 [[nodiscard]] static constexpr bool is_row_major() noexcept { return true; }
497
502 [[nodiscard]] static constexpr std::size_t memory_footprint() noexcept
503 {
504 return sizeof(Mat);
505 }
506
512 [[nodiscard]] constexpr bool isDiagonal(
513 T epsilon = std::numeric_limits<T>::epsilon()) const noexcept
514 requires SquareMatrix<Mat>
515 {
516 for (std::size_t r = 0; r < Rows; ++r) {
517 for (std::size_t c = 0; c < Cols; ++c) {
518 if (r != c && std::abs(fields[r][c]) > epsilon) {
519 return false;
520 }
521 }
522 }
523 return true;
524 }
525
531 [[nodiscard]] constexpr bool isSymmetric(
532 T epsilon = std::numeric_limits<T>::epsilon()) const noexcept
533 requires SquareMatrix<Mat>
534 {
535 for (std::size_t r = 0; r < Rows; ++r) {
536 for (std::size_t c = r + 1; c < Cols; ++c) {
537 if (std::abs(fields[r][c] - fields[c][r]) > epsilon) {
538 return false;
539 }
540 }
541 }
542 return true;
543 }
544
551 [[nodiscard]] constexpr bool isUpperTriangular(
552 T epsilon = std::numeric_limits<T>::epsilon()) const noexcept
553 requires SquareMatrix<Mat>
554 {
555 for (std::size_t r = 1; r < Rows; ++r) {
556 for (std::size_t c = 0; c < r; ++c) {
557 if (std::abs(fields[r][c]) > epsilon) {
558 return false;
559 }
560 }
561 }
562 return true;
563 }
564
571 [[nodiscard]] constexpr bool isLowerTriangular(
572 T epsilon = std::numeric_limits<T>::epsilon()) const noexcept
573 requires SquareMatrix<Mat>
574 {
575 for (std::size_t r = 0; r < Rows - 1; ++r) {
576 for (std::size_t c = r + 1; c < Cols; ++c) {
577 if (std::abs(fields[r][c]) > epsilon) {
578 return false;
579 }
580 }
581 }
582 return true;
583 }
584
591 [[nodiscard]] constexpr std::size_t rank(T epsilon = std::numeric_limits<T>::epsilon() *
592 T(1000)) const noexcept
593 requires std::floating_point<T>
594 {
595 auto temp = *this;
596 std::size_t rank = 0;
597
598 for (std::size_t r = 0; r < std::min(Rows, Cols); ++r) {
599 // Find pivot
600 std::size_t pivot_row = r;
601 for (std::size_t i = r + 1; i < Rows; ++i) {
602 if (std::abs(temp[i][r]) > std::abs(temp[pivot_row][r])) {
603 pivot_row = i;
604 }
605 }
606
607 if (std::abs(temp[pivot_row][r]) <= epsilon) continue;
608
609 if (pivot_row != r) {
610 std::ranges::swap(temp[r], temp[pivot_row]);
611 }
612
613 rank++;
614
615 // Eliminate below
616 for (std::size_t i = r + 1; i < Rows; ++i) {
617 if (std::abs(temp[i][r]) <= epsilon) continue;
618
619 T factor = temp[i][r] / temp[r][r];
620 for (std::size_t j = r; j < Cols; ++j) {
621 temp[i][j] -= factor * temp[r][j];
622 }
623 }
624 }
625
626 return rank;
627 }
628
629 /**************************************************************************************
630 | |
631 | Unary arithmetic operator |
632 | |
633 **************************************************************************************/
634
639 constexpr Mat operator+() const noexcept { return *this; }
640
645 constexpr Mat operator-() const noexcept
646 {
647 Mat result;
648 std::ranges::transform(fields, result.fields.begin(), std::negate{});
649 return result;
650 }
651
652 /**************************************************************************************
653 | |
654 | Compound assignment operator |
655 | |
656 **************************************************************************************/
657
663 constexpr Mat& operator+=(Mat const& rhs) noexcept
664 {
665 std::ranges::transform(fields, rhs.fields, fields.begin(), std::plus{});
666 return *this;
667 }
668
674 constexpr Mat& operator-=(Mat const& rhs) noexcept
675 {
676 std::ranges::transform(fields, rhs.fields, fields.begin(), std::minus{});
677 return *this;
678 }
679
685 constexpr Mat& operator*=(Mat const& rhs) noexcept
686 requires(Rows == Cols)
687 {
688 *this = *this * rhs;
689 return *this;
690 }
691
692 /**************************************************************************************
693 | |
694 | Scalar compound assignment operator |
695 | |
696 **************************************************************************************/
697
703 constexpr Mat& operator+=(T rhs) noexcept
704 {
705 for (auto& row : fields) row += rhs;
706 return *this;
707 }
708
714 constexpr Mat& operator-=(T rhs) noexcept
715 {
716 for (auto& row : fields) row -= rhs;
717 return *this;
718 }
719
725 constexpr Mat& operator*=(T rhs) noexcept
726 {
727 for (auto& row : fields) row *= rhs;
728 return *this;
729 }
730
736 constexpr Mat& operator/=(T rhs) noexcept
737 {
738 for (auto& row : fields) row /= rhs;
739 return *this;
740 }
741};
742
743/**************************************************************************************
744| |
745| Type Aliases |
746| |
747**************************************************************************************/
748
749// Primary aliases
750template <class T = float>
751using Mat2 = Mat<2, 2, T>;
752template <class T = float>
753using Mat3 = Mat<3, 3, T>;
754template <class T = float>
755using Mat4 = Mat<4, 4, T>;
756
757// Common type instantiations
758using Mat2f = Mat2<float>;
759using Mat2d = Mat2<double>;
760using Mat3f = Mat3<float>;
761using Mat3d = Mat3<double>;
762using Mat4f = Mat4<float>;
763using Mat4d = Mat4<double>;
764
765// Legacy compatibility - can be removed eventually
766using Mat2x2f = Mat2f;
767using Mat2x2d = Mat2d;
768using Mat3x3f = Mat3f;
769using Mat3x3d = Mat3d;
770using Mat4x4f = Mat4f;
771using Mat4x4d = Mat4d;
772
773/**************************************************************************************
774| |
775| Binary operators |
776| |
777**************************************************************************************/
778
788template <std::size_t Rows, std::size_t Cols, class T>
789[[nodiscard]] constexpr Mat<Rows, Cols, T> operator+(
790 Mat<Rows, Cols, T> lhs, Mat<Rows, Cols, T> const& rhs) noexcept
791{
792 lhs += rhs;
793 return lhs;
794}
795
805template <std::size_t Rows, std::size_t Cols, class T>
806[[nodiscard]] constexpr Mat<Rows, Cols, T> operator-(
807 Mat<Rows, Cols, T> lhs, Mat<Rows, Cols, T> const& rhs) noexcept
808{
809 lhs -= rhs;
810 return lhs;
811}
812
813/**************************************************************************************
814| |
815| Scalar binary operators |
816| |
817**************************************************************************************/
818
828template <std::size_t Rows, std::size_t Cols, class T>
829[[nodiscard]] constexpr Mat<Rows, Cols, T> operator+(Mat<Rows, Cols, T> lhs,
830 T rhs) noexcept
831{
832 lhs += rhs;
833 return lhs;
834}
835
845template <std::size_t Rows, std::size_t Cols, class T>
846[[nodiscard]] constexpr Mat<Rows, Cols, T> operator-(Mat<Rows, Cols, T> lhs,
847 T rhs) noexcept
848{
849 lhs -= rhs;
850 return lhs;
851}
852
862template <std::size_t Rows, std::size_t Cols, class T>
864 T rhs) noexcept
865{
866 lhs *= rhs;
867 return lhs;
868}
869
879template <std::size_t Rows, std::size_t Cols, class T>
881 T rhs) noexcept
882{
883 lhs /= rhs;
884 return lhs;
885}
886
896template <std::size_t Rows, std::size_t Cols, class T>
897[[nodiscard]] constexpr Mat<Rows, Cols, T> operator+(T lhs,
898 Mat<Rows, Cols, T> rhs) noexcept
899{
900 rhs += lhs;
901 return rhs;
902}
903
913template <std::size_t Rows, std::size_t Cols, class T>
914[[nodiscard]] constexpr Mat<Rows, Cols, T> operator-(
915 T lhs, Mat<Rows, Cols, T> const& rhs) noexcept
916{
917 Mat<Rows, Cols, T> result;
918 std::ranges::transform(rhs.fields, result.fields.begin(),
919 [lhs](auto const& row) { return lhs - row; });
920 return result;
921}
922
932template <std::size_t Rows, std::size_t Cols, class T>
933[[nodiscard]] constexpr Mat<Rows, Cols, T> operator*(T lhs,
934 Mat<Rows, Cols, T> rhs) noexcept
935{
936 rhs *= lhs;
937 return rhs;
938}
939
949template <std::size_t Rows, std::size_t Cols, class T>
950[[nodiscard]] constexpr Mat<Rows, Cols, T> operator/(
951 T lhs, Mat<Rows, Cols, T> const& rhs) noexcept
952{
953 Mat<Rows, Cols, T> result;
954 std::ranges::transform(rhs.fields, result.fields.begin(),
955 [lhs](auto const& row) { return lhs / row; });
956 return result;
957}
958
959/**************************************************************************************
960| |
961| Matrix × vector product |
962| |
963**************************************************************************************/
964
974template <std::size_t Rows, std::size_t Cols, class T>
975[[nodiscard]] constexpr Vec<Rows, T> operator*(Mat<Rows, Cols, T> const& m,
976 Vec<Cols, T> const& v) noexcept
977{
978 Vec<Rows, T> result{};
979 for (std::size_t r = 0; r < Rows; ++r) {
980 result[r] = dot(m.fields[r], v);
981 }
982 return result;
983}
984
994template <std::size_t Rows, std::size_t Cols, class T>
995[[nodiscard]] constexpr Vec<Cols, T> operator*(Vec<Rows, T> const& v,
996 Mat<Rows, Cols, T> const& m) noexcept
997{
998 Vec<Cols, T> result{};
999 for (std::size_t c = 0; c < Cols; ++c) {
1000 for (std::size_t r = 0; r < Rows; ++r) {
1001 result[c] += v[r] * m.fields[r][c];
1002 }
1003 }
1004 return result;
1005}
1006
1007/**************************************************************************************
1008| |
1009| Matrix × matrix product |
1010| |
1011**************************************************************************************/
1012
1025// Mat<Rows, Shared, T> * Mat<Shared, Cols, T> -> Mat<Rows, Cols, T>
1026template <std::size_t Rows, std::size_t Shared, std::size_t Cols, class T>
1027[[nodiscard]] constexpr Mat<Rows, Cols, T> operator*(
1028 Mat<Rows, Shared, T> const& a, Mat<Shared, Cols, T> const& b) noexcept
1029{
1030 Mat<Rows, Cols, T> result{};
1031 for (std::size_t r = 0; r < Rows; ++r) {
1032 for (std::size_t c = 0; c < Cols; ++c) {
1033 for (std::size_t k = 0; k < Shared; ++k) {
1034 result.fields[r][c] += a.fields[r][k] * b.fields[k][c];
1035 }
1036 }
1037 }
1038 return result;
1039}
1040
1041/**************************************************************************************
1042| |
1043| Functions |
1044| |
1045**************************************************************************************/
1046
1055template <SquareMatrix M>
1056[[nodiscard]] constexpr auto determinant(M const& m) noexcept
1057{
1058 using T = typename M::value_type;
1059 constexpr auto N = M::rows();
1060
1061 if constexpr (2 == N) {
1062 return m[0][0] * m[1][1] - m[0][1] * m[1][0];
1063 } else if constexpr (3 == N) {
1064 return m[0][0] * (m[1][1] * m[2][2] - m[1][2] * m[2][1]) -
1065 m[0][1] * (m[1][0] * m[2][2] - m[1][2] * m[2][0]) +
1066 m[0][2] * (m[1][0] * m[2][1] - m[1][1] * m[2][0]);
1067 } else if constexpr (4 == N) {
1068 // Use row-major indexing: m[row][col]
1069 T const A2323 = m[2][2] * m[3][3] - m[2][3] * m[3][2];
1070 T const A1323 = m[2][1] * m[3][3] - m[2][3] * m[3][1];
1071 T const A1223 = m[2][1] * m[3][2] - m[2][2] * m[3][1];
1072 T const A0323 = m[2][0] * m[3][3] - m[2][3] * m[3][0];
1073 T const A0223 = m[2][0] * m[3][2] - m[2][2] * m[3][0];
1074 T const A0123 = m[2][0] * m[3][1] - m[2][1] * m[3][0];
1075 return m[0][0] * (m[1][1] * A2323 - m[1][2] * A1323 + m[1][3] * A1223) -
1076 m[0][1] * (m[1][0] * A2323 - m[1][2] * A0323 + m[1][3] * A0223) +
1077 m[0][2] * (m[1][0] * A1323 - m[1][1] * A0323 + m[1][3] * A0123) -
1078 m[0][3] * (m[1][0] * A1223 - m[1][1] * A0223 + m[1][2] * A0123);
1079 } else {
1080 []<bool flag = false>() {
1081 static_assert(flag, "determinant only implemented for 2x2, 3x3, and 4x4 matrices");
1082 }();
1083 }
1084}
1085
1096template <InvertibleMatrix M>
1097[[nodiscard]] constexpr M inverse(M const& m) noexcept
1098{
1099 using T = typename M::value_type;
1100 constexpr auto N = M::rows();
1101
1102 if constexpr (2 == N) {
1103 T const det_inv = T(1) / determinant(m);
1104 M result{};
1105 result[0][0] = m[1][1] * det_inv;
1106 result[0][1] = -m[0][1] * det_inv;
1107 result[1][0] = -m[1][0] * det_inv;
1108 result[1][1] = m[0][0] * det_inv;
1109 return result;
1110 } else if constexpr (3 == N) {
1111 T const det_inv = T(1) / determinant(m);
1112 M result{};
1113 result[0][0] = (m[1][1] * m[2][2] - m[1][2] * m[2][1]) * det_inv;
1114 result[0][1] = -(m[0][1] * m[2][2] - m[0][2] * m[2][1]) * det_inv;
1115 result[0][2] = (m[0][1] * m[1][2] - m[0][2] * m[1][1]) * det_inv;
1116 result[1][0] = -(m[1][0] * m[2][2] - m[1][2] * m[2][0]) * det_inv;
1117 result[1][1] = (m[0][0] * m[2][2] - m[0][2] * m[2][0]) * det_inv;
1118 result[1][2] = -(m[0][0] * m[1][2] - m[0][2] * m[1][0]) * det_inv;
1119 result[2][0] = (m[1][0] * m[2][1] - m[1][1] * m[2][0]) * det_inv;
1120 result[2][1] = -(m[0][0] * m[2][1] - m[0][1] * m[2][0]) * det_inv;
1121 result[2][2] = (m[0][0] * m[1][1] - m[0][1] * m[1][0]) * det_inv;
1122 return result;
1123 } else if constexpr (4 == N) {
1124 T const A2323 = m[2][2] * m[3][3] - m[2][3] * m[3][2];
1125 T const A1323 = m[2][1] * m[3][3] - m[2][3] * m[3][1];
1126 T const A1223 = m[2][1] * m[3][2] - m[2][2] * m[3][1];
1127 T const A0323 = m[2][0] * m[3][3] - m[2][3] * m[3][0];
1128 T const A0223 = m[2][0] * m[3][2] - m[2][2] * m[3][0];
1129 T const A0123 = m[2][0] * m[3][1] - m[2][1] * m[3][0];
1130 T const A2313 = m[1][2] * m[3][3] - m[1][3] * m[3][2];
1131 T const A1313 = m[1][1] * m[3][3] - m[1][3] * m[3][1];
1132 T const A1213 = m[1][1] * m[3][2] - m[1][2] * m[3][1];
1133 T const A2312 = m[1][2] * m[2][3] - m[1][3] * m[2][2];
1134 T const A1312 = m[1][1] * m[2][3] - m[1][3] * m[2][1];
1135 T const A1212 = m[1][1] * m[2][2] - m[1][2] * m[2][1];
1136 T const A0313 = m[1][0] * m[3][3] - m[1][3] * m[3][0];
1137 T const A0213 = m[1][0] * m[3][2] - m[1][2] * m[3][0];
1138 T const A0312 = m[1][0] * m[2][3] - m[1][3] * m[2][0];
1139 T const A0212 = m[1][0] * m[2][2] - m[1][2] * m[2][0];
1140 T const A0113 = m[1][0] * m[3][1] - m[1][1] * m[3][0];
1141 T const A0112 = m[1][0] * m[2][1] - m[1][1] * m[2][0];
1142
1143 T const det_inv =
1144 T(1) / (m[0][0] * (m[1][1] * A2323 - m[1][2] * A1323 + m[1][3] * A1223) -
1145 m[0][1] * (m[1][0] * A2323 - m[1][2] * A0323 + m[1][3] * A0223) +
1146 m[0][2] * (m[1][0] * A1323 - m[1][1] * A0323 + m[1][3] * A0123) -
1147 m[0][3] * (m[1][0] * A1223 - m[1][1] * A0223 + m[1][2] * A0123));
1148
1149 M result{};
1150 result[0][0] = (m[1][1] * A2323 - m[1][2] * A1323 + m[1][3] * A1223) * det_inv;
1151 result[0][1] = -(m[0][1] * A2323 - m[0][2] * A1323 + m[0][3] * A1223) * det_inv;
1152 result[0][2] = (m[0][1] * A2313 - m[0][2] * A1313 + m[0][3] * A1213) * det_inv;
1153 result[0][3] = -(m[0][1] * A2312 - m[0][2] * A1312 + m[0][3] * A1212) * det_inv;
1154 result[1][0] = -(m[1][0] * A2323 - m[1][2] * A0323 + m[1][3] * A0223) * det_inv;
1155 result[1][1] = (m[0][0] * A2323 - m[0][2] * A0323 + m[0][3] * A0223) * det_inv;
1156 result[1][2] = -(m[0][0] * A2313 - m[0][2] * A0313 + m[0][3] * A0213) * det_inv;
1157 result[1][3] = (m[0][0] * A2312 - m[0][2] * A0312 + m[0][3] * A0212) * det_inv;
1158 result[2][0] = (m[1][0] * A1323 - m[1][1] * A0323 + m[1][3] * A0123) * det_inv;
1159 result[2][1] = -(m[0][0] * A1323 - m[0][1] * A0323 + m[0][3] * A0123) * det_inv;
1160 result[2][2] = (m[0][0] * A1313 - m[0][1] * A0313 + m[0][3] * A0113) * det_inv;
1161 result[2][3] = -(m[0][0] * A1312 - m[0][1] * A0312 + m[0][3] * A0112) * det_inv;
1162 result[3][0] = -(m[1][0] * A1223 - m[1][1] * A0223 + m[1][2] * A0123) * det_inv;
1163 result[3][1] = (m[0][0] * A1223 - m[0][1] * A0223 + m[0][2] * A0123) * det_inv;
1164 result[3][2] = -(m[0][0] * A1213 - m[0][1] * A0213 + m[0][2] * A0113) * det_inv;
1165 result[3][3] = (m[0][0] * A1212 - m[0][1] * A0212 + m[0][2] * A0112) * det_inv;
1166 return result;
1167 } else {
1168 []<bool flag = false>() {
1169 static_assert(flag, "inverse only implemented for 2x2, 3x3, and 4x4 matrices");
1170 }();
1171 }
1172}
1173
1183template <std::size_t Rows, std::size_t Cols, class T>
1184[[nodiscard]] constexpr Mat<Cols, Rows, T> transpose(Mat<Rows, Cols, T> const& m) noexcept
1185{
1186 Mat<Cols, Rows, T> result{};
1187 for (std::size_t r = 0; r < Rows; ++r) {
1188 for (std::size_t c = 0; c < Cols; ++c) {
1189 result.fields[c][r] = m.fields[r][c];
1190 }
1191 }
1192 return result;
1193}
1194
1202// Convenient factory functions
1203template <std::size_t R, std::size_t C, class T = float>
1204[[nodiscard]] constexpr Mat<R, C, T> zeros() noexcept
1205{
1206 return Mat<R, C, T>::zeros();
1207}
1208
1215template <std::size_t N, class T = float>
1216[[nodiscard]] constexpr Mat<N, N, T> identity() noexcept
1217{
1218 return Mat<N, N, T>::identity();
1219}
1220
1228template <std::size_t R, std::size_t C, class T = float>
1229[[nodiscard]] constexpr Mat<R, C, T> ones() noexcept
1230{
1231 return Mat<R, C, T>::ones();
1232}
1233
1234/**************************************************************************************
1235| |
1236| Symmetric 3×3 eigen decomposition |
1237| |
1238**************************************************************************************/
1239
1251template <std::floating_point T>
1252[[nodiscard]] constexpr Vec<3, T> eigenValues(Mat<3, 3, T> const& m) noexcept
1253{
1254 T const a = m[0][0], d = m[0][1], f = m[0][2];
1255 T const b = m[1][1], e = m[1][2];
1256 T const c = m[2][2];
1257
1258 T const x_1 =
1259 a * a + b * b + c * c - a * b - a * c - b * c + T(3) * (d * d + f * f + e * e);
1260
1261 T const x_2 = -(T(2) * a - b - c) * (T(2) * b - a - c) * (T(2) * c - a - b) +
1262 T(9) * ((T(2) * c - a - b) * (d * d) + (T(2) * b - a - c) * (f * f) +
1263 (T(2) * a - b - c) * (e * e)) -
1264 T(54) * (d * e * f);
1265
1266 T const phi =
1267 T(0) < x_2
1268 ? std::atan(std::sqrt(T(4) * x_1 * x_1 * x_1 - x_2 * x_2) / x_2)
1269 : (T(0) > x_2 ? std::atan(std::sqrt(T(4) * x_1 * x_1 * x_1 - x_2 * x_2) / x_2) +
1270 std::numbers::pi_v<T>
1271 : std::numbers::pi_v<T> / T(2));
1272
1273 return Vec<3, T>(
1274 (a + b + c - T(2) * std::sqrt(x_1) * std::cos(phi / T(3))) / T(3),
1275 (a + b + c +
1276 T(2) * std::sqrt(x_1) * std::cos((phi + std::numbers::pi_v<T>) / T(3))) /
1277 T(3),
1278 (a + b + c +
1279 T(2) * std::sqrt(x_1) * std::cos((phi - std::numbers::pi_v<T>) / T(3))) /
1280 T(3));
1281}
1282
1296template <std::floating_point T>
1297[[nodiscard]] constexpr std::array<Vec<3, T>, 3> eigenVectors(
1298 Mat<3, 3, T> const& m) noexcept
1299{
1300 return eigenVectors(m, eigenValues(m));
1301}
1302
1317template <std::floating_point T>
1318[[nodiscard]] constexpr std::array<Vec<3, T>, 3> eigenVectors(
1319 Mat<3, 3, T> const& m, Vec<3, T> const& eigen_values) noexcept
1320{
1321 assert(eigenValues(m) == eigen_values);
1322
1323 T const d = m[0][1];
1324 T const f = m[0][2] == T(0) ? std::numeric_limits<T>::epsilon() : m[0][2];
1325 T const b = m[1][1], e = m[1][2];
1326 T const c = m[2][2];
1327
1328 T const l_1 = eigen_values[0];
1329 T const l_2 = eigen_values[1];
1330 T const l_3 = eigen_values[2];
1331
1332 T const m_1 = (d * (c - l_1) - e * f) / (f * (b - l_1) - d * e);
1333 T const m_2 = (d * (c - l_2) - e * f) / (f * (b - l_2) - d * e);
1334 T const m_3 = (d * (c - l_3) - e * f) / (f * (b - l_3) - d * e);
1335
1336 return {normalize(Vec<3, T>((l_1 - c - e * m_1) / f, m_1, T(1))),
1337 normalize(Vec<3, T>((l_2 - c - e * m_2) / f, m_2, T(1))),
1338 normalize(Vec<3, T>((l_3 - c - e * m_3) / f, m_3, T(1)))};
1339}
1340
1341/**************************************************************************************
1342| |
1343| Projection / view matrices |
1344| |
1345**************************************************************************************/
1346
1358template <std::floating_point T>
1359[[nodiscard]] Mat<4, 4, T> orthogonal(T left, T right, T bottom, T top)
1360{
1361 Mat<4, 4, T> m{};
1362 m[0][0] = T(2) / (right - left);
1363 m[1][1] = T(2) / (top - bottom);
1364 m[2][2] = -T(1);
1365 m[0][3] = -(right + left) / (right - left);
1366 m[1][3] = -(top + bottom) / (top - bottom);
1367 m[3][3] = T(1);
1368 return m;
1369}
1370
1384template <std::floating_point T>
1385[[nodiscard]] Mat<4, 4, T> orthogonal(T left, T right, T bottom, T top, T zNear, T zFar)
1386{
1387 Mat<4, 4, T> m{};
1388 m[3][3] = T(1);
1389
1390 m[0][0] = T(2) / (right - left);
1391 m[1][1] = T(2) / (top - bottom);
1392 m[2][2] = T(1) / (zFar - zNear);
1393 m[0][3] = -(right + left) / (right - left);
1394 m[1][3] = -(top + bottom) / (top - bottom);
1395 m[2][3] = -zNear / (zFar - zNear);
1396
1397 return m;
1398}
1399
1411template <std::floating_point T>
1412[[nodiscard]] Mat<4, 4, T> perspective(T fovy, T aspect, T near, T far)
1413{
1414 Mat<4, 4, T> m{};
1415
1416 T const tan_half_fovy = std::tan(fovy / T(2));
1417
1418 m[0][0] = T(1) / (aspect * tan_half_fovy);
1419 m[1][1] = T(1) / tan_half_fovy;
1420 m[2][2] = far / (far - near);
1421 m[3][2] = T(1);
1422 m[2][3] = -(far * near) / (far - near);
1423
1424 return m;
1425}
1426
1443template <std::floating_point T>
1444[[nodiscard]] Mat<4, 4, T> perspective(T fx, T fy, T cx, T cy, T width, T height, T near,
1445 T far)
1446{
1447 Mat<4, 4, T> m{};
1448
1449 m[0][0] = T(2) * fx / width;
1450 m[1][1] = T(2) * fy / height;
1451 m[0][2] = (T(2) * cx / width) - T(1);
1452 m[1][2] = (T(2) * cy / height) - T(1);
1453 m[2][2] = far / (far - near);
1454 m[3][2] = T(1);
1455 m[2][3] = -(far * near) / (far - near);
1456
1457 return m;
1458}
1459
1470template <std::floating_point T>
1471[[nodiscard]] Mat<4, 4, T> lookAt(Vec<3, T> const& eye, Vec<3, T> const& target,
1472 Vec<3, T> const& up)
1473{
1474 Mat<4, 4, T> m{};
1475
1476 Vec<3, T> const f(normalize(target - eye));
1477 Vec<3, T> const s(normalize(cross(f, up)));
1478 Vec<3, T> const u(cross(s, f));
1479
1480 m[0][0] = s[0];
1481 m[0][1] = s[1];
1482 m[0][2] = s[2];
1483 m[1][0] = -u[0];
1484 m[1][1] = -u[1];
1485 m[1][2] = -u[2];
1486 m[2][0] = f[0];
1487 m[2][1] = f[1];
1488 m[2][2] = f[2];
1489 m[0][3] = -dot(s, eye);
1490 m[1][3] = dot(u, eye);
1491 m[2][3] = -dot(f, eye);
1492 m[3][3] = T(1);
1493
1494 return m;
1495}
1496
1508template <std::floating_point T>
1509[[nodiscard]] Mat<4, 4, T> infinitePerspective(T fovy, T aspect, T near)
1510{
1511 Mat<4, 4, T> m{};
1512 T const tan_half_fovy = std::tan(fovy / T(2));
1513
1514 m[0][0] = T(1) / (aspect * tan_half_fovy);
1515 m[1][1] = T(1) / tan_half_fovy;
1516
1517 m[2][2] = T(1);
1518 m[3][2] = T(1);
1519 m[2][3] = -near;
1520
1521 return m;
1522}
1523
1534template <std::floating_point T>
1535[[nodiscard]] Mat<4, 4, T> rotate(Mat<4, 4, T> const& m, T angle, Vec<3, T> const& v)
1536{
1537 T const c = std::cos(angle);
1538 T const s = std::sin(angle);
1539
1540 Vec<3, T> const axis(normalize(v));
1541 Vec<3, T> const temp((T(1) - c) * axis);
1542
1543 // Rotation matrix R in row-major: rot[row][col] = R_{row,col}
1544 Mat<3, 3, T> rot{};
1545 rot[0][0] = c + temp[0] * axis[0];
1546 rot[0][1] = temp[1] * axis[0] - s * axis[2];
1547 rot[0][2] = temp[2] * axis[0] + s * axis[1];
1548 rot[1][0] = temp[0] * axis[1] + s * axis[2];
1549 rot[1][1] = c + temp[1] * axis[1];
1550 rot[1][2] = temp[2] * axis[1] - s * axis[0];
1551 rot[2][0] = temp[0] * axis[2] - s * axis[1];
1552 rot[2][1] = temp[1] * axis[2] + s * axis[0];
1553 rot[2][2] = c + temp[2] * axis[2];
1554
1555 // Compute M * R for upper-left 3x3, preserving last row and column
1556 Mat<4, 4, T> result{};
1557 for (std::size_t i = 0; i < 3; ++i) {
1558 for (std::size_t j = 0; j < 3; ++j) {
1559 for (std::size_t k = 0; k < 3; ++k) {
1560 result[i][j] += m[i][k] * rot[k][j];
1561 }
1562 }
1563 result[i][3] = m[i][3];
1564 }
1565 result[3] = m[3];
1566 return result;
1567}
1568
1569/**************************************************************************************
1570| |
1571| Structured bindings |
1572| |
1573**************************************************************************************/
1574
1584template <std::size_t I, std::size_t Rows, std::size_t Cols, class T>
1585 requires(I < Rows)
1586[[nodiscard]] constexpr Vec<Cols, T>& get(Mat<Rows, Cols, T>& m) noexcept
1587{
1588 return m.fields[I];
1589}
1590
1600template <std::size_t I, std::size_t Rows, std::size_t Cols, class T>
1601 requires(I < Rows)
1602[[nodiscard]] constexpr Vec<Cols, T> const& get(Mat<Rows, Cols, T> const& m) noexcept
1603{
1604 return m.fields[I];
1605}
1606
1616template <std::size_t I, std::size_t Rows, std::size_t Cols, class T>
1617 requires(I < Rows)
1618[[nodiscard]] constexpr Vec<Cols, T>&& get(Mat<Rows, Cols, T>&& m) noexcept
1619{
1620 return std::move(m.fields[I]);
1621}
1622
1623/**************************************************************************************
1624| |
1625| Print |
1626| |
1627**************************************************************************************/
1628
1639template <std::size_t Rows, std::size_t Cols, class T>
1640std::ostream& operator<<(std::ostream& out, Mat<Rows, Cols, T> const& m)
1641{
1642 for (std::size_t r = 0; r < Rows; ++r) {
1643 if (r > 0) out << '\n';
1644 out << m.fields[r];
1645 }
1646 return out;
1647}
1648
1649} // namespace ufo
1650
1655template <std::size_t Rows, std::size_t Cols, class T>
1656struct std::tuple_size<ufo::Mat<Rows, Cols, T>>
1657 : std::integral_constant<std::size_t, Rows> {
1658};
1659
1660template <std::size_t I, std::size_t Rows, std::size_t Cols, class T>
1661struct std::tuple_element<I, ufo::Mat<Rows, Cols, T>> {
1662 using type = ufo::Vec<Cols, T>;
1663};
1664
1665template <std::size_t Rows, std::size_t Cols, std::formattable<char> T>
1666struct std::formatter<ufo::Mat<Rows, Cols, T>> {
1667 constexpr auto parse(std::format_parse_context& ctx) { return ctx.begin(); }
1668
1669 auto format(ufo::Mat<Rows, Cols, T> const& m, std::format_context& ctx) const
1670 {
1671 auto out = ctx.out();
1672 for (std::size_t r = 0; r < Rows; ++r) {
1673 if (r > 0) out = std::format_to(out, "\n");
1674 out = std::format_to(out, "{}", m.fields[r]);
1675 }
1676 return out;
1677 }
1678};
1679
1680#endif // UFO_NUMERIC_MAT_HPP
Concept satisfied by invertible matrices (square with floating-point elements).
Definition mat.hpp:102
Concept satisfied by any specialization of Mat<Rows, Cols, U>.
Definition mat.hpp:86
Concept satisfied by square matrix types (Rows == Cols).
Definition mat.hpp:95
constexpr T trace() const noexcept
Computes the trace (sum of diagonal elements) of a square matrix.
Definition mat.hpp:345
constexpr Mat & operator+=(T rhs) noexcept
Adds scalar rhs to every element.
Definition mat.hpp:703
constexpr auto & operator[](this auto &self, size_type r, size_type c) noexcept
Accesses the element at row r, column c.
Definition mat.hpp:232
constexpr Mat & operator+=(Mat const &rhs) noexcept
Adds rhs element-wise to this matrix.
Definition mat.hpp:663
T angle(Quat< T > const &q) noexcept
Extracts the rotation angle (in radians) from a unit quaternion.
Definition quat.hpp:852
constexpr Vec< Cols, T > & get(Mat< Rows, Cols, T > &m) noexcept
Structured-binding accessor — lvalue reference to row I.
Definition mat.hpp:1586
constexpr auto determinant(M const &m) noexcept
Computes the determinant of a square matrix.
Definition mat.hpp:1056
Mat< 4, 4, T > orthogonal(T left, T right, T bottom, T top)
Builds a right-handed 2-D orthographic projection matrix (no depth clipping).
Definition mat.hpp:1359
constexpr T dot(Quat< T > const &a, Quat< T > const &b) noexcept
Computes the four-component dot product a.w*b.w + a.x*b.x + a.y*b.y + a.z*b.z.
Definition quat.hpp:643
constexpr Mat operator+() const noexcept
Unary identity operator.
Definition mat.hpp:639
constexpr Vec< 3, T > eigenValues(Mat< 3, 3, T > const &m) noexcept
Computes the eigenvalues of a real symmetric 3×3 matrix, sorted ascending.
Definition mat.hpp:1252
STL namespace.
All vision-related classes and functions.
Definition cloud.hpp:49
constexpr T b(Lab< T, Flags > color) noexcept
Returns the un-weighted blue–yellow axis value.
Definition lab.hpp:326
Mat< 4, 4, T > perspective(T fovy, T aspect, T near, T far)
Builds a perspective projection matrix (OpenCV convention).
Definition mat.hpp:1412
constexpr Mat< Rows, Cols, T > operator*(Mat< Rows, Cols, T > lhs, T rhs) noexcept
Multiplies every element of lhs by scalar rhs.
Definition mat.hpp:863
constexpr Mat< Rows, Cols, T > operator/(Mat< Rows, Cols, T > lhs, T rhs) noexcept
Divides every element of lhs by scalar rhs.
Definition mat.hpp:880
constexpr Mat< R, C, T > zeros() noexcept
Returns an R × C matrix with all elements set to zero.
Definition mat.hpp:1204
constexpr T a(Lab< T, Flags > color) noexcept
Returns the un-weighted green–red axis value.
Definition lab.hpp:310
constexpr Mat< R, C, T > ones() noexcept
Returns an R × C matrix with all elements set to one.
Definition mat.hpp:1229
Mat< 4, 4, T > infinitePerspective(T fovy, T aspect, T near)
Builds a right-handed perspective projection matrix with an infinite far plane.
Definition mat.hpp:1509
constexpr std::array< Vec< 3, T >, 3 > eigenVectors(Mat< 3, 3, T > const &m) noexcept
Computes the eigenvectors of a real symmetric 3×3 matrix.
Definition mat.hpp:1297
constexpr Quat< T > normalize(Quat< T > const &q) noexcept
Returns a unit quaternion in the same direction as q.
Definition quat.hpp:679
constexpr Mat< Cols, Rows, T > transpose(Mat< Rows, Cols, T > const &m) noexcept
Returns the transpose of a matrix.
Definition mat.hpp:1184
constexpr Quat< T > cross(Quat< T > const &q1, Quat< T > const &q2) noexcept
Computes the Hamilton cross product of two quaternions.
Definition quat.hpp:721
constexpr M inverse(M const &m) noexcept
Computes the inverse of a square floating-point matrix.
Definition mat.hpp:1097
Mat< 4, 4, T > rotate(Mat< 4, 4, T > const &m, T angle, Vec< 3, T > const &v)
Applies an axis-angle rotation to a 4×4 matrix.
Definition mat.hpp:1535
Vec< 3, T > axis(Quat< T > const &q) noexcept
Extracts the unit rotation axis from a unit quaternion.
Definition quat.hpp:869
Mat< 4, 4, T > lookAt(Vec< 3, T > const &eye, Vec< 3, T > const &target, Vec< 3, T > const &up)
Builds a view matrix (OpenCV convention).
Definition mat.hpp:1471
constexpr Mat< N, N, T > identity() noexcept
Returns an N × N identity matrix.
Definition mat.hpp:1216
constexpr T sum(Vec< Dim, T > const &v) noexcept
Computes the sum of all elements in a vector.
Definition vec.hpp:1309
A fixed-size matrix with Rows rows and Cols columns.
Definition mat.hpp:113
constexpr auto end(this auto &self) noexcept
Returns a past-the-end row iterator.
Definition mat.hpp:299
static constexpr std::size_t size() noexcept
Returns the total number of elements (Rows * Cols).
Definition mat.hpp:326
constexpr Mat() noexcept=default
Default-constructs a zero-initialized matrix.
constexpr Mat & operator-=(T rhs) noexcept
Subtracts scalar rhs from every element.
Definition mat.hpp:714
constexpr Mat & operator*=(Mat const &rhs) noexcept
Multiplies this square matrix by rhs (matrix product, square matrices only).
Definition mat.hpp:685
constexpr std::optional< Mat > safe_inverse(T epsilon=std::numeric_limits< T >::epsilon() *T(1000)) const noexcept
Computes the inverse, returning std::nullopt for near-singular matrices.
Definition mat.hpp:403
explicit(sizeof...(Args)==1) const expr Mat(Args... args) noexcept
Constructs a matrix from exactly Rows * Cols element values (row-major).
Definition mat.hpp:131
static constexpr std::size_t rows() noexcept
Returns the number of rows.
Definition mat.hpp:314
constexpr Mat & operator-=(Mat const &rhs) noexcept
Subtracts rhs element-wise from this matrix.
Definition mat.hpp:674
constexpr bool isNearZero(T epsilon=std::numeric_limits< T >::epsilon() *T(100)) const noexcept
Returns true if the Frobenius norm is less than epsilon.
Definition mat.hpp:375
constexpr Mat operator-() const noexcept
Unary negation operator.
Definition mat.hpp:645
constexpr bool all_of(Pred &&pred) const noexcept
Returns true if all elements satisfy the predicate.
Definition mat.hpp:454
constexpr T frobenius_norm() const noexcept
Computes the Frobenius norm of the matrix.
Definition mat.hpp:359
static consteval Mat zeros() noexcept
Returns a zero-initialized matrix.
Definition mat.hpp:145
constexpr auto & at(this auto &self, size_type r, size_type c)
Bounds-checked access to the element at row r, column c.
Definition mat.hpp:254
constexpr bool any_of(Pred &&pred) const noexcept
Returns true if at least one element satisfies the predicate.
Definition mat.hpp:466
constexpr bool isSymmetric(T epsilon=std::numeric_limits< T >::epsilon()) const noexcept
Returns true if the matrix equals its transpose (within epsilon).
Definition mat.hpp:531
constexpr auto begin(this auto &self) noexcept
Returns an iterator to the first row.
Definition mat.hpp:290
constexpr bool operator==(Mat const &) const =default
Compares two matrices for equality (element-wise).
constexpr bool isDiagonal(T epsilon=std::numeric_limits< T >::epsilon()) const noexcept
Returns true if all off-diagonal elements are within epsilon of zero.
Definition mat.hpp:512
static constexpr std::size_t cols() noexcept
Returns the number of columns.
Definition mat.hpp:320
constexpr Mat transform(UnaryOp &&op) const noexcept
Applies a unary operation to each element and returns the resulting matrix.
Definition mat.hpp:478
constexpr bool isLowerTriangular(T epsilon=std::numeric_limits< T >::epsilon()) const noexcept
Returns true if all elements above the main diagonal are within epsilon of zero.
Definition mat.hpp:571
constexpr Mat(Mat< R2, C2, T > const &other) noexcept
Cross-size constructor — copies the overlapping region, zero-fills the rest.
Definition mat.hpp:208
constexpr std::size_t rank(T epsilon=std::numeric_limits< T >::epsilon() *T(1000)) const noexcept
Estimates the matrix rank via Gaussian elimination.
Definition mat.hpp:591
constexpr T conditionNumber() const noexcept
Estimates the condition number using the Frobenius norm.
Definition mat.hpp:389
static consteval Mat identity() noexcept
Returns the identity matrix (square matrices only).
Definition mat.hpp:151
constexpr Mat & operator/=(T rhs) noexcept
Divides every element by scalar rhs.
Definition mat.hpp:736
static constexpr bool is_row_major() noexcept
Returns true (storage is row-major).
Definition mat.hpp:496
constexpr auto & operator[](this auto &self, size_type i) noexcept
Accesses row i as a Vec<Cols, T>.
Definition mat.hpp:242
constexpr bool isUpperTriangular(T epsilon=std::numeric_limits< T >::epsilon()) const noexcept
Returns true if all elements below the main diagonal are within epsilon of zero.
Definition mat.hpp:551
static consteval Mat ones() noexcept
Returns a matrix with all elements set to T(1).
Definition mat.hpp:165
static constexpr bool is_column_major() noexcept
Returns false (storage is row-major).
Definition mat.hpp:490
constexpr Mat & operator*=(T rhs) noexcept
Multiplies every element by scalar rhs.
Definition mat.hpp:725
static constexpr std::size_t memory_footprint() noexcept
Returns the size of this matrix type in bytes.
Definition mat.hpp:502
constexpr auto data(this auto &self) noexcept
Returns a pointer to the first row.
Definition mat.hpp:305
constexpr auto block(std::size_t start_row, std::size_t start_col) const noexcept -> Mat< R2, R2, T > requires(R2<=Rows &&R2<=Cols)
Extracts a square sub-matrix of size R2 × R2 starting at (start_row, start_col).
Definition mat.hpp:433
constexpr row_type const & row(size_type r) const noexcept
Returns a const reference to row r.
Definition mat.hpp:267
constexpr col_type col(size_type c) const noexcept
Returns column c as a Vec<Rows, T> (by value).
Definition mat.hpp:277
constexpr auto flat_view(this auto &self) noexcept
Returns a flat std::span<T, Rows * Cols> over all elements (row-major).
Definition mat.hpp:418
constexpr Mat(Rs &&... rs) noexcept
Constructs a matrix from Rows row vectors.
Definition mat.hpp:181
A fixed-size arithmetic vector of up to 4 dimensions.
Definition vec.hpp:76