perf(linalg): opt-in solve_ols normal-equations Cholesky fast path (DIFF_DIFF_SOLVE_OLS_FASTPATH)#670
Conversation
…IFF_DIFF_SOLVE_OLS_FASTPATH) solve_ols is the universal OLS entry point; both backends run an equilibrated thin SVD (gelsd-parity) unconditionally. After #634's stage-0 certification removed the pivoted-QR cost, the SVD solve itself is the dominant stage on solver-bound fits (58%/54%/40% of SunAbraham county/firm and CS dr cov40). Setting DIFF_DIFF_SOLVE_OLS_FASTPATH=1 (positive integer; per-call resolver mirroring DIFF_DIFF_DEMEAN_CHUNK_COLS) routes certified-well-conditioned full-rank solves through an equilibrated normal-equations Cholesky: - numpy twin: reuses the stage-0 rank-certification artifacts (the Gram is already built to certify rank), gated by cho_factor + LAPACK dpocon at reciprocal condition > 1e-6 (the _IRLS_CHOL_RCOND_GUARD budget: forward error ~eps*cond <= 2e-10); self-builds and self-certifies on the skip_rank_check route (factorization success alone is not a certificate). - Rust kernel solve_ols_chol: SEPARATE self-certifying pyfunction (a stale extension degrades via the independent-import pattern instead of a call-time TypeError): faer Llt with the exact 1-norm rcond whose inverse byproduct doubles as the sandwich bread; ONE owned n x k buffer (the equilibrated copy, reused in place for the vcov scores - no thin-SVD U transient); faer-only heavy ops, so the accelerate/openblas/no-BLAS wheel variants behave identically; shared first-appearance cluster indexer with the SVD path. - Fallback contract: any certification decline falls through the UNCHANGED legacy chain (Rust SVD, then gelsd) on both dispatch routes, so knob-on-decline output equals knob-off exactly; solve_ols gains an optional diagnostics_out sink recording which branch ran. Measured (M4 Max, medians; committed A/B lane with a pristine-base-tree identity gate): SunAbraham 1.13->0.63 s and 16.77->9.89 s (1.7-1.8x), CallawaySantAnna dr 40-cov 4.40->3.57 s (1.23x), skip_rank_check micro 1.56x, weighted/survey twin 1.07x; estimate deltas <= 9e-15 ATT / 3e-12 rel SE; rust allocator high-water on the 2.4Mx130 clustered solve 7.27 -> 2.66 GB. Knob-off byte-identical to the base tree on every benchmark scenario. Also fixed (found while validating the non-finite-inference contract): the legacy Rust SVD vcov path silently returned all-Inf vcov on saturated full-rank designs (n == k) - the (n-k) adjustment divides by zero and the dispatcher fallback check keyed on NaN only. Both Rust vcov paths now return the documented all-NaN sentinel (matching the canonical numpy saturated guard, G >= 2 cluster error keeping precedence), and the dispatcher rejects any non-finite Rust vcov via a shared helper - on the skip_rank_check route only Inf reroutes (all-NaN remains the documented sentinel there; rerouting it to a full-rank-assuming numpy path could raise on a singular bread). CHANGELOG Fixed entry; sole qualified exception to the byte-identity claim. Tests: 57 cargo (LU oracles for beta/hc1/CR1, decline contracts, saturated NaN, G<2 precedence) + resolver/fast-path/dispatch/kernel/saturated pytest classes across both backends (property parity on ~20 designs, forced and natural-guard-trip byte-identity, BETWEEN fixture with self-check, default-path spy locks, WLS incl. zero weights, hc2/conley spot checks, 20-call clustered bit-determinism, stale-symbol degradation, Inf-injection reroutes on both routes, NaN-sentinel pass-through). Docs: CHANGELOG Added+Fixed, REGISTRY Note (thresholds, verbatim-fallback contract, tol-bounded-not-bit opt-in parity), performance-plan section with attribution/results/memory tables, doc-deps notes, TODO row swapped to the default-on-flip follow-up + cross-refs on the parked memory-floor and QR-reuse rows. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01GPX5Rv8ozQXPdUV23QTfjr
|
Overall Assessment ✅ Looks good — no unmitigated P0/P1 findings. Executive Summary
Methodology
Code Quality
Performance
Maintainability
Tech Debt
Security
Documentation/Tests
|
Summary
DIFF_DIFF_SOLVE_OLS_FASTPATH=1normal-equations Cholesky fast path forsolve_ols, both backends. After perf(linalg): per-cell solver fast paths - IRLS Cholesky inner solve + rank-detection certification (CS covariate fits 1.5-2x) #634's stage-0 Gram certification removed the pivoted-QR cost, the unconditional SVD solve is the dominant stage on solver-bound fits (58%/54%/40% of SunAbraham county/firm and CallawaySantAnna dr cov40 fit time). The knob routes certified-well-conditioned full-rank solves through an equilibrated normal-equations Cholesky; any certification decline falls through the UNCHANGED legacy chain verbatim.cho_factor+ LAPACKdpoconat reciprocal condition > 1e-6 (the_IRLS_CHOL_RCOND_GUARDerror budget, ~eps*cond <= 2e-10); self-builds and self-certifies on theskip_rank_checkroute.solve_ols_chol: separate self-certifying pyfunction (stale extensions degrade via the independent-import pattern): faerLlt, exact 1-norm rcond whose inverse byproduct doubles as the sandwich bread, one owned n x k buffer reused in place for the vcov scores (no thin-SVD U transient), faer-only heavy ops so the accelerate/openblas/no-BLAS wheel variants behave identically, shared first-appearance cluster indexer with the SVD path.benchmarks/speed_review/bench_solve_ols_fastpath.pywith a pristine-base-tree identity gate): SunAbraham 1.13->0.63 s / 16.77->9.89 s (1.7-1.8x), CS dr 40-covariate 4.40->3.57 s (1.23x),skip_rank_checkmicro-solve 1.56x, weighted/survey twin 1.07x; estimate deltas <= 9e-15 ATT / 3e-12 rel SE; rust allocator high-water on the 2.4Mx130 clustered solve 7.27 -> 2.66 GB. Knob-off ATT/SE byte-identical to the base tree on every scenario.skip_rank_checkroute only Inf reroutes — all-NaN remains the documented sentinel there). This is the sole, CHANGELOG-documented exception to the default-path byte-identity claim.Methodology references (required if estimator / math changes)
Validation
tests/test_linalg.py(resolver conventions; property parity across ~20 designs; forced-fallback and natural-guard-trip byte-identity with a self-checking BETWEEN fixture; default-path spy locks; skip_rank_check self-certification decline; WLS incl. zero weights; rank-deficient interplay; cert-artifact reuse bitwise equality; hc2/conley spot checks),tests/test_rust_backend.py(kernel-vs-twin parity at the established decimal bars; 20-call clustered bit-determinism; decline/None contracts; dispatch spies proving the default path unchanged; stale-symbol degradation; estimator-level SunAbraham + DiD-absorb-cluster parity; saturated-contract classes for both kernels; Inf-injection reroutes on both routes; NaN-sentinel pass-through), plus 7 new cargo tests (LU oracles, decline contracts, saturated NaN, G<2 precedence).benchmarks/speed_review/baselines/solve_ols_fastpath_{before,after}.json; results tables indocs/performance-plan.md.Security / privacy
🤖 Generated with Claude Code
https://claude.ai/code/session_01GPX5Rv8ozQXPdUV23QTfjr