Commit 0a7b7e5
committed
jc/pillar-7-3d: fix repeated-eigenvalue eigvec recovery on rotated axisymmetric Σ
User-reported bug against the merged Pillar-7 probe (PR #403):
> When a covariance has a repeated eigenvalue but is not diagonal (for
> example an axisymmetric 3DGS splat with s = [2, 2, 1] and a nontrivial
> quaternion), A - λI is rank one and all row-pair cross products for the
> repeated λ are zero, so eigvec_for falls back to the same arbitrary
> vector for both equal eigenvalues. These duplicate, non-orthogonal
> vectors are then used by sqrt() and log_spd() for spectral
> reconstruction, producing a matrix that is not the square root/log of
> the input; the new 3D sandwich certification can therefore report
> incorrect results for common axisymmetric covariances even though the
> diagonal fast-path tests pass.
## Root cause
`Spd3::eig` called `eigvec_for` three times independently — one per
eigenvalue. For repeated eigenvalues (λ₁ = λ₂), both calls hit the
same matrix `A − λ·I`, picked the same largest cross-product among
row pairs, and returned the SAME unit vector. V was rank-deficient
and `spectral_reconstruct(sqrt λ, V)` was NOT the square root of Σ.
The diagonal fast-path branch (p1 < eps_diag) bypassed eigvec_for
entirely and returned the canonical basis — so axis-aligned tests
passed even though the rotated-axisymmetric case was broken.
The same bug existed in ndarray's `splat3d::spd3::recover_eigvecs`
in the initial PR 1 commit; it was fixed there during the PP-13 audit
loop (ndarray commit 08f90ff) with the same duplicate-detection pass
this commit applies to the jc probe.
## Fix
After the three independent `eigvec_for` recoveries:
1. Detect column pairs with |cos θ| > 0.99 (≈ 8° tolerance, well
above f64 roundoff). Demote the later column.
2. For each demoted column, fill via `gram_schmidt_complement_3d`
against the basis built from the remaining filled eigenvectors —
any orthogonal completion spans the degenerate eigenspace
equally well, so `Σ = V · diag(λ) · Vᵀ` is invariant.
3. Final modified-Gram-Schmidt pass via `orthonormalize_columns`
suppresses cross-orthogonality drift to ~1e-15 at f64.
## Regression tests added (4)
The diagonal fast-path tests and the random-rotation `sandwich_preserves_spd`
test did not exercise this code path. Four new tests target the
rotated-axisymmetric class explicitly:
- `rotated_axisymmetric_sqrt_squared_equals_sigma` — the user-reported
property. s = [2, 2, 1] (pancake splat) under a 30° rotation about
(1,1,1)/√3. sqrt(Σ)² must equal Σ. Pre-fix: ~5% error on diagonals.
Post-fix: ~1e-8 (f64 epsilon for compound computation).
- `rotated_axisymmetric_eigenvalues_are_correct` — eigenvalues = (4, 4, 1)
regardless of rotation. Tolerance 1e-7 (acos-based Smith-1961
accumulates ~1e-8 on quat-constructed inputs).
- `rotated_axisymmetric_eigvecs_orthonormal` — every column unit
length AND every pair orthogonal. Pre-fix: dot(v0, v1) ≈ 1 (same
vector). Post-fix: |dot| < 1e-9.
- `rotated_axisymmetric_log_spd_finite_and_correct` — log_spd uses
the same spectral lift; for Σ with eigenvalues (4, 4, 1),
‖log Σ‖_F² = 2·(ln 4)² ≈ 3.844. Pre-fix: log_spd corrupted by
rank-deficient V. Post-fix: matches analytical value to 1e-6.
## Test count
cargo test --manifest-path crates/jc/Cargo.toml --release
→ 64 passed (was 60: +4 regression tests, all green)
ewa_sandwich_3d::tests:
→ 13 passed (was 9: +4 new), pillar_passes still PASS
https://claude.ai/code/session_017GFLBnDy23AWBqvkbHHC411 parent c22b92d commit 0a7b7e5
1 file changed
Lines changed: 253 additions & 2 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
156 | 156 | | |
157 | 157 | | |
158 | 158 | | |
159 | | - | |
160 | | - | |
| 159 | + | |
| 160 | + | |
| 161 | + | |
| 162 | + | |
| 163 | + | |
| 164 | + | |
| 165 | + | |
| 166 | + | |
| 167 | + | |
| 168 | + | |
| 169 | + | |
| 170 | + | |
| 171 | + | |
| 172 | + | |
| 173 | + | |
| 174 | + | |
| 175 | + | |
| 176 | + | |
| 177 | + | |
| 178 | + | |
| 179 | + | |
| 180 | + | |
| 181 | + | |
| 182 | + | |
| 183 | + | |
161 | 184 | | |
162 | 185 | | |
163 | 186 | | |
164 | 187 | | |
| 188 | + | |
| 189 | + | |
| 190 | + | |
| 191 | + | |
| 192 | + | |
| 193 | + | |
| 194 | + | |
| 195 | + | |
| 196 | + | |
| 197 | + | |
| 198 | + | |
| 199 | + | |
| 200 | + | |
| 201 | + | |
| 202 | + | |
| 203 | + | |
| 204 | + | |
| 205 | + | |
| 206 | + | |
| 207 | + | |
165 | 208 | | |
166 | 209 | | |
167 | 210 | | |
| |||
287 | 330 | | |
288 | 331 | | |
289 | 332 | | |
| 333 | + | |
| 334 | + | |
| 335 | + | |
| 336 | + | |
| 337 | + | |
| 338 | + | |
| 339 | + | |
| 340 | + | |
| 341 | + | |
| 342 | + | |
| 343 | + | |
| 344 | + | |
| 345 | + | |
| 346 | + | |
| 347 | + | |
| 348 | + | |
| 349 | + | |
| 350 | + | |
| 351 | + | |
| 352 | + | |
| 353 | + | |
| 354 | + | |
| 355 | + | |
| 356 | + | |
| 357 | + | |
| 358 | + | |
| 359 | + | |
| 360 | + | |
| 361 | + | |
| 362 | + | |
| 363 | + | |
| 364 | + | |
| 365 | + | |
| 366 | + | |
| 367 | + | |
| 368 | + | |
| 369 | + | |
| 370 | + | |
| 371 | + | |
| 372 | + | |
| 373 | + | |
| 374 | + | |
| 375 | + | |
| 376 | + | |
| 377 | + | |
| 378 | + | |
| 379 | + | |
| 380 | + | |
| 381 | + | |
| 382 | + | |
| 383 | + | |
| 384 | + | |
| 385 | + | |
| 386 | + | |
| 387 | + | |
| 388 | + | |
| 389 | + | |
| 390 | + | |
| 391 | + | |
| 392 | + | |
| 393 | + | |
| 394 | + | |
| 395 | + | |
| 396 | + | |
| 397 | + | |
| 398 | + | |
| 399 | + | |
| 400 | + | |
| 401 | + | |
| 402 | + | |
| 403 | + | |
| 404 | + | |
| 405 | + | |
| 406 | + | |
| 407 | + | |
| 408 | + | |
| 409 | + | |
290 | 410 | | |
291 | 411 | | |
292 | 412 | | |
| |||
607 | 727 | | |
608 | 728 | | |
609 | 729 | | |
| 730 | + | |
| 731 | + | |
| 732 | + | |
| 733 | + | |
| 734 | + | |
| 735 | + | |
| 736 | + | |
| 737 | + | |
| 738 | + | |
| 739 | + | |
| 740 | + | |
| 741 | + | |
| 742 | + | |
| 743 | + | |
| 744 | + | |
| 745 | + | |
| 746 | + | |
| 747 | + | |
| 748 | + | |
| 749 | + | |
| 750 | + | |
| 751 | + | |
| 752 | + | |
| 753 | + | |
| 754 | + | |
| 755 | + | |
| 756 | + | |
| 757 | + | |
| 758 | + | |
| 759 | + | |
| 760 | + | |
| 761 | + | |
| 762 | + | |
| 763 | + | |
| 764 | + | |
| 765 | + | |
| 766 | + | |
| 767 | + | |
| 768 | + | |
| 769 | + | |
| 770 | + | |
| 771 | + | |
| 772 | + | |
| 773 | + | |
| 774 | + | |
| 775 | + | |
| 776 | + | |
| 777 | + | |
| 778 | + | |
| 779 | + | |
| 780 | + | |
| 781 | + | |
| 782 | + | |
| 783 | + | |
| 784 | + | |
| 785 | + | |
| 786 | + | |
| 787 | + | |
| 788 | + | |
| 789 | + | |
| 790 | + | |
| 791 | + | |
| 792 | + | |
| 793 | + | |
| 794 | + | |
| 795 | + | |
| 796 | + | |
| 797 | + | |
| 798 | + | |
| 799 | + | |
| 800 | + | |
| 801 | + | |
| 802 | + | |
| 803 | + | |
| 804 | + | |
| 805 | + | |
| 806 | + | |
| 807 | + | |
| 808 | + | |
| 809 | + | |
| 810 | + | |
| 811 | + | |
| 812 | + | |
| 813 | + | |
| 814 | + | |
| 815 | + | |
| 816 | + | |
| 817 | + | |
| 818 | + | |
| 819 | + | |
| 820 | + | |
| 821 | + | |
| 822 | + | |
| 823 | + | |
| 824 | + | |
| 825 | + | |
| 826 | + | |
| 827 | + | |
| 828 | + | |
| 829 | + | |
| 830 | + | |
| 831 | + | |
| 832 | + | |
| 833 | + | |
| 834 | + | |
| 835 | + | |
| 836 | + | |
| 837 | + | |
| 838 | + | |
| 839 | + | |
| 840 | + | |
| 841 | + | |
| 842 | + | |
| 843 | + | |
| 844 | + | |
| 845 | + | |
| 846 | + | |
| 847 | + | |
| 848 | + | |
| 849 | + | |
| 850 | + | |
| 851 | + | |
| 852 | + | |
| 853 | + | |
| 854 | + | |
| 855 | + | |
| 856 | + | |
| 857 | + | |
| 858 | + | |
| 859 | + | |
| 860 | + | |
610 | 861 | | |
0 commit comments