tesseract++ 0.0.1
N-dimensional tensor library for embedded systems
Loading...
Searching...
No Matches
fused_matrix.h
Go to the documentation of this file.
1#ifndef FUSEDMATRIX_H
2#define FUSEDMATRIX_H
3
7#include "matrix_traits.h"
8#include "math/math_utils.h"
9
10template <typename T, my_size_t Rows, my_size_t Cols>
11class FusedMatrix : public FusedTensorND<T, Rows, Cols>
12{
13public:
15
16 // Default constructor initializes a 2D matrix with default values
18 : FusedTensorND<T, Rows, Cols>() {}
19
20 // Constructor to initialize all elements to a specific value
21 FusedMatrix(T initValue)
22 : FusedTensorND<T, Rows, Cols>(initValue) {}
23
24 // Copy constructor from another FusedMatrix (tested)
26 : FusedTensorND<T, Rows, Cols>(other)
27 {
28#ifdef DEBUG_FUSED_MATRIX
29 MyErrorHandler::log("Copy constructor from another FusedMatrix", ErrorLevel::Info);
30#endif
31 }
32
33 // Copy constructor from base class (tested)
35 : FusedTensorND<T, Rows, Cols>(baseTensor)
36 {
37#ifdef DEBUG_FUSED_MATRIX
38 MyErrorHandler::log("Copy constructor from base class FusedTensorND", ErrorLevel::Info);
39#endif
40 }
41
42 // Move constructor from another FusedMatrix (tested)
43 FusedMatrix(FusedMatrix &&other) noexcept
45 {
46#ifdef DEBUG_FUSED_MATRIX
47 MyErrorHandler::log("Move constructor from another FusedMatrix", ErrorLevel::Info);
48#endif
49 }
50
51 // Move constructor from base class (tested)
54 {
55#ifdef DEBUG_FUSED_MATRIX
56 MyErrorHandler::log("Move constructor from base class FusedTensorND", ErrorLevel::Info);
57#endif
58 }
59
60 // Constructor to initialize from a 2D array (tested)
61 FusedMatrix(T (&initList)[Rows][Cols]) : FusedTensorND<T, Rows, Cols>()
62 {
63#ifdef DEBUG_FUSED_MATRIX
64 MyErrorHandler::log("Constructor to initialize from a 2D array", ErrorLevel::Info);
65#endif
66 // loop trough the input and use (i,j) to store them
67 for (my_size_t i = 0; i < Rows; ++i)
68 {
69 for (my_size_t j = 0; j < Cols; ++j)
70 {
71 (*this)(i, j) = initList[i][j];
72 }
73 }
74 }
75
76 /* ------ Transfomation funtions ------ */
77 // Static method to create a FusedMatrix from a FusedTensorND (tested)
79 {
80#ifdef DEBUG_FUSED_MATRIX
81 MyErrorHandler::log("Static method to create a FusedMatrix from a FusedTensorND", ErrorLevel::Info);
82#endif
83 return FusedMatrix(move(tensor));
84 }
85
86 // method to copy this as a FusedTensorND (tested)
88 {
89#ifdef DEBUG_FUSED_MATRIX
90 MyErrorHandler::log("Copy a FusedMatrix to FusedTensorND", ErrorLevel::Info);
91#endif
92 // Cast to base class to ensure correct type
93 return static_cast<const FusedTensorND<T, Rows, Cols> &>(*this);
94 }
95
96 // method to move this as a FusedTensorND (tested)
98 {
99#ifdef DEBUG_FUSED_MATRIX
100 MyErrorHandler::log("Move a FusedMatrix to FusedTensorND", ErrorLevel::Info);
101#endif
102 // Cast to base class to ensure correct type
103 return FusedTensorND<T, Rows, Cols>(move(*this));
104 }
105 /*---------------------------------------*/
106
107 // Assignment from expression template (tested)
108 template <typename Expr>
110 {
111#ifdef DEBUG_FUSED_MATRIX
112 MyErrorHandler::log("FusedMatrix assignment from expression", ErrorLevel::Info);
113#endif
115 return *this;
116 }
117
118 // Copy assingment operators -------------------------------------------
119 // Copy assignment from FusedTensorND (tested)
121 {
122#ifdef DEBUG_FUSED_MATRIX
123 MyErrorHandler::log("FusedMatrix copy assignment from FusedTensorND", ErrorLevel::Info);
124#endif
126 return *this;
127 }
128
129 // Copy assignment from FusedMatrix (tested)
131 {
132#ifdef DEBUG_FUSED_MATRIX
133 MyErrorHandler::log("FusedMatrix copy assignment from FusedMatrix", ErrorLevel::Info);
134#endif
135 // Call the base class operator= to assign the tensor
137
138 // Return the derived type
139 return *this;
140 }
141 // ---------------------------------------------------------------------
142
143 // Move assigment operators --------------------------------------------
144 // Move assignment from FusedTensorND (tested)
146 {
147#ifdef DEBUG_FUSED_MATRIX
148 MyErrorHandler::log("FusedMatrix move assignment from FusedTensorND", ErrorLevel::Info);
149#endif
151 return *this;
152 }
153
154 // Move assignment from FusedMatrix (tested)
156 {
157#ifdef DEBUG_FUSED_MATRIX
158 MyErrorHandler::log("FusedMatrix move assignment from FusedMatrix", ErrorLevel::Info);
159#endif
161 return *this;
162 }
163
164 // Override operator= to assign a 2D array to the matrix (tested)
165 FusedMatrix &operator=(T (&initList)[Rows][Cols])
166 {
167#ifdef DEBUG_FUSED_MATRIX
168 MyErrorHandler::log("Assignment from a 2D array", ErrorLevel::Info);
169#endif
170 // loop trough the input and use (i,j) to store them
171 for (my_size_t i = 0; i < Rows; ++i)
172 {
173 for (my_size_t j = 0; j < Cols; ++j)
174 {
175 (*this)(i, j) = initList[i][j];
176 }
177 }
178
179 // Return the derived type
180 return *this;
181 }
182
187
188 const T &operator()(my_size_t i, my_size_t j) const
189 {
191 }
192
193 // Override setToZero to return a FusedMatrix
195 {
196 // Call the base class setToZero to set all elements to zero
198
199 // Cast the base class (FusedTensorND) to FusedMatrix to return the derived type
200 return *this;
201 }
202
203 // Override setHomogen to return a FusedMatrix
205 {
206 // Call the base class setHomogen to set all elements to a specific value
208
209 // Cast the base class (FusedTensorND) to FusedMatrix to return the derived type
210 return *this;
211 }
212
213 // Override setRandom to return a FusedMatrix
215 {
216 // Call the base class setRandom to set all elements to random values
217 FusedTensorND<T, Rows, Cols>::setRandom(_maxRand, _minRand);
218
219 // Cast the base class (FusedTensorND) to FusedMatrix to return the derived type
220 return *this;
221 }
222
223 // Override setDiagonal to return a FusedMatrix
225 {
226 // Call the base class setDiagonal
228
229 // Cast the base class (FusedTensorND) to FusedMatrix to return the derived type
230 return *this;
231 }
232
233 // Override setIdentity to return a FusedMatrix
235 {
236 // Call the base class setIdentity
238
239 // Cast the base class (FusedTensorND) to FusedMatrix to return the derived type
240 return *this;
241 }
242
243 // Override setSequencial to return a FusedMatrix
245 {
246 // Call the base class setSequencial
248
249 // Cast the base class (FusedTensorND) to FusedMatrix to return the derived type
250 return *this;
251 }
252
253 // matmul using einsum of parent class
254 template <typename LeftExpr, typename RightExpr>
256 {
257 return {FusedTensorND<T, Rows, Cols>::einsum(mat1, mat2, 1, 0)};
258 }
259
260 bool isIdentity(void) const
261 {
262 // Check if the matrix is square
263 if (!this->areDimsEqual())
264 {
265 return false;
266 }
267
268 // Check if the diagonal elements are 1 and the rest are 0
269 for (my_size_t i = 0; i < this->getDim(0); i++)
270 {
271 for (my_size_t j = 0; j < this->getDim(1); j++)
272 {
273 if (i == j)
274 {
275 if (math::abs((*this)(i, j) - T(1)) > T(PRECISION_TOLERANCE))
276 {
277 return false;
278 }
279 }
280 else
281 {
282 if (math::abs((*this)(i, j)) > T(PRECISION_TOLERANCE))
283 {
284 return false;
285 }
286 }
287 }
288 }
289 return true;
290 }
291
292 bool isSymmetric(void) const
293 {
294 // Check if the matrix is square
295 if (!this->areDimsEqual())
296 {
297 MyErrorHandler::error("FusedMatrix is not square");
298 }
299
300 // use the fact that A = A^T for symmetric matrices
301 // use transpose() to get the transpose of the matrix
302 // and see if it's equal to the original matrix
303
304 return (*this == this->transpose_view());
305 }
306
307 bool isUpperTriangular(void) const
308 {
309 my_size_t rows = this->getDim(0);
310 my_size_t cols = this->getDim(1);
311
312 for (my_size_t i = 1; i < rows; ++i)
313 {
314 // Below-diagonal entries: columns 0 to min(i, cols) - 1
315 my_size_t jmax = (i < cols) ? i : cols;
316 for (my_size_t j = 0; j < jmax; ++j)
317 {
318 if (math::abs((*this)(i, j)) > T(PRECISION_TOLERANCE))
319 {
320 return false;
321 }
322 }
323 }
324 return true;
325 }
326
327 bool isLowerTriangular(void) const
328 {
329 my_size_t rows = this->getDim(0);
330 my_size_t cols = this->getDim(1);
331
332 for (my_size_t i = 0; i < rows; ++i)
333 {
334 for (my_size_t j = i + 1; j < cols; ++j)
335 {
336 if (math::abs((*this)(i, j)) > T(PRECISION_TOLERANCE))
337 {
338 return false;
339 }
340 }
341 }
342 return true;
343 }
344
345 FusedMatrix upperTriangular(bool inplace = false)
346 {
347 // Check if the matrix is square
348 if (!this->areDimsEqual())
349 {
350 MyErrorHandler::error("FusedMatrix is not square");
351 }
352
353 my_size_t matrix_size = this->getDim(0); // Assuming the matrix is square the number of rows and columns are equal
354
355 if (!inplace)
356 {
357 // Create a copy and modify it
358 // std::cout << "Setting matrix to upper triangular" << std::endl;
359 FusedMatrix result = *this;
360 for (my_size_t i = 1; i < matrix_size; i++)
361 {
362 for (my_size_t j = 0; j < i; j++)
363 {
364 result(i, j) = T(0);
365 }
366 }
367 return result;
368 }
369 else
370 {
371 // std::cout << "Setting matrix to upper triangular in place" << std::endl;
372 // Modify the matrix in-place
373 for (my_size_t i = 1; i < matrix_size; i++)
374 {
375 for (my_size_t j = 0; j < i; j++)
376 {
377 (*this)(i, j) = T(0);
378 }
379 }
380 return *this; // Returning the modified matrix itself
381 }
382 }
383
384 FusedMatrix lowerTriangular(bool inplace = false)
385 {
386 // Check if the matrix is square
387 if (!this->areDimsEqual())
388 {
389 MyErrorHandler::error("FusedMatrix is not square");
390 }
391
392 my_size_t matrix_size = this->getDim(0); // Assuming the matrix is square the number of rows and columns are equal
393
394 if (!inplace)
395 {
396 // Create a copy and modify it
397 // std::cout << "Setting matrix to lower triangular" << std::endl;
398 FusedMatrix result = *this;
399 for (my_size_t i = 0; i < matrix_size; i++)
400 {
401 for (my_size_t j = i + 1; j < matrix_size; j++)
402 {
403 result(i, j) = T(0);
404 }
405 }
406 return result;
407 }
408 else
409 {
410 // std::cout << "Setting matrix to lower triangular in place" << std::endl;
411 // Modify the matrix in-place
412 for (my_size_t i = 0; i < matrix_size; i++)
413 {
414 for (my_size_t j = i + 1; j < matrix_size; j++)
415 {
416 (*this)(i, j) = T(0);
417 }
418 }
419 return *this; // Returning the modified matrix itself
420 }
421 }
422
423 /* Invers operation using Gauss-Jordan algorithm */
425 {
426 if (!this->areDimsEqual())
427 {
428 MyErrorHandler::error("FusedMatrix is non-invertible cause: not square");
429 }
430
431 // check if is identity
432 if (this->isIdentity())
433 {
434 return *this;
435 }
436
437 FusedMatrix _outp = *this;
438 FusedMatrix _temp = *this;
439
440 my_size_t rows = _temp.getDim(0);
441 my_size_t cols = _temp.getDim(1);
442 _outp.setIdentity();
443
444 /* Gauss Elimination... */
445 for (my_size_t j = 0; j < rows - 1; j++)
446 {
447 for (my_size_t i = j + 1; i < rows; i++)
448 {
449 if (math::abs(_temp(j, j)) < T(PRECISION_TOLERANCE))
450 {
451 /* FusedMatrix is non-invertible */
452 MyErrorHandler::error("FusedMatrix is non-invertible cause: diagonal element is zero (Gauss Elimination)");
453 }
454
455 T tmp = _temp(i, j) / _temp(j, j);
456
457 for (my_size_t k = 0; k < cols; k++)
458 {
459 _temp(i, k) -= (_temp(j, k) * tmp);
460 _outp(i, k) -= (_outp(j, k) * tmp);
461
462 // round _temp(i, k) to zero if it's too small
463 // round _outp(i, k) to zero if it's too small
464 }
465 }
466 }
467
468 /* At this point, the _temp matrix should be an upper triangular matrix.
469 * But because of rounding error, it might not.
470 * Make it upper triangular by setting the lower triangular to zero.
471 */
472 _temp.upperTriangular(true);
473
474 /* Jordan... */
475 for (my_size_t j = rows - 1; j > 0; j--)
476 {
477 for (int i = j - 1; i >= 0; i--)
478 {
479 if (math::abs(_temp(j, j)) < T(PRECISION_TOLERANCE))
480 {
481 /* FusedMatrix is non-invertible */
482 MyErrorHandler::error("FusedMatrix is non-invertible cause: diagonal element is zero (Jordan)");
483 }
484
485 T tmp = _temp(i, j) / _temp(j, j);
486 _temp(i, j) -= (_temp(j, j) * tmp);
487
488 // round _temp(i, j) to zero if it's too small
489
490 for (int k = rows - 1; k >= 0; k--)
491 {
492 _outp(i, k) -= (_outp(j, k) * tmp);
493
494 // round _outp(i, k) to zero if it's too small
495 }
496 }
497 }
498
499 /* Normalize the matrix */
500 for (my_size_t i = 0; i < rows; i++)
501 {
502 if (math::abs(_temp(i, i)) < T(PRECISION_TOLERANCE))
503 {
504 /* FusedMatrix is non-invertible */
505 MyErrorHandler::error("FusedMatrix is non-invertible cause: diagonal element is zero (Normalization)");
506 }
507
508 T tmp = _temp(i, i);
509 _temp(i, i) = T(1.0);
510
511 for (my_size_t j = 0; j < cols; j++)
512 {
513 _outp(i, j) /= tmp;
514 }
515 }
516 return _outp;
517 }
518
519 bool isOrthogonal(void)
520 {
521 // Check if the matrix is square
522 if (!this->areDimsEqual())
523 {
524 MyErrorHandler::error("FusedMatrix is not square");
525 }
526
527 auto ident = FusedMatrix<T, Rows, Cols>::matmul(*this, this->transpose_view());
528 if (!ident.isIdentity())
529 {
530 return false;
531 }
532
533 auto ident1 = FusedMatrix<T, Rows, Cols>::matmul(this->transpose_view(), *this);
534 if (!ident1.isIdentity())
535 {
536 return false;
537 }
538 return true;
539 }
540
554 {
555 // Strict: rejects near-zero diagonals
556 auto strict = matrix_algorithms::cholesky(*this);
557 if (strict.has_value())
558 {
560 }
561
562 // Relaxed: allows zero diagonals (semi-definite)
563 // Negative tolerance lets exact-zero diagonals pass while
564 // still rejecting truly negative ones.
565 auto relaxed = matrix_algorithms::cholesky(*this, T(-PRECISION_TOLERANCE));
566 if (relaxed.has_value())
567 {
569 }
570
572 }
573};
574
575#endif // FUSEDMATRIX_H
Cholesky decomposition for symmetric positive-definite matrices.
Definition BaseExpr.h:15
static void log(const T &msg, ErrorLevel level=ErrorLevel::Plain)
Definition error_handler.h:18
static void error(const T &msg)
Definition error_handler.h:30
Definition fused_matrix.h:12
bool isSymmetric(void) const
Definition fused_matrix.h:292
FusedMatrix & setDiagonal(T _val)
Definition fused_matrix.h:224
const T & operator()(my_size_t i, my_size_t j) const
Definition fused_matrix.h:188
FusedMatrix & setIdentity(void)
Definition fused_matrix.h:234
FusedMatrix(const FusedMatrix &other)
Definition fused_matrix.h:25
FusedTensorND< T, Rows, Cols > copyToTensor(void) const
Definition fused_matrix.h:87
FusedMatrix(const FusedTensorND< T, Rows, Cols > &baseTensor)
Definition fused_matrix.h:34
FusedMatrix & operator=(FusedTensorND< T, Rows, Cols > &&other) noexcept
Definition fused_matrix.h:145
FusedMatrix(FusedMatrix &&other) noexcept
Definition fused_matrix.h:43
FusedMatrix & operator=(const FusedTensorND< T, Rows, Cols > &other)
Definition fused_matrix.h:120
bool isLowerTriangular(void) const
Definition fused_matrix.h:327
FusedMatrix(T initValue)
Definition fused_matrix.h:21
bool isOrthogonal(void)
Definition fused_matrix.h:519
FusedMatrix lowerTriangular(bool inplace=false)
Definition fused_matrix.h:384
FusedMatrix & setToZero(void)
Definition fused_matrix.h:194
FusedMatrix & setSequencial(void)
Definition fused_matrix.h:244
FusedMatrix & operator=(const BaseExpr< Expr > &expr)
Definition fused_matrix.h:109
FusedMatrix & operator=(FusedMatrix< T, Rows, Cols > &&other) noexcept
Definition fused_matrix.h:155
FusedMatrix & setRandom(my_size_t _maxRand, my_size_t _minRand)
Definition fused_matrix.h:214
FusedMatrix(FusedTensorND< T, Rows, Cols > &&baseTensor) noexcept
Definition fused_matrix.h:52
static constexpr FusedMatrix moveFromTensor(FusedTensorND< T, Rows, Cols > &&tensor)
Definition fused_matrix.h:78
FusedMatrix()
Definition fused_matrix.h:17
FusedMatrix & operator=(const FusedMatrix &other)
Definition fused_matrix.h:130
FusedMatrix & setHomogen(T _val)
Definition fused_matrix.h:204
FusedTensorND< T, Rows, Cols > moveToTensor(void)
Definition fused_matrix.h:97
bool isIdentity(void) const
Definition fused_matrix.h:260
FusedMatrix(T(&initList)[Rows][Cols])
Definition fused_matrix.h:61
FusedMatrix & operator=(T(&initList)[Rows][Cols])
Definition fused_matrix.h:165
static FusedMatrix< T, Rows, Cols > matmul(const BaseExpr< LeftExpr > &mat1, const BaseExpr< RightExpr > &mat2)
Definition fused_matrix.h:255
matrix_traits::Definiteness isPositiveDefinite() const
Determine if the matrix is positive definite, semi-definite, or neither.
Definition fused_matrix.h:553
T & operator()(my_size_t i, my_size_t j)
Definition fused_matrix.h:183
FusedMatrix inverse(void) const
Definition fused_matrix.h:424
DEFINE_TYPE_ALIAS(T, value_type)
bool isUpperTriangular(void) const
Definition fused_matrix.h:307
FusedMatrix upperTriangular(bool inplace=false)
Definition fused_matrix.h:345
Definition fused_tensor.h:31
FusedTensorND & setSequencial(void)
Definition fused_tensor.h:428
FusedTensorND & setIdentity(void)
Definition fused_tensor.h:408
FORCE_INLINE auto transpose_view() const noexcept
Definition fused_tensor.h:304
FusedTensorND & setDiagonal(T _val)
Definition fused_tensor.h:383
FusedTensorND & setToZero(void) noexcept
Definition fused_tensor.h:347
T & operator()(Indices... indices) TESSERACT_CONDITIONAL_NOEXCEPT
Definition fused_tensor.h:206
FusedTensorND & setHomogen(T _val) noexcept
Definition fused_tensor.h:355
FusedTensorND & operator=(const BaseExpr< Expr > &expr)
Definition fused_tensor.h:95
static constexpr bool areDimsEqual()
Definition fused_tensor.h:246
static FORCE_INLINE constexpr my_size_t getDim(my_size_t i) TESSERACT_CONDITIONAL_NOEXCEPT
Definition fused_tensor.h:804
T value_type
Definition fused_tensor.h:37
FusedTensorND & setRandom(T _maxRand, T _minRand)
Definition fused_tensor.h:363
static FusedTensorND einsum(const BaseExpr< LeftExpr > &_tensor1, const BaseExpr< RightExpr > &_tensor2, const my_size_t a, const my_size_t b)
Contract two tensors along specified axes using SIMD dot products.
Definition fused_tensor.h:484
#define my_size_t
Size/index type used throughout the library.
Definition config.h:126
#define PRECISION_TOLERANCE
Tolerance for floating-point comparisons (e.g. symmetry checks, Cholesky).
Definition config.h:117
Runtime property descriptors and error codes for matrices.
constexpr T abs(T x) noexcept
Compute the absolute value of a numeric value.
Definition math_utils.h:48
Expected< MatrixType, MatrixStatus > cholesky(const MatrixType &A, typename MatrixType::value_type tol=typename MatrixType::value_type(PRECISION_TOLERANCE))
Compute the Cholesky decomposition of a symmetric positive-definite matrix.
Definition cholesky.h:87
Definiteness
Describes the definiteness of a symmetric matrix.
Definition matrix_traits.h:20
@ PositiveSemiDefinite
All eigenvalues ≥ 0.
@ PositiveDefinite
All eigenvalues > 0.
@ NotPositiveDefinite
Neither positive definite nor semi-definite.
constexpr remove_reference_t< T > && move(T &&t) noexcept
Cast to rvalue reference (replacement for std::move).
Definition simple_type_traits.h:178