Small structural matrix utilities that are needed across the library but do not belong to any single algorithm:
Symmetrizeenforces exact symmetry on a matrix that should be symmetric in theory but drifts under floating-point round-off.CongruenceTransformcomputes the quadratic formA·M·Aᵀ— the single most common shape in covariance-propagating code (Kalman predictF·P·Fᵀ, innovation covarianceH·P·Hᵀ, Joseph update(I−KH)·P·(I−KH)ᵀ, etc.).
Both are recurring needs in Kalman filters, EM parameter updates, and Riccati/Lyapunov solvers.
Any square matrix decomposes into a symmetric and a skew-symmetric part:
Symmetrize returns the symmetric part
If CongruenceTransform returns a symmetric result exactly (in exact arithmetic):
| Operation | Time | Space | Notes |
|---|---|---|---|
| Symmetrize | One transpose, add, scale | ||
| CongruenceTransform | For |
Symmetrize — for $M = \begin{bmatrix}1 & 3 \ -1 & 2\end{bmatrix}$: $M^\top = \begin{bmatrix}1 & -1 \ 3 & 2\end{bmatrix}$, so $\tfrac{1}{2}(M + M^\top) = \begin{bmatrix}1 & 1 \ 1 & 2\end{bmatrix}$ — off-diagonals averaged, diagonal unchanged.
CongruenceTransform — with
Symmetrize is not a fix for indefiniteness — it removes the skew part but does not make a matrix positive-definite; covariance code typically also adds a small diagonal jitter (+ εI) separately.
CongruenceTransform association — the implementation evaluates (A·M)·Aᵀ, matching the left-associative operator*; results are bit-identical to hand-written A * M * A.Transpose(). Under fast-math the symmetry of the output can still carry tiny round-off asymmetry — follow with Symmetrize when exact symmetry is required.
Float-only — both are static_assert(std::is_floating_point_v<T>).
The skew-symmetric part Symmetrize's companion. The transposed congruence DiscreteAlgebraicRiccatiEquation) is obtained by passing A.Transpose().
- Kalman predict / update —
F·P·Fᵀ,H·P·Hᵀ, Joseph form(I−KH)·P·(I−KH)ᵀ + K·R·Kᵀacross the KF/EKF/UKF/smoother family. - EM / covariance updates — re-symmetrize
Q,R,Pafter asymmetric matrix products (estimators::ExpectationMaximization). - Riccati / Lyapunov solutions — propagate and enforce symmetry of the solution matrix.
Operate on math::Matrix / math::SquareMatrix. Consumed by the filters::active Kalman family and estimators::ExpectationMaximization; CongruenceTransform pairs naturally with Symmetrize for covariance-positivity hygiene.
Matrix and vector dimensions must be strictly positive; a zero-length parameter vector is not representable. Element access on an empty fixed-size array has no valid index, so allowing it would trade a compile-time error for silent undefined behaviour.
A component without trainable parameters (for example a pooling or pure activation stage) should report the absence of parameters explicitly — an optional parameter vector that is empty, or an interface that has no parameter accessor at all — rather than returning a zero-length vector.
- Golub, G. H. & Van Loan, C. F., "Matrix Computations", 4th ed., §2 (symmetric/skew decomposition)
- Higham, N. J., "Accuracy and Stability of Numerical Algorithms", 2nd ed. (symmetry enforcement in covariance recursions)