Repository navigation
Add the cd model: Cao & Dowd synthetic control with spillovers - #1
Merged
Merged
Conversation
load_california_cd(51) and load_california_cd(41) load the authors' 50-state-plus-DC cigarette-sales panel (1970-2000, treated from 1989), copied from jcao0/synthetic-control-spillover at commit 86004020, with the paper's exposure sets. .gitattributes keeps the authors' state list byte-identical (BOM and CRLF). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
method="cd" fits an intercept-adjusted simplex SCM for every unit, a fixed exposure structure (affected_units or a labeled effect_matrix), period-specific direct and spillover effects, Andrews-type P tests for C alpha_t = d, and the kappa_A specification test (arXiv:1902.07343v4). The defaults follow the authors' Proposition 99 replication code, so a default fit reproduces the paper's Section 6 tables: interpolated critical values (quantile_method="linear") and intervals that add the signed pre-treatment error quantiles (ci_method="published", returned by effect_ci). The paper's Section 4 definitions are available as quantile_method="empirical", ci_method="inversion" and reference_mode="leave_one_period_out". test_cd.py checks the 51- and 41-unit fits against the authors' frozen output, and Monte Carlo, leave-one-out and kappa_A statistics against their simulation code; the fixtures are in benchmarks/reference/cao_dowd. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Adds docs/models/cd.qmd: usage, inference options, how to reproduce Tables S.6-S.8 and Figure 4, and the three places where the authors' application code departs from the paper's Section 4 definitions. The model catalogue, README, datasets page, API reference, llms.txt and CHANGELOG now list cd as implemented. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The solver applied max(3000, scm_maxiter), so the field (default 900) had no effect. Default it to 3000 and pass it through unchanged. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
cmg777
approved these changes
Oct 16, 2026
cmg777
left a comment
Contributor
There was a problem hiding this comment.
Thanks — validated locally (tests, slow test, lint, mypy, fixture checksums). Merging as-is; follow-up PRs will fold cd into the package's single-config / per-model-subpackage architecture, switch defaults to the paper's (v3) definitions with your application-code behaviour kept as switches, and extend it to mlsynth's cd feature set.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Adds scspill's second model,
method="cd": the synthetic control method with spillovers of Cao & Dowd (arXiv:1902.07343v4).affected_unitsor a labeledeffect_matrix, then yields direct and spillover effects for each post-treatment period.C α_t = dviatest_hypothesis, pointwise intervals ineffect_ci, and theκ_Aspecification test.load_california_cd(51)andload_california_cd(41)load the authors' 50-states-plus-DC Proposition 99 panel, from jcao0/synthetic-control-spillover at commit86004020.quantile_method="empirical",ci_method="inversion",reference_mode="leave_one_period_out"). The differences between the two are listed under Caveats indocs/models/cd.qmd.sarbehaves as before. It is still the default whenmethodis omitted, and its tests are unchanged.Commits
cd.py, themethoddispatch,test_cd.py, and the reference fixtures from the authors.llms.txt, and the CHANGELOG.scm_maxitercontrol the SLSQP iteration limit.Where to look
scspill/utils/scspill_helpers/cd.py: the estimator and the tests (about 520 lines).scspill/estimators/scspill.py: themethoddispatch (about 20 lines).scspill/tests/test_cd.py: checks against the paper and the authors' output.docs/models/cd.qmd: usage, how to reproduce the paper, and the caveats.About 2,500 of the added lines are data and fixtures copied as-is from the authors' repository: the CSVs and
benchmarks/reference/cao_dowd/.Validation
κ_Areference statistics, all compared against the authors' simulation code.make testgave 193 passed and 1 skipped; the slow tests,make lintandmypyalso pass.Caveats (documented, not bugs in this PR)