Fixes for control systems AND SVD and QR decomposition #9

Merged
Cynopolis merged 11 commits from fixes-for-control-systems into main 2026-08-26 13:08:22 -04:00
Owner
No description provided.
Cynopolis added 9 commits 2026-08-26 08:54:47 -04:00
- Snapshot bidiagonal block before solving (W overwrite corrupted Ublock)
- Wide-matrix QL row extent fix (rowsQL = n when transposed)
- Vt output copy bound j<columns (was OOB write clobbering caller sigma)
- Rank-deficient blocks: residual singular values sigma_i = ||B*v_i||
  instead of sqrt(eigs of B*B) (condition-number squaring); Gram-Schmidt
  orthonormalization of U columns with rank-deficiency completion
- JacobiEigenSymmetric: return signed eigenvalues (removed fabsf)
- Fix 28 WithinRel(0.0f,.) matcher misuse -> WithinAbs in matrix-tests
- New unit tests: SolveBidiagonalBlock2x2 (7 scipy-referenced cases),
  JacobiEigenSymmetric (3 cases), DeflateBidiagonal/BidiagonalIsDiagonal
- Full-rank random 5x5 (cond ~11.5)
- Rank-deficient 5x5 (exact rank 3, noise-level tail sigmas)
- Wide dynamic range 5x5 (cond ~9000, diagonal decay 50 -> 1e-3)
- Symmetric indefinite 5x5 (sigma = |eigenvalues|)
Replace the fixed 5x5 SVD implementation with template <uint8_t N>
building blocks over Matrix<N,N> working buffers (N = max(rows, cols)),
removing the 5x5 size limit. Public API (SVD::SVD) is unchanged and the
whole path stays heap-free: peak stack is ~11*N^2 floats, budgeted in
the SVD.hpp header doc.

Fixes found while porting/validating the templated rewrite:
- QL.Identity() was a no-op (static factory returns by value); init
  the Householder accumulators with an explicit diagonal loop
- restore the QL column sign-flip in ExtractAndSortSingularValues for
  negative unsolved W diagonal entries (Householder sign flips)
- T = B^T B tridiagonal formula: T[i][i] = d[i]^2 + e[i-1]^2 only
  (e[i] contributes to T[i+1][i+1], not T[i][i])
- wide-matrix Vt assembly: Vt = QL^T must be filled over the full
  m x m (m = columns of A), not just the top n x n

Tests:
- matrix-tests: add large-size instantiation cases beyond the old limit
  (tall 7x5 N=7, square 6x6 N=6, wide 5x8 N=8 transpose path with full
  orthogonal 8x8 Vt, tall 6x4 near rank-deficient N=6 deflation path),
  all checked against numpy/scipy float32 references
- svd-build-blocks-tests: adapt Jacobi test to the Matrix<N,N> interface
- svd-reference-values.py: add the four new reference matrices
Add QR eigen library: implicit Wilkinson-shifted QR for symmetric matrices
Merge-Checker / build_and_test (pull_request) Failing after 28m10s
c9a9492fcf
- src/QR.hpp / src/QR.cpp: fully templated QR::EigenQR (N >= 2), no heap
  allocation (3*N^2 float working buffers on stack). Givens tridiagonalization
  (bottom-up) + implicit Wilkinson-shifted QR with bulge chasing, relative
  deflation, exact-zero peeling, closed-form 2x2 termination.
- Matrix::EigenQR now delegates to QR::EigenQR (old unshifted body removed);
  eigenvalues sorted descending, eigenvectors in columns of the output.
- unit-tests/qr-build-blocks-tests.cpp: 8 building-block test cases
  (215 assertions) with scipy/numpy references.
- unit-tests/qr-reference-values.py: numpy/scipy reference generator mirroring
  every building block and the full pipeline (eigh, n=3..8).
- CMake: new 'qr' static library; Matrix links against it;
  qr-build-blocks-tests target enabled.
Cynopolis reviewed 2026-08-26 08:56:21 -04:00
@@ -8,0 +12,4 @@
// chain, pull in the full QR library so its template definition is available.
namespace QR {
template <uint8_t N>
void EigenQR(Matrix<N, N> &matrixToDecompose, Matrix<N, N> &eigenVectors,
Author
Owner

TODO: THis is weird.

TODO: THis is weird.
Author
Owner

No it makes sense because there is a bit of a circular include here.

Matrix.cpp -> includes QR.hpp -> includes Matrix.hpp -> includes Matrix.cpp

No it makes sense because there is a bit of a circular include here. Matrix.cpp -> includes QR.hpp -> includes Matrix.hpp -> includes Matrix.cpp
Cynopolis marked this conversation as resolved
Cynopolis added 1 commit 2026-08-26 12:23:07 -04:00
Got rid of unused function warnings
Merge-Checker / build_and_test (pull_request) Failing after 28m19s
c2f5520664
Cynopolis added 1 commit 2026-08-26 13:07:55 -04:00
Added an SVD passthrough to matrix.cpp
Merge-Checker / build_and_test (pull_request) Failing after 20m35s
b6a649bad9
Cynopolis merged commit f0035ab67f into main 2026-08-26 13:08:22 -04:00
Cynopolis deleted branch fixes-for-control-systems 2026-08-26 13:08:22 -04:00
Sign in to join this conversation.
No Reviewers
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: Cynopolis/Vector3D#9