Many embedded control and estimation algorithms reduce to solving a dense linear system
For an
where:
-
$P \in {0,1}^{n \times n}$ is a permutation matrix encoding row swaps, -
$L \in \mathbb{R}^{n \times n}$ is unit lower-triangular ($L_{ii} = 1$ ,$L_{ij} = 0$ for$j > i$ ), -
$U \in \mathbb{R}^{n \times n}$ is upper-triangular ($U_{ij} = 0$ for$i > j$ ).
At step
-
Pivot selection: find
$p = \arg\max_{i \geq k} |A_{ik}|$ (the largest-magnitude entry in the current column from the diagonal down). -
Row swap: interchange rows
$k$ and$p$ in the working matrix and record the swap in$P$ . -
Elimination: for each
$i > k$ compute the multiplier$\ell_{ik} = A_{ik} / A_{kk}$ , store it below the diagonal, and update the trailing submatrix:
After
Given
Both passes cost math::SolveUnitLowerTriangular / math::SolveUpperTriangular kernels
(from math/TriangularSolve.hpp)
applied directly to the packed factor — the same triangular-solve building blocks
that back QrDecomposition.
The factored form is exposed for reuse by other components: L(), U(), and P()
return the individual factors (so callers can verify IsSingular() reports whether the last Decompose aborted.
The determinant of
The sign flips each time rows are swapped; it starts at
The inverse is formed by solving
| Operation | Time | Space | Notes |
|---|---|---|---|
Decompose |
GEPP in-place; multipliers packed with |
||
Solve |
Two triangular sweeps; reuses stored factors | ||
Determinant |
One pass over |
||
Inverse |
Solve suffices |
All storage is stack-allocated; the packed LU matrix and pivot vector are bounded by
Factor $A = \begin{pmatrix} 2 & 1 & -1 \ -3 & -1 & 2 \ -2 & 1 & 2 \end{pmatrix}$.
Step
Step
Step
The resulting
-
Zero pivot after partial pivoting: if the largest candidate in a column falls at or
below a relative threshold (
$\varepsilon_\text{rel},\max_k|A_{kk}|$ , with$\varepsilon_\text{rel} = 10^{-6}$ forfloat), the matrix is (numerically) rank-deficient. The factorization aborts and returnsfalse; the caller must not invokeSolveorInverse. A relative (rather than absolute) tolerance is essential: on a truly singular matrix the trailing pivot is a rounding-error residual whose magnitude scales with the matrix entries and varies across platforms/fast-mathsettings, so an absolute cutoff would miss it. -
Skipping pivoting: without row swaps, a matrix with
$A_{00} = 0$ would cause immediate division by zero; partial pivoting is mandatory for general matrices. -
Growth factor: partial pivoting bounds the element growth factor at
$2^{n-1}$ ; in practice growth is far smaller. For adversarial matrices, complete pivoting or iterative refinement provides stronger guarantees. -
Reusing the factored form:
InversecallsSolve$n$ times and is$O(n^3)$ ; preferSolvefor a single right-hand side to avoid the extra$O(n^3)$ work and the conditioning penalty of computing the inverse explicitly. -
Symmetric positive-definite systems: use
CholeskyDecompositioninstead — it is roughly twice as fast and requires no pivoting.
- Complete pivoting (GECP): swaps both rows and columns to achieve a smaller growth factor bound; rarely needed in practice but theoretically more stable.
-
Block LU: partitions
$A$ into blocks for cache-friendly BLAS-3 operations on large matrices; impractical for the small$n$ typical in embedded applications. - Sparse LU (SuperLU / KLU): reorders columns to minimise fill-in; relevant for finite-element or circuit matrices, not for dense embedded systems.
- Recursive LU: divides the matrix recursively for parallelism; incompatible with the no-recursion constraint of this library.
- General dense linear system solvers for observer and controller gains.
- One-shot or repeated-solve scenarios in model-predictive control warm-starting.
- Determinant computation for stability margins and matrix rank tests.
- Matrix inversion for covariance update steps where the explicit inverse is required.
-
GaussianEliminationperforms the same GEPP steps but does not retain the factored form, making it a single-shot solver;LuDecompositionamortises the$O(n^3)$ cost over multipleSolvecalls. -
CholeskyDecompositionis a specialised$O!\left(\tfrac{1}{3}n^3\right)$ factorization for symmetric positive-definite matrices — roughly$2\times$ faster and without the overhead of pivoting. -
QrDecompositionis preferred for least-squares (overdetermined) problems; for square full-rank systems, LU is faster. -
ConditionNumbercan be estimated cheaply after factorization by examining the ratio$\max_k |U_{kk}| / \min_k |U_{kk}|$ .
- G. H. Golub & C. F. Van Loan, Matrix Computations, 4th ed., Johns Hopkins UP, 2013, Ch. 3.
- W. H. Press et al., Numerical Recipes in C, 3rd ed., Cambridge UP, 2007, §2.3.
- L. N. Trefethen & D. Bau, Numerical Linear Algebra, SIAM, 1997, Lecture 20–22.