Skip to content

jc/pillar-7-3d: EWA-sandwich on 3×3 SPD covariances (Smith 1961)#403

Merged
AdaWorldAPI merged 1 commit into
mainfrom
claude/splat3d-cpu-simd-renderer-MAOO0
May 18, 2026
Merged

jc/pillar-7-3d: EWA-sandwich on 3×3 SPD covariances (Smith 1961)#403
AdaWorldAPI merged 1 commit into
mainfrom
claude/splat3d-cpu-simd-renderer-MAOO0

Conversation

@AdaWorldAPI
Copy link
Copy Markdown
Owner

Sibling of the 2D EWA-sandwich probe (Pillar 6 in module numbering;
line 9 of lib.rs comment). 3D analogue certifies the same Σ-push-
forward claim (PSD preservation + log-norm concentration via
sandwich M·Σ·Mᵀ) for the 3×3 SPD covariances consumed by
ndarray::hpc::splat3d in the J·W·Σ·Wᵀ·Jᵀ EWA projection.

  • Spd3 self-contained in f64 (zero dep on ndarray; matches the
    Pillar 6 Spd2 self-containment pattern)
  • Smith 1961 closed-form eigendecomp; eigenvector recovery via
    row-pair cross product + Gram-Schmidt fallback
  • 1000 paths × 10 hops, σ_step=0.2, joint PASS gate: PSD rate ≥ 0.999
    AND CV tightness ≤ 1.75 (3D CV formula: √(2/n)·√(1+3σ²n))
  • Registered as new pillar after EWA-Sandwich (2D) in run_all_pillars

https://claude.ai/code/session_017GFLBnDy23AWBqvkbHHC41

Sibling of the 2D EWA-sandwich probe (Pillar 6 in module numbering;
line 9 of lib.rs comment). 3D analogue certifies the same Σ-push-
forward claim (PSD preservation + log-norm concentration via
sandwich M·Σ·Mᵀ) for the 3×3 SPD covariances consumed by
ndarray::hpc::splat3d in the J·W·Σ·Wᵀ·Jᵀ EWA projection.

- Spd3 self-contained in f64 (zero dep on ndarray; matches the
  Pillar 6 Spd2 self-containment pattern)
- Smith 1961 closed-form eigendecomp; eigenvector recovery via
  row-pair cross product + Gram-Schmidt fallback
- 1000 paths × 10 hops, σ_step=0.2, joint PASS gate: PSD rate ≥ 0.999
  AND CV tightness ≤ 1.75 (3D CV formula: √(2/n)·√(1+3σ²n))
- Registered as new pillar after EWA-Sandwich (2D) in run_all_pillars

https://claude.ai/code/session_017GFLBnDy23AWBqvkbHHC41
Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 70866b69ec

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +160 to +164
let vecs = [
eigvec_for(self, lam1),
eigvec_for(self, lam2),
eigvec_for(self, lam3),
];
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Handle repeated 3D eigenvalues with an orthonormal basis

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.

Useful? React with 👍 / 👎.

@AdaWorldAPI AdaWorldAPI merged commit 252eb25 into main May 18, 2026
6 checks passed
AdaWorldAPI pushed a commit that referenced this pull request May 18, 2026
…isymmetric Σ

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_017GFLBnDy23AWBqvkbHHC41
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants