Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion .github/workflows/ai_pr_review.yml
Original file line number Diff line number Diff line change
Expand Up @@ -340,9 +340,13 @@ jobs:
echo "Unified diff (context=5):"
# Exclude large generated/data files from the full diff to stay
# within the model's input limit. The --name-status above still
# lists them. Narrowed to real-data assets and notebook outputs.
# lists them. Narrowed to real-data assets, notebook outputs, and
# the qte golden fixture (generated single-line JSON, ~700KB - a
# regeneration blew the input limit at PR #688; the reviewable
# artifact is benchmarks/R/generate_qte_golden.R).
git --no-pager diff --unified=5 "$BASE_SHA" "$HEAD_SHA" \
-- . ':!benchmarks/data/real/*.json' ':!benchmarks/data/real/*.csv' \
':!benchmarks/data/qte_golden.json' \
':!docs/tutorials/*.ipynb'
} >> "$PROMPT"

Expand Down
30 changes: 23 additions & 7 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -83,20 +83,36 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
DiD for the canonical 2x2 design with continuous outcomes: `ChangesInChanges`
(alias `CiC`) recovers the treated group's full counterfactual outcome
distribution and quantile treatment effects via the CDF transformation
`F_10(F_00^{-1}(F_01(y)))`, invariant to monotone outcome rescaling; `QDiD`
`F_10(F_00^{-1}(F_01(y)))`, invariant to monotone outcome rescaling
(unconditional fits; the covariate QR branch is not); `QDiD`
is the paper's additive quantile-DiD comparison estimator. Point estimation
matches R `qte` 1.3.1 exactly (CiC via an exact port of R's type-1 quantile
arithmetic incl. its fuzz handling - bit-exact golden parity; QDiD via qte's
type-7 form, documented in REGISTRY.md as a finite-sample deviation from the
paper's transformation, population-equivalent). Bootstrap-only inference
(panel unit-block or pooled repeated-cross-section resampling per qte's
schemes; seedable, `n_bootstrap=200` default; replicate-SD SEs, normal
intervals, sup-t uniform bands at qte's fixed 95% level). Diagnostics:
interior-range guard (eq. 17) with NaN inference outside, support-violation /
heavy-ties / QDiD-non-monotonicity warnings. Deferred and documented:
covariates, discrete-outcome bounds, analytical SEs, staggered designs.
Golden fixtures: `benchmarks/R/generate_qte_golden.R` (qte pinned 1.3.1) ->
`benchmarks/data/qte_golden.json`.
intervals, sup-t uniform bands at qte's fixed 95% level). Covariates are
supported on both estimators (`covariates=[...]` or trailing formula terms),
porting qte's `xformla` branch exactly: per-cell linear quantile regressions
(Koenker-Bassett LP via scipy HiGHS) on qte's fixed internal 0.01-0.99 tau
grid, quantreg `predict.rqs` Fhat/Qhat step-function conventions verbatim,
per-observation conditional-rank imputation, QR refits inside every
bootstrap replicate, and a conditional-envelope support diagnostic
(Melly-Santangelo 2015, Assumption 4); the unconditional interior-range
guard applies to covariate-free fits only. Diagnostics: interior-range
guard (eq. 17) with NaN inference outside, support-violation / heavy-ties /
QDiD-non-monotonicity warnings (the latter two scoped as documented in
REGISTRY.md under covariates). Deferred and documented: the full
Melly-Santangelo covariate estimator, discrete-outcome bounds, analytical
SEs, staggered designs. Golden fixtures:
`benchmarks/R/generate_qte_golden.R` (qte pinned 1.3.1, quantreg 6.1) ->
`benchmarks/data/qte_golden.json`, with covariate scenarios, atol=0
convention micro-fixtures (`qr_cases`), and deterministic seeded SE blocks
(`cores=1`; qte's default forked bootstrap is not reproducible even seeded).
Cross-language covariate parity is layered - conventions bit-exact given R
inputs, LP solver proven optimal per tau, end-to-end results gated at
documented exact-tie selection bounds (see the REGISTRY Deviation note).

### Changed
- `diff_diff/guides/llms-autonomous.txt` no longer lists regression discontinuity as
Expand Down
6 changes: 0 additions & 6 deletions ROADMAP.md
Original file line number Diff line number Diff line change
Expand Up @@ -84,12 +84,6 @@ Extends DiD to duration / survival outcomes where standard methods fail (hazard

**Reference**: Deaner & Ku (2025), *AEA Conference Paper*.

### Quantile / Distributional DiD

Recover the full counterfactual distribution and quantile treatment effects (QTT), not just mean ATT. Changes-in-Changes (CiC) identification strategy.

**Reference**: Athey & Imbens (2006), *Econometrica*. (Ciaccio 2024 extension listed under Under Consideration.)

### CATT Meta-Learner for Heterogeneous Effects

ML-powered conditional ATT, using a doubly robust meta-learner to discover which units benefit most from treatment.
Expand Down
3 changes: 2 additions & 1 deletion TODO.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ generic sparse-FE, QR+SVD rank-detection redundancy, `check_finite` bypass — m
| Issue | Location | Origin | Effort | Priority |
|-------|----------|--------|--------|----------|
| `EfficientDiD` conditional path: the largest remaining O(n) stage is the sieve/nuisance construction outside the tiled pass (~9s at 10k). (The `_ridge_solve_weights` Python-prep shave landed 2026-07-07 — the `omega_stack[rest]` fancy-index copy and tail scatter are skipped when no row is zero-masked, byte-identical outputs; the `zero_mask` abs scan itself remains, needed for correctness.) | `efficient_did_covariates.py` | CS-scaling | Mid | Low |
| `_rq_fit` LP assembly is dense (`A_eq = [X, I, -I]` with dense identity blocks, rebuilt per cell fit): a `scipy.sparse` construction would cut memory and likely HiGHS time for large cells / bootstrap-heavy covariate CiC/QDiD fits. CAVEAT before doing it: a different matrix representation can change HiGHS's vertex selection at degenerate/tied QR optima - end-to-end covariate goldens are tie-selection-gated (fine), but the `qr_cases` tight coefficient matches may shift to the equal-loss branch; re-run the parity suite and re-calibrate if needed. | `diff_diff/changes_in_changes.py::_rq_fit` | covariates PR | Quick | Low |
| Evaluate flipping `DIFF_DIFF_SOLVE_OLS_FASTPATH` default-ON after an opt-in soak (the 2026-07 certified normal-equations Cholesky fast path, both backends). A flip needs: golden/parity-suite recapture at the tol-bounded posture (fitted ~1e-8 abs / SE ~1e-6 rel — the default today is byte-pinned in several benchmark conventions), certification-rate telemetry across real workloads (any decline is silent-correct but forfeits the speedup), and the staged default-flip protocol used for `df_convention` (v4-class change). | `diff_diff/linalg.py::_resolve_solve_ols_fastpath`, `rust/src/linalg.rs::solve_ols_chol` | CS-scaling | Mid | Low |

### Testing / docs
Expand Down Expand Up @@ -112,7 +113,7 @@ Doable in principle, but no current caller and/or explicitly out of paper scope.

| Issue | Location | PR | Priority |
|-------|----------|----|----------|
| ChangesInChanges covariates (Melly-Santangelo 2015 QR pipeline: per-cell quantile-regression conditional CDFs -> conditional CiC -> integrate over treated-group covariates). No R parity target exists (the MS Stata code is the only implementation; distinct from Kranker's `cic`); would need simulation-based validation. Reviewed: `docs/methodology/papers/melly-santangelo-2015-review.md`. | `diff_diff/changes_in_changes.py` | #682 | Low |
| ChangesInChanges FULL Melly-Santangelo covariate estimator (monotonized integrated-indicator conditional CDFs, treated-post `F_{X|11}` integration, exchangeable bootstrap with variance-weighted KS bands, tail trimming, pre-period specification test). The qte-`xformla` simplified form of the MS pipeline SHIPPED in the covariates PR (`covariates=` on both estimators, parity-tested vs qte 1.3.1); this row's earlier "No R parity target exists" claim was WRONG and is corrected in the MS review doc. The full estimator has no reference implementation (the MS Stata code is the only one; distinct from Kranker's `cic`) and would need simulation-based validation. Reviewed: `docs/methodology/papers/melly-santangelo-2015-review.md`. | `diff_diff/changes_in_changes.py` | #682 | Low |
| ChangesInChanges discrete-outcome bounds + DCIC point identification (Athey-Imbens Sections 4/5.2 incl. Imbens-Manski intervals; Kranker's Stata `cic` is the reference). The shipped ties warning marks the boundary of the continuous scope. | `diff_diff/changes_in_changes.py` | #682 | Low |
| ChangesInChanges analytical SEs (Athey-Imbens Theorems 5.1-5.3 influence functions, panel 5.5-5.7, Appendix B covariances; needs the footnote-31 boundary density estimator - note the review's suspected half-range/midpoint typo). Bootstrap is the shipped inference. | `diff_diff/changes_in_changes.py` | #682 | Low |
| Staggered/multi-period distributional DiD (Athey-Imbens Section 6 / Ciaccio arXiv:2408.01208v2; `ecic` is the staggered event-study CiC lineage - a distinct method from Ciaccio's copula approach, do not conflate). Reviewed: `docs/methodology/papers/ciaccio-2024-review.md`; ROADMAP row is reviewed-deferred pending demand. | `diff_diff/changes_in_changes.py` | #682 | Low |
Expand Down
Loading
Loading