tesseract++ 0.0.1
N-dimensional tensor library for embedded systems
Loading...
Searching...
No Matches
inverse.h
Go to the documentation of this file.
1#ifndef FUSED_ALGORITHMS_INVERSE_H
2#define FUSED_ALGORITHMS_INVERSE_H
3
4#include "config.h"
6#include "matrix_traits.h"
9#include "math/math_utils.h"
10
37namespace matrix_algorithms
38{
39
41
64 template <typename T, my_size_t N>
66 {
67 static_assert(is_floating_point_v<T>,
68 "inverse requires a floating-point scalar type");
69
70 if constexpr (N == 1)
71 {
72 if (math::abs(A(0, 0)) <= T(PRECISION_TOLERANCE))
73 {
74 return Unexpected{MatrixStatus::Singular};
75 }
76
77 FusedMatrix<T, 1, 1> result(T(0));
78 result(0, 0) = T(1) / A(0, 0);
79 return move(result);
80 }
81 else if constexpr (N == 2)
82 {
83 T det = A(0, 0) * A(1, 1) - A(0, 1) * A(1, 0);
84
85 if (math::abs(det) <= T(PRECISION_TOLERANCE))
86 {
87 return Unexpected{MatrixStatus::Singular};
88 }
89
90 T inv_det = T(1) / det;
91
92 FusedMatrix<T, 2, 2> result(T(0));
93 result(0, 0) = A(1, 1) * inv_det;
94 result(0, 1) = -A(0, 1) * inv_det;
95 result(1, 0) = -A(1, 0) * inv_det;
96 result(1, 1) = A(0, 0) * inv_det;
97 return move(result);
98 }
99 else if constexpr (N == 3)
100 {
101 // Cofactors
102 T c00 = A(1, 1) * A(2, 2) - A(1, 2) * A(2, 1);
103 T c01 = A(1, 2) * A(2, 0) - A(1, 0) * A(2, 2);
104 T c02 = A(1, 0) * A(2, 1) - A(1, 1) * A(2, 0);
105
106 T det = A(0, 0) * c00 + A(0, 1) * c01 + A(0, 2) * c02;
107
108 if (math::abs(det) <= T(PRECISION_TOLERANCE))
109 {
110 return Unexpected{MatrixStatus::Singular};
111 }
112
113 T inv_det = T(1) / det;
114
115 FusedMatrix<T, 3, 3> result(T(0));
116
117 result(0, 0) = c00 * inv_det;
118 result(0, 1) = (A(0, 2) * A(2, 1) - A(0, 1) * A(2, 2)) * inv_det;
119 result(0, 2) = (A(0, 1) * A(1, 2) - A(0, 2) * A(1, 1)) * inv_det;
120
121 result(1, 0) = c01 * inv_det;
122 result(1, 1) = (A(0, 0) * A(2, 2) - A(0, 2) * A(2, 0)) * inv_det;
123 result(1, 2) = (A(0, 2) * A(1, 0) - A(0, 0) * A(1, 2)) * inv_det;
124
125 result(2, 0) = c02 * inv_det;
126 result(2, 1) = (A(0, 1) * A(2, 0) - A(0, 0) * A(2, 1)) * inv_det;
127 result(2, 2) = (A(0, 0) * A(1, 1) - A(0, 1) * A(1, 0)) * inv_det;
128
129 return move(result);
130 }
131 else if constexpr (N == 4)
132 {
133 // 2×2 minors from rows 0–1
134 T c0 = A(0, 0) * A(1, 1) - A(0, 1) * A(1, 0);
135 T c1 = A(0, 0) * A(1, 2) - A(0, 2) * A(1, 0);
136 T c2 = A(0, 0) * A(1, 3) - A(0, 3) * A(1, 0);
137 T c3 = A(0, 1) * A(1, 2) - A(0, 2) * A(1, 1);
138 T c4 = A(0, 1) * A(1, 3) - A(0, 3) * A(1, 1);
139 T c5 = A(0, 2) * A(1, 3) - A(0, 3) * A(1, 2);
140
141 // 2×2 minors from rows 2–3
142 T s0 = A(2, 0) * A(3, 1) - A(2, 1) * A(3, 0);
143 T s1 = A(2, 0) * A(3, 2) - A(2, 2) * A(3, 0);
144 T s2 = A(2, 0) * A(3, 3) - A(2, 3) * A(3, 0);
145 T s3 = A(2, 1) * A(3, 2) - A(2, 2) * A(3, 1);
146 T s4 = A(2, 1) * A(3, 3) - A(2, 3) * A(3, 1);
147 T s5 = A(2, 2) * A(3, 3) - A(2, 3) * A(3, 2);
148
149 T det = c0 * s5 - c1 * s4 + c2 * s3 + c3 * s2 - c4 * s1 + c5 * s0;
150
151 if (math::abs(det) <= T(PRECISION_TOLERANCE))
152 {
153 return Unexpected{MatrixStatus::Singular};
154 }
155
156 T inv_det = T(1) / det;
157
158 FusedMatrix<T, 4, 4> result(T(0));
159
160 // Adjugate transposed, row by row
161 result(0, 0) = (A(1, 1) * s5 - A(1, 2) * s4 + A(1, 3) * s3) * inv_det;
162 result(0, 1) = (-A(0, 1) * s5 + A(0, 2) * s4 - A(0, 3) * s3) * inv_det;
163 result(0, 2) = (A(3, 1) * c5 - A(3, 2) * c4 + A(3, 3) * c3) * inv_det;
164 result(0, 3) = (-A(2, 1) * c5 + A(2, 2) * c4 - A(2, 3) * c3) * inv_det;
165
166 result(1, 0) = (-A(1, 0) * s5 + A(1, 2) * s2 - A(1, 3) * s1) * inv_det;
167 result(1, 1) = (A(0, 0) * s5 - A(0, 2) * s2 + A(0, 3) * s1) * inv_det;
168 result(1, 2) = (-A(3, 0) * c5 + A(3, 2) * c2 - A(3, 3) * c1) * inv_det;
169 result(1, 3) = (A(2, 0) * c5 - A(2, 2) * c2 + A(2, 3) * c1) * inv_det;
170
171 result(2, 0) = (A(1, 0) * s4 - A(1, 1) * s2 + A(1, 3) * s0) * inv_det;
172 result(2, 1) = (-A(0, 0) * s4 + A(0, 1) * s2 - A(0, 3) * s0) * inv_det;
173 result(2, 2) = (A(3, 0) * c4 - A(3, 1) * c2 + A(3, 3) * c0) * inv_det;
174 result(2, 3) = (-A(2, 0) * c4 + A(2, 1) * c2 - A(2, 3) * c0) * inv_det;
175
176 result(3, 0) = (-A(1, 0) * s3 + A(1, 1) * s1 - A(1, 2) * s0) * inv_det;
177 result(3, 1) = (A(0, 0) * s3 - A(0, 1) * s1 + A(0, 2) * s0) * inv_det;
178 result(3, 2) = (-A(3, 0) * c3 + A(3, 1) * c1 - A(3, 2) * c0) * inv_det;
179 result(3, 3) = (A(2, 0) * c3 - A(2, 1) * c1 + A(2, 2) * c0) * inv_det;
180
181 return move(result);
182 }
183 else
184 {
185 // Generic LU path
186
187 // 1. Decompose P·A = L·U
188 auto lu_result = lu(A);
189
190 if (!lu_result.has_value())
191 {
192 return Unexpected{lu_result.error()};
193 }
194
195 auto &decomp = lu_result.value();
196
197 // 2. Build P·I (permuted identity)
198 FusedMatrix<T, N, N> PI(T(0));
199
200 for (my_size_t i = 0; i < N; ++i)
201 {
202 PI(i, decomp.perm(i)) = T(1);
203 }
204
205 // 3. Extract L and U for substitution
206 auto L = decomp.L();
207 auto U = decomp.U();
208
209 // 4. Solve L·Y = P·I (forward substitution, unit diagonal)
210 auto fwd_result = forward_substitute<true>(L, PI);
211
212 if (!fwd_result.has_value())
213 {
214 return Unexpected{fwd_result.error()};
215 }
216
217 auto &Y = fwd_result.value();
218
219 // 5. Solve U·X = Y (back substitution)
220 auto back_result = back_substitute(U, Y);
221
222 if (!back_result.has_value())
223 {
224 return Unexpected{back_result.error()};
225 }
226
227 return move(back_result.value());
228 }
229 }
230
241 template <typename T, my_size_t N>
243 {
244 auto result = inverse(A);
245
246 if (!result.has_value())
247 {
248 MyErrorHandler::error("matrix inverse failed: singular matrix");
249 }
250
251 return move(result.value());
252 }
253
254} // namespace matrix_algorithms
255
256#endif // FUSED_ALGORITHMS_INVERSE_H
static void error(const T &msg)
Definition error_handler.h:30
A discriminated union holding either a success value or an error.
Definition expected.h:86
Definition fused_matrix.h:12
Global configuration for the tesseract tensor library.
#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
A minimal, STL-free expected/result type for failable operations.
LU decomposition with partial pivoting for square matrices.
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
Definition cholesky.h:52
Expected< FusedMatrix< T, N, N >, MatrixStatus > inverse(const FusedMatrix< T, N, N > &A)
Compute the inverse of a square matrix.
Definition inverse.h:65
Expected< FusedVector< T, N >, MatrixStatus > back_substitute(const FusedMatrix< T, N, N > &U, const FusedVector< T, N > &b)
Solve the upper-triangular system Ux = b by back substitution.
Definition triangular_solve.h:216
FusedMatrix< T, N, N > inverse_or_die(const FusedMatrix< T, N, N > &A)
Matrix inverse — abort on failure.
Definition inverse.h:242
Expected< LUResult< T, N >, MatrixStatus > lu(const FusedMatrix< T, N, N > &A, T tol=T(PRECISION_TOLERANCE))
Compute the LU decomposition of a square matrix with partial pivoting.
Definition lu.h:151
MatrixStatus
Error codes for matrix decomposition and solver algorithms.
Definition matrix_traits.h:33
constexpr remove_reference_t< T > && move(T &&t) noexcept
Cast to rvalue reference (replacement for std::move).
Definition simple_type_traits.h:178
Tag type for constructing an Expected in the error state.
Definition expected.h:30
E error
The error value.
Definition expected.h:31
Forward/back substitution for triangular systems.