perf(two_stage): certified sparse-LSMR Stage-1 fallback — no dense normal-matrix materialization#666
perf(two_stage): certified sparse-LSMR Stage-1 fallback — no dense normal-matrix materialization#666igerber wants to merge 5 commits into
Conversation
Overall AssessmentExecutive Summary
MethodologyFinding: P3 informational Code QualitySeverity: None PerformanceSeverity: None MaintainabilityFinding: P3 Tech DebtSeverity: None SecuritySeverity: None Documentation/TestsFinding: P1 Finding: P3 Path To Approval
I did not run the suite; the local Python environment could not import |
|
🔁 AI review rerun (requested by @igerber) Head SHA: Overall Assessment✅ Looks good — no unmitigated P0/P1 findings. Prior P1 methodology-test regression is resolved. Executive Summary
MethodologyFinding: P3 informational Code QualitySeverity: None PerformanceSeverity: None MaintainabilityFinding: P3 Tech DebtSeverity: None SecuritySeverity: None Documentation/TestsFinding: P3 Severity: None |
|
🔁 AI review rerun (requested by @igerber) Head SHA: Overall Assessment✅ Looks good — no unmitigated P0/P1 findings. Executive Summary
MethodologyFinding: P3 informational Code QualitySeverity: None PerformanceSeverity: None MaintainabilitySeverity: None Tech DebtSeverity: None SecuritySeverity: None Documentation/TestsFinding: P3 Severity: P3 verification limitation |
|
🔁 AI review rerun (requested by @igerber) Head SHA: Overall Assessment✅ Looks good — no unmitigated P0/P1 findings. Executive Summary
MethodologyFinding: P3 informational Code QualitySeverity: None PerformanceSeverity: None MaintainabilitySeverity: None Tech DebtSeverity: None SecuritySeverity: None Documentation/TestsFinding: P3 Finding: P3 verification limitation |
…rmal-matrix materialization
The RuntimeError fallback for the sparse Stage-1 factorization called
np.linalg.lstsq(XtX_10.toarray(), ...) at four sites (analytical
unweighted + weighted GMM sandwich, SpilloverDiD Wave-D meat, bootstrap)
- an O((U+T+K)^2) densification and OOM risk. All four now solve via
certified per-column sparse LSMR (istop {0,1,2,4,5}; one uncapped
retry; _LSMRUnconvergedError on failure).
ANALYSIS (the TODO row's deliverable): the row cautioned that the
ImputationDiD null-space-invariance argument "does NOT transfer" because
gamma_hat feeds coefficient-level consumers. The consumer trace refutes
this: every gamma_hat/theta_exact consumer is an X_10-range functional -
Psi = X_10 @ gamma; the GMM score correction c_g' gamma with
c_g = X_{10,g}' eps_{10,g} in rowspace(X_10); Stage-1 residuals
y - X_10 theta - and null(X'X) = null(X_10) exactly, so the min-norm
ambiguity annihilates everywhere. Locked by a dense-lstsq-oracle parity
test on a singular Gram (consumer functional X @ z), a no-densify guard
through the full fit, and an uncertified-istop fail-closed test (NaN
overall_se/p_value; the raise matters because the GMM-score nan_to_num
would launder NaN scores into zeros).
Boundaries: analytical vcov -> NaN on _LSMRUnconvergedError (3 callers);
SpilloverDiD meat -> NaN matrix; bootstrap -> the established None
degenerate contract. 448 two_stage+spillover tests pass.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Lbd6nqWmg4snvvBmegwqiw
…ld lstsq warning tests/test_methodology_two_stage.py::test_singular_omega0_warns_and_falls_back still matched "lstsq" in the fallback warning (my sibling sweep covered tests/test_two_stage.py but missed the methodology file); now matches "falling back to sparse LSMR". Also the stale spillover.py re-factorization note describing the removed dense toarray() fallback (review P3). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Lbd6nqWmg4snvvBmegwqiw
…e spillover mentions Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Lbd6nqWmg4snvvBmegwqiw
…OG + test docstrings Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Lbd6nqWmg4snvvBmegwqiw
…vey note Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Lbd6nqWmg4snvvBmegwqiw
a87aa66 to
0876790
Compare
|
🔁 AI review rerun (requested by @igerber) Head SHA: Overall Assessment✅ Looks good — no unmitigated P0/P1 findings. Executive Summary
MethodologyFinding: P3 informational Code QualitySeverity: None PerformanceSeverity: None MaintainabilitySeverity: None Tech DebtSeverity: None SecuritySeverity: None Documentation/TestsFinding: P3 verification limitation |
Summary
RuntimeErrorfallback for the sparse Stage-1 factorization callednp.linalg.lstsq(XtX_10.toarray(), ...)at four sites (analytical unweighted + weighted GMM sandwich, the SpilloverDiD Wave-D meat, and the bootstrap) — anO((U+T+K)²)dense materialization and OOM risk on large panels. All four now solve via certified per-column sparse LSMR (istop ∈ {0,1,2,4,5}; one uncapped-conlim retry;_LSMRUnconvergedErroron failure).gamma_hatfeeds coefficient-level consumers. The consumer trace refutes this forgamma_hat(every consumer is anX_10-range functional:Psi = X_10 γ; the GMM score correctionc_g'γwithc_g ∈ rowspace(X_10);null(X'X) = null(X_10)exactly). The one consumer outside that argument — the bootstrap exact-residual helper'sX_1 @ theta_exacton treated rows — is covered by min-norm agreement: both dense lstsq (SVD) and LSMR return the min-norm least-squares solution._LSMRUnconvergedError(3 callers; the raise matters because the GMM-scorenan_to_numwould otherwise launder NaN scores into zeros and a finite, wrong variance); SpilloverDiD meat → NaN matrix; bootstrap → the establishedNonedegenerate contract.Methodology references (required if estimator / math changes)
Validation
tests/test_two_stage.py(helper-level singular-Gram oracle parity incl. multi-RHS; forced-fallback fit-level LSMR-vs-dense-oracle ATT/SE parity; no-lstsq guard through the full fit; uncertified-istop fail-closed NaN; weighted/survey fallback with unit-constant weights);tests/test_spillover.py(meat LSMR fallback + fail-closed NaN through the spillover boundary).Security / privacy
Generated with Claude Code