feat(synthetic_control): ADH-2015 §4 tail diagnostics (regression_weights + sparse_synthetic_control)#608
Conversation
…_weights + sparse_synthetic_control)
Close the last two Abadie-Diamond-Hainmueller (2015) §4 checklist items with two
opt-in SyntheticControlResults methods:
- regression_weights(): implied regression-counterfactual donor weights
W^reg = X0a'(X0a X0a')^{-1} X1a (intercept-augmented, min-norm least-squares),
flagging donors an OLS counterfactual would push outside [0,1] -- the extrapolation
the simplex-constrained synthetic control avoids. Pure linear algebra, no refit;
min-norm + rank-deficient warning when k+1 > J.
- sparse_synthetic_control(): exhaustive C(J,l) size-l donor subset search holding V
FIXED at the baseline fit (captured on the fit snapshot as fit_X1s/fit_X0s/fit_v),
reporting how fit/ATT degrade as the synthetic is forced sparse. Default sizes=[1,2,3]
skips over-cap sizes with a warning; an explicitly requested oversized l raises
(max_subsets guard).
Both surface under estimator_native_diagnostics (not_run -> populated) and leave the
analytical inference contract unchanged (se/t_stat/p_value/conf_int stay NaN). No
behavior change to any existing fit. Docs + paper-review checklist + 13 tests included.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LHDijzf8zHXk5T8ahS2mKi
PR Review ReportOverall Assessment✅ Looks good — no unmitigated P0/P1 findings. Executive Summary
MethodologyFinding 1Severity: P3 informational Code QualityNo findings. PerformanceNo findings. The combinatorial sparse search has a MaintainabilityNo findings. Tech DebtNo findings. The previous TODO item for these ADH-2015 tail diagnostics was removed because this PR implements it. SecurityNo findings. No secrets or sensitive literals were introduced in the changed files reviewed. Documentation/TestsFinding 1Severity: P3 informational |
Summary
SyntheticControl, closing the last two §4 checklist items:regression_weights()— the implied donor weightsW^reg = X0a'(X0a X0a')^{-1} X1aof the regression counterfactual (intercept-augmented, so they sum to 1 at full row rank), flagging donors an OLS counterfactual would push outside[0, 1]— the extrapolation the simplex-constrained synthetic control avoids. Pure linear algebra (no refit), computed as the min-norm least-squares solution with a rank-deficient warning.sparse_synthetic_control()— exhaustiveC(J, l)size-ldonor-subset search holdingVfixed at the baseline fit (captured on the fit snapshot), reporting how fit / ATT degrade as the synthetic is forced sparse. Defaultsizes=[1,2,3]skips over-cap sizes with a warning; an explicitly requested oversizedlraises (max_subsetsguard).estimator_native_diagnostics(not_run→ populated) and leave the analytical inference contract unchanged (se/t_stat/p_value/conf_intstay NaN). No behavior change to any existing fit — the only fit-path addition is capturing the(X1s, X0s, V)triple on the snapshot (nulled on pickle and in in-time-truncated snapshots).Methodology references (required if estimator / math changes)
SyntheticControl— Abadie-Diamond-Hainmueller (2015) §4 robustness diagnostics (regression-weight extrapolation; sparse-SC subset search).docs/methodology/REGISTRY.md§SyntheticControl; paper review indocs/methodology/papers/abadie-diamond-hainmueller-2015-review.md.regression_weights()computesW^regas a min-norm least-squares solution — identical to ADH's closed-form Gram inverse at full row rank, but well-defined and better-conditioned when the intercept-augmented predictor matrix is rank-deficient (k+1 > Jor collinear predictors); flagged with aUserWarningand documented as a REGISTRY Note (sum-to-one and row-scaling invariance both hold only at full row rank). No R anchor exists (RSynthhas neither diagnostic) — validated by a numpy oracle of theW^regformula and by self-consistency (the exhaustive sparse winner and its weights match an independent brute-force search using the same fixed baselineV).Validation
tests/test_methodology_synthetic_control.py(+19 tests) —W^regnumpy oracle, full-rank row-scaling invariance, rank-deficient min-norm warning, sparse brute-force self-consistency (provingVis held fixed, not re-searched),v_method="cv"validation-window capture,max_subsets/ non-integer-sizes/ empty-sizesinput validation, fail-closed on unpickled / non-converged / too-few-donors, and DiagnosticReport surfacing. Existing SyntheticControl + DiagnosticReport suites pass unchanged.Security / privacy
Generated with Claude Code