Commit a9ec8bd
Conley Wave A: DiD support, combined cluster kernel, sparse k-d-tree, callable metric validation
Four mechanical extensions on top of the Phase 1+2 Conley sandwich
(PR #426). All four touch the same surface (conley.py + linalg.py +
estimators.py + twfe.py + tests/test_conley_vcov.py).
- DiD.fit() accepts `unit=<col>` as a fit-time kwarg (NOT on __init__;
unused unless Conley is set; not part of get_params/set_params).
- Drops the prior fit-time redirect to MultiPeriodDiD.
- Validates unit/lag_cutoff/coords/cutoff_km; rejects survey_design
and wild_bootstrap with NotImplementedError.
- On a 2-period panel, matches MPD(...).fit(post_periods=[1],
reference_period=0) bit-exactly (atol=1e-10).
- compute_robust_vcov / LinearRegression / TWFE / DiD now accept
cluster_ids alongside vcov_type='conley'; meat applies
K_total[i,j] = K_space(d_ij/h) * 1{c_i == c_j}.
- Validator enforces cluster-time invariance on the panel block-
decomposed path (cluster constant within unit across periods).
- Per-slice mask construction (NOT full n×n) preserves memory on
panel paths; serial-component mask is trivially all-ones under
the invariance contract.
- TWFE auto-cluster on Conley path still silently dropped; explicit
cluster=<col> opts into combined kernel. DiD has no auto-cluster,
so opt-in is fully explicit. DiD-vs-TWFE asymmetry documented.
- linalg validator's conley + cluster_ids reject and twfe's
explicit-cluster reject both dropped.
- _compute_spatial_bartlett_meat_sparse uses
scipy.spatial.cKDTree.query_ball_tree to build a CSR sparse
kernel matrix instead of materializing the dense n×n distance.
- Auto-activates for n > _CONLEY_SPARSE_N_THRESHOLD (5_000) AND
metric in {haversine, euclidean} AND kernel == "bartlett".
- Bartlett-only gate: bartlett at u=1 returns exactly 0 so the
sparse path safely drops at-cutoff pairs; uniform at u=1 is 1
and would require closed-interval query semantics incompatible
with haversine chord projection roundoff.
- Haversine projects to 3-D unit-sphere Cartesian; chord query
radius matches arc-length cutoff with a 1e-12 relative epsilon
for projection roundoff; exact great-circle is recomputed only
for in-range neighbors.
- Private _conley_sparse: Optional[bool] kwarg controls the toggle
(None=auto, True=force, False=force dense; True with unsupported
config raises).
- Bit-identity parity vs dense at atol=1e-10 on synthetic fixtures;
R parity at atol=1e-6 preserved on all 3 panel R fixtures with
_conley_sparse=True forced.
- Renames _CONLEY_DENSE_WARN_N -> _CONLEY_DENSE_OOM_WARN_N (20_000)
to disambiguate from the new 5_000 sparse threshold; warning text
differentiates sparse-eligible vs dense-fallback paths.
- _validate_callable_metric_result checks shape (n,n), finite,
non-negative, symmetric within atol=1e-10.
- Each failure raises a targeted ValueError naming the violated
invariant. Previously, malformed callables produced opaque BLAS
errors deep in the pipeline.
Tests
- tests/test_conley_vcov.py: 36 new tests across TestConleySparse,
TestConleySparseRParityForced, TestConleyCluster,
TestConleyDistanceMetrics extension.
- Existing DiD-rejection / TWFE-explicit-cluster-reject /
linalg-conley-cluster-reject tests flipped to behavioral asserts.
- test_did_conley_matches_mpd_post_periods_1 locks the DiD-vs-MPD
bit-exact agreement on a 2-period panel.
- Full regression sweep (test_conley_vcov + test_linalg +
test_estimators + test_estimators_vcov_type + test_methodology_twfe
+ test_linalg_hc2_bm): 511 passed.
Docs
- docs/methodology/REGISTRY.md: new "Combined spatial + cluster
product kernel" subsection with math + cluster-time-invariance
contract + two-limit-fixture anchors; new "Performance / scale"
subsection on the sparse path; new "Callable conley_metric
validation" subsection; updated panel-API restrictions table;
DiD-vs-TWFE asymmetry paragraph.
- CHANGELOG.md: Unreleased Wave A entry; Phase 1+2 entry's
"DiD continues to raise" / "cluster_ids raises" text updated to
reflect the lifted rejects.
- diff_diff/guides/llms.txt + llms-full.txt: DiD support + combined
kernel + sparse path documented; restrictions list refreshed.
- README.md: catalog one-line refresh.
- TODO.md: rows for the four Wave A items removed; rows 121 (Conley
+ survey/weights, Bertanha-Imbens 2014) and 122 (SyntheticDiD
Conley path, spatial-block bootstrap) retained for later waves.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>1 parent d5e5021 commit a9ec8bd
14 files changed
Lines changed: 1644 additions & 200 deletions
File tree
- diff_diff
- guides
- docs
- api/_autosummary
- methodology
- tests
Large diffs are not rendered by default.
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
124 | 124 | | |
125 | 125 | | |
126 | 126 | | |
127 | | - | |
| 127 | + | |
128 | 128 | | |
129 | 129 | | |
130 | 130 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
116 | 116 | | |
117 | 117 | | |
118 | 118 | | |
119 | | - | |
120 | | - | |
121 | | - | |
122 | 119 | | |
123 | 120 | | |
124 | | - | |
125 | 121 | | |
126 | 122 | | |
127 | 123 | | |
| |||
0 commit comments