Line data Source code
1 : #ifndef EDCA948E_6A98_4AF3_8A01_916736E1577B
2 : #define EDCA948E_6A98_4AF3_8A01_916736E1577B
3 :
4 : #include "base/first_include.h" // IWYU pragma: keep
5 : #include "math/linalg/errors.h"
6 : #include "math/linalg/matrix_io.h"
7 : #include <initializer_list>
8 :
9 : namespace tracking
10 : {
11 : namespace math
12 : {
13 :
14 : template <typename ValueType_, sint32 Rows_, sint32 Cols_, bool IsRowMajor_>
15 : class Matrix;
16 :
17 : template <typename ValueType_, sint32 Size_, bool IsRowMajor_>
18 : class SquareMatrix;
19 :
20 : template <typename ValueType_, sint32 Size_, bool IsLower_, bool IsRowMajor_>
21 : class TriangularMatrix;
22 :
23 : template <typename ValueType_, sint32 Size_>
24 : class Vector;
25 :
26 : // TODO(matthias): add interface contract
27 :
28 : /// \brief A diagonal matrix that stores only the diagonal elements for memory efficiency.
29 : ///
30 : /// This class represents diagonal matrixes where only the diagonal elements are stored
31 : /// and manipulated. All off-diagonal elements are implicitly zero. Provides optimized
32 : /// operations for diagonal-specific computations like inversion and multiplication.
33 : ///
34 : /// \tparam ValueType_ The atomic data type of internal elements
35 : /// \tparam Size_ The dimension of the diagonal matrix (compile-time constant)
36 : ///
37 : /// \note Memory efficient: stores only Size_ elements instead of Size_²
38 : /// \note All operations are O(Size_) instead of O(Size_²) for general matrixes
39 : ///
40 : /// \see SquareMatrix for general square matrix operations
41 : /// \see TriangularMatrix for triangular matrix operations
42 : template <typename ValueType_, sint32 Size_>
43 399 : class DiagonalMatrix TEST_REMOVE_FINAL
44 : {
45 : public:
46 : // rule of 5 declarations
47 2 : DiagonalMatrix() = default;
48 311 : DiagonalMatrix(const DiagonalMatrix& other) = default;
49 111 : DiagonalMatrix(DiagonalMatrix&&) noexcept = default;
50 : auto operator=(const DiagonalMatrix&) -> DiagonalMatrix& = default;
51 28 : auto operator=(DiagonalMatrix&&) noexcept -> DiagonalMatrix& = default;
52 :
53 : /// \brief Construct an identity diagonal matrix.
54 : ///
55 : /// Creates a diagonal matrix with ones on the diagonal (identity matrix).
56 : ///
57 : /// \return DiagonalMatrix An identity matrix with ones on the diagonal
58 : ///
59 : /// \note This is equivalent to a diagonal matrix with all diagonal elements equal to 1
60 : [[nodiscard]] static auto Identity() -> DiagonalMatrix;
61 :
62 : /// \brief Set the diagonal matrix to identity in-place.
63 : ///
64 : /// Modifies the diagonal elements to all be 1, creating an identity matrix.
65 : ///
66 : /// \note This operation modifies the matrix in-place and does not change its size
67 : void setIdentity();
68 :
69 : /// \brief Creates a DiagonalMatrix from a flat initializer list
70 : ///
71 : /// This function creates a diagonal matrix where the diagonal elements are taken from
72 : /// a flat initializer list. The list size must exactly match the matrix dimension.
73 : ///
74 : /// \param[in] list Initializer list containing the diagonal values
75 : /// \return DiagonalMatrix with the specified diagonal elements
76 : /// \note The list size must equal Size_, otherwise assertion fails
77 : [[nodiscard]] static auto FromList(const std::initializer_list<ValueType_>& list) -> DiagonalMatrix;
78 :
79 : /// \brief Creates a DiagonalMatrix from the diagonal of a nested initializer list
80 : ///
81 : /// This function creates a diagonal matrix by extracting the diagonal elements from
82 : /// a nested initializer list representing a full matrix. Only the diagonal elements
83 : /// (where row index equals column index) are used.
84 : ///
85 : /// \param[in] list Nested initializer list representing a square matrix
86 : /// \return DiagonalMatrix containing the diagonal elements from the input list
87 : /// \note The outer list size must equal Size_, and each inner list size must equal Size_
88 : [[nodiscard]] static auto FromList(const std::initializer_list<std::initializer_list<ValueType_>>& list) -> DiagonalMatrix;
89 :
90 : /// \brief Set a diagonal block matrix at given position
91 : /// \tparam SrcSize_ Size_ of the source block
92 : /// \tparam SrcCount Number of diagonal elements to copy from source
93 : /// \tparam SrcIdxBeg Begin diagonal element index in source
94 : /// \tparam DstIdxBeg Begin diagonal element index in dest
95 : /// \param[in] block Source block matrix to copy from
96 : template <sint32 SrcSize_, sint32 SrcCount_, sint32 SrcIdxBeg_, sint32 DstIdxBeg_>
97 : void setBlock(const DiagonalMatrix<ValueType_, SrcSize_>& block);
98 :
99 : /// \brief Multiplication with generic matrix: D * Matrix
100 : /// \tparam Cols_
101 : /// \tparam IsRowMajor_
102 : /// \param[in] mat
103 : /// \return Matrix<ValueType_, Size_, Cols_, IsRowMajor_>
104 : template <sint32 Cols_, bool IsRowMajor_>
105 : [[nodiscard]] auto operator*(const Matrix<ValueType_, Size_, Cols_, IsRowMajor_>& mat) const
106 : -> Matrix<ValueType_, Size_, Cols_, IsRowMajor_>;
107 :
108 : /// \brief Multiplication with triangular matrix: D * Matrix
109 : /// \tparam isLower_
110 : /// \tparam isRowMajor_
111 : /// \param[in] mat A triangular matrix
112 : /// \return TriangularMatrix<ValueType_, Size_, isLower_, isRowMajor_>
113 : template <bool IsLower_, bool IsRowMajor_>
114 : [[nodiscard]] auto operator*(const TriangularMatrix<ValueType_, Size_, IsLower_, IsRowMajor_>& mat) const
115 : -> TriangularMatrix<ValueType_, Size_, IsLower_, IsRowMajor_>;
116 :
117 : /// \brief Multiplication with diagonal matrix: D * Matrix
118 : /// \param[in] mat A diagonal matrix
119 : /// \return DiagonalMatrix<ValueType_, Size_>
120 : [[nodiscard]] auto operator*(const DiagonalMatrix& mat) const -> DiagonalMatrix;
121 :
122 : /// \brief Multiplication with scalar: D * scalar
123 : /// \param[in] scalar A scalar value
124 : /// \return DiagonalMatrix<ValueType_, Size_>
125 : [[nodiscard]] auto operator*(const ValueType_ scalar) const -> DiagonalMatrix;
126 :
127 : /// \brief Inplace Multiplication with diagonal matrix: D * Matrix
128 : /// \param[in] mat A diagonal matrix
129 : void operator*=(const DiagonalMatrix& mat);
130 :
131 : /// \brief Inplace Multiplication with scalar: D * scalar
132 : /// \param[in] scalar A scalar value
133 : void operator*=(const ValueType_ scalar);
134 :
135 : /// \brief Element access to a scalar diagonal value
136 : /// \param[in] idx Row/Col index of the element
137 : /// \return tl::expected<std::reference_wrapper<ValueType_>, Errors> either the reference at (idx) or an Error descriptor
138 : [[nodiscard]] auto operator[](const sint32 idx) -> tl::expected<std::reference_wrapper<ValueType_>, Errors>
139 : { // implemented here to solve cyclic includes
140 : if (!(idx >= 0 && idx < Size_))
141 : {
142 : return tl::unexpected<Errors>{Errors::invalid_access_idx};
143 : }
144 : return at_unsafe(idx);
145 : }
146 :
147 : /// \brief Element read-only access to a scalar diagonal value
148 : /// \param[in] idx Row/Col index of the element
149 : /// \return tl::expected<ValueType_, Errors> either the value at (idx) or an Error descriptor
150 : [[nodiscard]] auto operator[](const sint32 idx) const -> tl::expected<ValueType_, Errors>
151 : { // implemented here to solve cyclic includes
152 : if (!(idx >= 0 && idx < Size_))
153 : {
154 : return tl::unexpected<Errors>{Errors::invalid_access_idx};
155 : }
156 : return at_unsafe(idx);
157 : }
158 :
159 : /// \brief Compute the inverse of the diagonal matrix.
160 : ///
161 : /// Calculates the inverse by taking the reciprocal of each diagonal element.
162 : /// The result is also a diagonal matrix.
163 : ///
164 : /// \return DiagonalMatrix The inverse matrix such that D * D^(-1) = I
165 : ///
166 : /// \warning Fails if any diagonal element is zero (singular matrix)
167 : /// \note O(Size_) complexity, very efficient for diagonal matrixes
168 : [[nodiscard]] auto inverse() const -> DiagonalMatrix;
169 :
170 : /// \brief Compute the inverse in-place.
171 : ///
172 : /// Modifies this matrix to contain its inverse by taking reciprocals of diagonal elements.
173 : ///
174 : /// \warning Fails if any diagonal element is zero (singular matrix)
175 : /// \note More memory efficient than the const version for large matrixes
176 : void inverse();
177 :
178 : /// \brief Calculate the trace of the diagonal matrix.
179 : ///
180 : /// Computes the sum of all diagonal elements of the matrix.
181 : /// The trace is defined as the sum of elements A_ii for i = 1 to n.
182 : ///
183 : /// \return ValueType_ The trace of the matrix(sum of diagonal elements)
184 : [[nodiscard]] auto trace() const -> ValueType_;
185 :
186 : /// \brief Calculate the determinant of the diagonal matrix.
187 : ///
188 : /// Computes the determinant as the product of the diagonal elements.
189 : ///
190 : /// \return ValueType_ The determinant of the matrix
191 : /// \note Time complexity: O(n) where n is the matrix dimension
192 : /// \note For singular matrixes, the determinant will be zero or very close to zero
193 : [[nodiscard]] auto determinant() const -> ValueType_;
194 :
195 : /// \brief Check if the diagonal matrix is positive definite.
196 : ///
197 : /// A diagonal matrix is positive definite if all diagonal elements are positive.
198 : ///
199 : /// \return true if all diagonal elements are > 0, false otherwise
200 : ///
201 : /// \note For diagonal matrixes, positive definiteness is equivalent to all elements > 0
202 : [[nodiscard]] auto isPositiveDefinite() const -> bool;
203 :
204 : /// \brief Check if the diagonal matrix is positive semi-definite.
205 : ///
206 : /// A diagonal matrix is positive semi-definite if all diagonal elements are non-negative.
207 : ///
208 : /// \return true if all diagonal elements are >= 0, false otherwise
209 : ///
210 : /// \note For diagonal matrixes, positive semi-definiteness means all elements >= 0
211 : [[nodiscard]] auto isPositiveSemiDefinite() const -> bool;
212 :
213 : //////////////////////////////////////////////////
214 : // unsafe access operators --->
215 : /// \brief Element read-only access to a scalar vector value
216 : /// \param[in] idx Row index of the element
217 : /// \return ValueType_ Scalar vector value
218 10101 : [[nodiscard]] auto at_unsafe(sint32 idx) const -> ValueType_ { return _data.at_unsafe(idx); }
219 :
220 : /// \brief Element access to a scalar vector value
221 : /// \param[in] idx Row index of the element
222 : /// \return ValueType_& Reference to the scalar vector value
223 8480 : [[nodiscard]] auto at_unsafe(sint32 idx) -> ValueType_& { return _data.at_unsafe(idx); }
224 : // <---
225 :
226 : // clang-format off
227 : TEST_REMOVE_PRIVATE:
228 : ; // workaround for correct indentation
229 : // clang-format on
230 : Vector<ValueType_, Size_> _data{};
231 : };
232 :
233 : template <typename ValueType_, sint32 Rows_, sint32 Cols_, bool IsRowMajor_>
234 : [[nodiscard]] auto operator*(const Matrix<ValueType_, Rows_, Cols_, IsRowMajor_>& mat,
235 : const DiagonalMatrix<ValueType_, Cols_>& diag) -> Matrix<ValueType_, Rows_, Cols_, IsRowMajor_>;
236 :
237 : } // namespace math
238 : } // namespace tracking
239 :
240 : #endif // EDCA948E_6A98_4AF3_8A01_916736E1577B
|