perf(linalg): low-rank factored CR2-BM adjustment operators (8-108x)#664
perf(linalg): low-rank factored CR2-BM adjustment operators (8-108x)#664igerber wants to merge 3 commits into
Conversation
Overall Assessment✅ Looks good — no unmitigated P0/P1 findings. Executive Summary
Methodology
Code Quality
Performance
Maintainability
Tech Debt
Security
Documentation/Tests
Verification note: |
Unweighted G_g = I - H_gg with H_gg = X_g M_U X_g' of rank <= k, so
A_g = (I - U_g U_g')^{-1/2} = I + (U_g Q) diag(gamma) (U_g Q)' from the
k x k eigenproblem of U_g'U_g (U_g = X_g M_U^{1/2}), with Moore-Penrose
zeroing at 1-lambda <= 1e-10 matching _cr2_adjustment_matrix. Consumers
only apply A_g to skinny matrices (meat scores; X_g bread_inv for the
DOF omegas), so the dense (n_g, n_g) A_g -- an O(n_g^3) eigh per
cluster, ~85% of CR2-BM runtime -- is never materialized. gamma via
expm1/log1p (stable as lambda -> 0). The unweighted S_W/MUWTWUM build is
also skipped (S_W = X'X exactly). Weighted clubSandwich path unchanged
(its G_g carries the S_W bias term).
_compute_cr2_bm end-to-end: 18->2.3 ms (n=5k/G=50/k=10), 119->5.3 ms
(n=20k/G=100), 597->33 ms (n=100k/G=500), 4111->38 ms (n=100k/G=100/k=40).
Parity: frozen dense-eigh oracle at rtol 1e-12 (vcov) / 1e-10 (DOF) with
identical NaN-guard patterns across balanced/unbalanced/k=40/leverage-1
absorbed-FE/singletons/near-zero-leverage (TestCR2BMLowRankAdjustment);
281 linalg+vcov consumer tests, clubSandwich goldens, and 682 estimator
tests pass unchanged on both backends.
_cr2_bm_dof_inner now takes precomputed A_g_Xbi; the MPD build-once spy
re-anchored on the shared core (the dense per-cluster build no longer
exists to count). Rust CR2-BM TODO row re-scoped to Parked: the NumPy
path is now BLAS-bound, so the port buys ~nothing.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Lbd6nqWmg4snvvBmegwqiw
7eb2ea5 to
6b13e7d
Compare
|
🔁 AI review rerun (requested by @igerber) Head SHA: Overall Assessment✅ Looks good — no unmitigated P0/P1 findings. Executive Summary
Methodology
Code Quality
Performance
Maintainability
Tech Debt
Security
Documentation/Tests
Verification: |
… asserts CI failure on linux-arm (py3.11/3.13/3.14): the gamma-stability oracle comparison asserted rtol=1e-12 with no scale-aware atol; the low-rank and dense evaluations reduce in different GEMM orders, and the fixture's 5000-row cluster puts the ~1-ULP absolute drift (1.3e-17) on small-magnitude off-diagonals where OpenBLAS reads it as ~1.3e-12 relative (exact-equal on Accelerate). rtol -> 1e-11 with the reassociation caveat documented; the parametrized oracle test's scale-aware atol widened 1e-15 -> 1e-13 x max|vcov| as the same-class sibling hardening. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Lbd6nqWmg4snvvBmegwqiw
|
/ai-review |
|
🔁 AI review rerun (requested by @igerber) Head SHA: Overall Assessment✅ Looks good — no unmitigated P0/P1 findings. I found one P2 performance edge case worth addressing or tracking, but it is not a correctness blocker. Executive Summary
MethodologySeverity: P3 informational, no action required Code QualitySeverity: None PerformanceSeverity: P2 MaintainabilitySeverity: None Tech DebtSeverity: P3 informational, tracked SecuritySeverity: None Documentation/TestsSeverity: P3 Verification: |
Review P2: the k x k eigenproblem regresses vs the prior dense path when clusters are tiny relative to k (paired designs, singleton-heavy clusterings with many covariates) - O(G k^3) total. Clusters with n_g <= k now build the tiny dense G_g = I - U_g U_g' directly and reuse _cr2_adjustment_matrix verbatim (identical pseudoinverse convention); per-cluster work is O(n_g k min(n_g,k) + min(n_g,k)^3). Cost claims corrected on docstring/CHANGELOG/REGISTRY; new tiny-clusters-k-gt-ng oracle parity case (n_g=2, k=12) crosses both branches in one design. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Lbd6nqWmg4snvvBmegwqiw
|
🔁 AI review rerun (requested by @igerber) Head SHA: Overall Assessment✅ Looks good — no unmitigated P0/P1 findings. Executive Summary
MethodologySeverity: P3 informational, no action required Code QualitySeverity: None PerformanceSeverity: None MaintainabilitySeverity: None Tech DebtSeverity: P3 informational, tracked SecuritySeverity: None Documentation/TestsSeverity: P3 informational |
Summary
A_g = (I − H_gg)^{−1/2}are evaluated via a low-rank identity:H_gg = X_g M_U X_g'has rank ≤ k, soA_g = I + (U_g Q) diag(γ) (U_g Q)'from the k×k eigenproblem ofU_g'U_g(U_g = X_g M_U^{1/2}), with Moore-Penrose zeroing at1−λ ≤ 1e-10matching_cr2_adjustment_matrix's convention. Consumers only ever applyA_gto skinny matrices, so the dense(n_g, n_g)A_g— anO(n_g³)eigh per cluster, ~85% of CR2-BM runtime — is never materialized;γis evaluated viaexpm1/log1p(stable as λ→0). The unweightedS_W/MUWTWUMbuild is also skipped (S_W = X'Xexactly)._compute_cr2_bm: 18→2.3 ms (n=5k/G=50/k=10), 119→5.3 ms (n=20k/G=100), 597→33 ms (n=100k/G=500), 4111→38 ms, ~108x (n=100k/G=100/k=40).G_gcarries theS_Wbias term and is not a rank-k identity perturbation._cr2_bm_dof_innernow takes the precomputedA_g_Xbiblocks; the MPD build-once spy re-anchored on the shared core (the dense per-cluster build no longer exists to count).Methodology references (required if estimator / math changes)
Validation
tests/test_linalg.py::TestCR2BMLowRankAdjustment(frozen dense-eigh oracle across balanced/unbalanced/k=40/leverage-1 absorbed-cluster-FE/singletons + near-zero-leverage γ-stability);tests/test_estimators_vcov_type.py::TestMPDClusterHC2BMSharedPrecomputespy re-anchored on the shared core.Security / privacy
Generated with Claude Code