diff-diff 3.6.2__tar.gz → 3.8.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (104) hide show
  1. {diff_diff-3.6.2 → diff_diff-3.8.0}/PKG-INFO +8 -4
  2. {diff_diff-3.6.2 → diff_diff-3.8.0}/README.md +3 -0
  3. {diff_diff-3.6.2 → diff_diff-3.8.0}/diff_diff/__init__.py +145 -119
  4. {diff_diff-3.6.2 → diff_diff-3.8.0}/diff_diff/_backend.py +85 -12
  5. diff_diff-3.8.0/diff_diff/_rdrobust_port.py +1913 -0
  6. {diff_diff-3.6.2 → diff_diff-3.8.0}/diff_diff/bacon.py +5 -2
  7. {diff_diff-3.6.2 → diff_diff-3.8.0}/diff_diff/bootstrap_chunking.py +165 -3
  8. {diff_diff-3.6.2 → diff_diff-3.8.0}/diff_diff/bootstrap_utils.py +7 -4
  9. {diff_diff-3.6.2 → diff_diff-3.8.0}/diff_diff/business_report.py +1 -1
  10. {diff_diff-3.6.2 → diff_diff-3.8.0}/diff_diff/chaisemartin_dhaultfoeuille.py +28 -11
  11. {diff_diff-3.6.2 → diff_diff-3.8.0}/diff_diff/chaisemartin_dhaultfoeuille_bootstrap.py +8 -8
  12. diff_diff-3.8.0/diff_diff/changes_in_changes.py +1429 -0
  13. diff_diff-3.8.0/diff_diff/changes_in_changes_results.py +242 -0
  14. {diff_diff-3.6.2 → diff_diff-3.8.0}/diff_diff/conformal.py +163 -19
  15. {diff_diff-3.6.2 → diff_diff-3.8.0}/diff_diff/continuous_did.py +836 -63
  16. {diff_diff-3.6.2 → diff_diff-3.8.0}/diff_diff/continuous_did_bspline.py +165 -0
  17. {diff_diff-3.6.2 → diff_diff-3.8.0}/diff_diff/continuous_did_results.py +33 -5
  18. {diff_diff-3.6.2 → diff_diff-3.8.0}/diff_diff/datasets.py +414 -5
  19. {diff_diff-3.6.2 → diff_diff-3.8.0}/diff_diff/diagnostic_report.py +13 -2
  20. {diff_diff-3.6.2 → diff_diff-3.8.0}/diff_diff/efficient_did.py +179 -44
  21. {diff_diff-3.6.2 → diff_diff-3.8.0}/diff_diff/efficient_did_bootstrap.py +83 -45
  22. {diff_diff-3.6.2 → diff_diff-3.8.0}/diff_diff/efficient_did_covariates.py +624 -2
  23. {diff_diff-3.6.2 → diff_diff-3.8.0}/diff_diff/efficient_did_results.py +4 -0
  24. {diff_diff-3.6.2 → diff_diff-3.8.0}/diff_diff/efficient_did_weights.py +175 -4
  25. {diff_diff-3.6.2 → diff_diff-3.8.0}/diff_diff/estimators.py +199 -25
  26. {diff_diff-3.6.2 → diff_diff-3.8.0}/diff_diff/guides/llms-autonomous.txt +39 -26
  27. {diff_diff-3.6.2 → diff_diff-3.8.0}/diff_diff/guides/llms-full.txt +210 -22
  28. {diff_diff-3.6.2 → diff_diff-3.8.0}/diff_diff/guides/llms-practitioner.txt +5 -0
  29. {diff_diff-3.6.2 → diff_diff-3.8.0}/diff_diff/guides/llms.txt +8 -3
  30. {diff_diff-3.6.2 → diff_diff-3.8.0}/diff_diff/had.py +454 -487
  31. {diff_diff-3.6.2 → diff_diff-3.8.0}/diff_diff/had_pretests.py +234 -589
  32. {diff_diff-3.6.2 → diff_diff-3.8.0}/diff_diff/honest_did.py +257 -72
  33. {diff_diff-3.6.2 → diff_diff-3.8.0}/diff_diff/imputation.py +361 -191
  34. {diff_diff-3.6.2 → diff_diff-3.8.0}/diff_diff/imputation_results.py +6 -0
  35. {diff_diff-3.6.2 → diff_diff-3.8.0}/diff_diff/linalg.py +1097 -128
  36. {diff_diff-3.6.2 → diff_diff-3.8.0}/diff_diff/local_linear.py +3 -10
  37. {diff_diff-3.6.2 → diff_diff-3.8.0}/diff_diff/power.py +6 -8
  38. {diff_diff-3.6.2 → diff_diff-3.8.0}/diff_diff/practitioner.py +610 -4
  39. {diff_diff-3.6.2 → diff_diff-3.8.0}/diff_diff/prep_dgp.py +4 -5
  40. {diff_diff-3.6.2 → diff_diff-3.8.0}/diff_diff/pretrends.py +1 -1
  41. {diff_diff-3.6.2 → diff_diff-3.8.0}/diff_diff/profile.py +16 -13
  42. diff_diff-3.8.0/diff_diff/rdd.py +1218 -0
  43. {diff_diff-3.6.2 → diff_diff-3.8.0}/diff_diff/results.py +26 -0
  44. {diff_diff-3.6.2 → diff_diff-3.8.0}/diff_diff/spillover.py +128 -118
  45. {diff_diff-3.6.2 → diff_diff-3.8.0}/diff_diff/staggered.py +695 -206
  46. {diff_diff-3.6.2 → diff_diff-3.8.0}/diff_diff/staggered_aggregation.py +365 -100
  47. {diff_diff-3.6.2 → diff_diff-3.8.0}/diff_diff/staggered_bootstrap.py +146 -105
  48. {diff_diff-3.6.2 → diff_diff-3.8.0}/diff_diff/staggered_results.py +9 -0
  49. {diff_diff-3.6.2 → diff_diff-3.8.0}/diff_diff/staggered_triple_diff.py +15 -4
  50. {diff_diff-3.6.2 → diff_diff-3.8.0}/diff_diff/sun_abraham.py +45 -6
  51. {diff_diff-3.6.2 → diff_diff-3.8.0}/diff_diff/survey.py +25 -64
  52. {diff_diff-3.6.2 → diff_diff-3.8.0}/diff_diff/synthetic_control_results.py +203 -3
  53. {diff_diff-3.6.2 → diff_diff-3.8.0}/diff_diff/synthetic_did.py +9 -2
  54. {diff_diff-3.6.2 → diff_diff-3.8.0}/diff_diff/triple_diff.py +7 -5
  55. {diff_diff-3.6.2 → diff_diff-3.8.0}/diff_diff/trop_local.py +0 -1
  56. {diff_diff-3.6.2 → diff_diff-3.8.0}/diff_diff/twfe.py +53 -31
  57. {diff_diff-3.6.2 → diff_diff-3.8.0}/diff_diff/two_stage.py +244 -203
  58. {diff_diff-3.6.2 → diff_diff-3.8.0}/diff_diff/two_stage_bootstrap.py +70 -48
  59. {diff_diff-3.6.2 → diff_diff-3.8.0}/diff_diff/utils.py +241 -17
  60. {diff_diff-3.6.2 → diff_diff-3.8.0}/diff_diff/wooldridge.py +2 -2
  61. {diff_diff-3.6.2 → diff_diff-3.8.0}/diff_diff/wooldridge_results.py +2 -2
  62. {diff_diff-3.6.2 → diff_diff-3.8.0}/pyproject.toml +45 -4
  63. {diff_diff-3.6.2 → diff_diff-3.8.0}/rust/Cargo.lock +64 -130
  64. {diff_diff-3.6.2 → diff_diff-3.8.0}/rust/Cargo.toml +1 -1
  65. diff_diff-3.8.0/rust/src/batched_solve.rs +353 -0
  66. {diff_diff-3.6.2 → diff_diff-3.8.0}/rust/src/lib.rs +9 -0
  67. diff_diff-3.8.0/rust/src/linalg.rs +1132 -0
  68. diff_diff-3.6.2/rust/src/linalg.rs +0 -503
  69. {diff_diff-3.6.2 → diff_diff-3.8.0}/LICENSE +0 -0
  70. {diff_diff-3.6.2 → diff_diff-3.8.0}/diff_diff/_guides_api.py +0 -0
  71. {diff_diff-3.6.2 → diff_diff-3.8.0}/diff_diff/_nprobust_port.py +0 -0
  72. {diff_diff-3.6.2 → diff_diff-3.8.0}/diff_diff/_reporting_helpers.py +0 -0
  73. {diff_diff-3.6.2 → diff_diff-3.8.0}/diff_diff/agent_workflow.py +0 -0
  74. {diff_diff-3.6.2 → diff_diff-3.8.0}/diff_diff/balancing.py +0 -0
  75. {diff_diff-3.6.2 → diff_diff-3.8.0}/diff_diff/chaisemartin_dhaultfoeuille_results.py +0 -0
  76. {diff_diff-3.6.2 → diff_diff-3.8.0}/diff_diff/conley.py +0 -0
  77. {diff_diff-3.6.2 → diff_diff-3.8.0}/diff_diff/diagnostics.py +0 -0
  78. {diff_diff-3.6.2 → diff_diff-3.8.0}/diff_diff/guides/__init__.py +0 -0
  79. {diff_diff-3.6.2 → diff_diff-3.8.0}/diff_diff/imputation_bootstrap.py +0 -0
  80. {diff_diff-3.6.2 → diff_diff-3.8.0}/diff_diff/lpdid.py +0 -0
  81. {diff_diff-3.6.2 → diff_diff-3.8.0}/diff_diff/lpdid_results.py +0 -0
  82. {diff_diff-3.6.2 → diff_diff-3.8.0}/diff_diff/prep.py +0 -0
  83. {diff_diff-3.6.2 → diff_diff-3.8.0}/diff_diff/stacked_did.py +0 -0
  84. {diff_diff-3.6.2 → diff_diff-3.8.0}/diff_diff/stacked_did_results.py +0 -0
  85. {diff_diff-3.6.2 → diff_diff-3.8.0}/diff_diff/staggered_triple_diff_results.py +0 -0
  86. {diff_diff-3.6.2 → diff_diff-3.8.0}/diff_diff/synthetic_control.py +0 -0
  87. {diff_diff-3.6.2 → diff_diff-3.8.0}/diff_diff/trop.py +1 -1
  88. {diff_diff-3.6.2 → diff_diff-3.8.0}/diff_diff/trop_global.py +0 -0
  89. {diff_diff-3.6.2 → diff_diff-3.8.0}/diff_diff/trop_results.py +0 -0
  90. {diff_diff-3.6.2 → diff_diff-3.8.0}/diff_diff/two_stage_results.py +0 -0
  91. {diff_diff-3.6.2 → diff_diff-3.8.0}/diff_diff/visualization/__init__.py +0 -0
  92. {diff_diff-3.6.2 → diff_diff-3.8.0}/diff_diff/visualization/_common.py +0 -0
  93. {diff_diff-3.6.2 → diff_diff-3.8.0}/diff_diff/visualization/_continuous.py +0 -0
  94. {diff_diff-3.6.2 → diff_diff-3.8.0}/diff_diff/visualization/_diagnostic.py +0 -0
  95. {diff_diff-3.6.2 → diff_diff-3.8.0}/diff_diff/visualization/_event_study.py +0 -0
  96. {diff_diff-3.6.2 → diff_diff-3.8.0}/diff_diff/visualization/_power.py +0 -0
  97. {diff_diff-3.6.2 → diff_diff-3.8.0}/diff_diff/visualization/_staggered.py +0 -0
  98. {diff_diff-3.6.2 → diff_diff-3.8.0}/diff_diff/visualization/_synthetic.py +0 -0
  99. {diff_diff-3.6.2 → diff_diff-3.8.0}/rust/build.rs +0 -0
  100. {diff_diff-3.6.2 → diff_diff-3.8.0}/rust/src/alloc_profile.rs +0 -0
  101. {diff_diff-3.6.2 → diff_diff-3.8.0}/rust/src/bootstrap.rs +0 -0
  102. {diff_diff-3.6.2 → diff_diff-3.8.0}/rust/src/demean.rs +0 -0
  103. {diff_diff-3.6.2 → diff_diff-3.8.0}/rust/src/trop.rs +0 -0
  104. {diff_diff-3.6.2 → diff_diff-3.8.0}/rust/src/weights.rs +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: diff-diff
3
- Version: 3.6.2
3
+ Version: 3.8.0
4
4
  Classifier: Development Status :: 5 - Production/Stable
5
5
  Classifier: Intended Audience :: Science/Research
6
6
  Classifier: Operating System :: OS Independent
@@ -20,9 +20,9 @@ Requires-Dist: scipy>=1.10
20
20
  Requires-Dist: pytest>=7.0 ; extra == 'dev'
21
21
  Requires-Dist: pytest-xdist>=3.0 ; extra == 'dev'
22
22
  Requires-Dist: pytest-cov>=4.0 ; extra == 'dev'
23
- Requires-Dist: black>=23.0 ; extra == 'dev'
24
- Requires-Dist: ruff>=0.1.0 ; extra == 'dev'
25
- Requires-Dist: mypy>=1.0 ; extra == 'dev'
23
+ Requires-Dist: black==26.3.1 ; extra == 'dev'
24
+ Requires-Dist: ruff==0.15.13 ; extra == 'dev'
25
+ Requires-Dist: mypy==2.1.0 ; extra == 'dev'
26
26
  Requires-Dist: maturin>=1.4,<2.0 ; extra == 'dev'
27
27
  Requires-Dist: matplotlib>=3.5 ; extra == 'dev'
28
28
  Requires-Dist: nbmake>=1.5 ; extra == 'dev'
@@ -32,6 +32,7 @@ Requires-Dist: pydata-sphinx-theme>=0.16.1 ; extra == 'docs'
32
32
  Requires-Dist: sphinxext-opengraph>=0.9 ; extra == 'docs'
33
33
  Requires-Dist: sphinx-sitemap>=2.5 ; extra == 'docs'
34
34
  Requires-Dist: nbsphinx>=0.9 ; extra == 'docs'
35
+ Requires-Dist: myst-parser>=2.0 ; extra == 'docs'
35
36
  Requires-Dist: matplotlib>=3.5 ; extra == 'docs'
36
37
  Requires-Dist: ipython>=8.0 ; extra == 'docs'
37
38
  Requires-Dist: plotly>=5.0 ; extra == 'plotly'
@@ -165,12 +166,14 @@ Full guide: `diff_diff.get_llm_guide("practitioner")`.
165
166
  - [TripleDifference](https://diff-diff.readthedocs.io/en/stable/api/triple_diff.html) - triple difference (DDD) estimator for designs requiring two criteria for treatment eligibility
166
167
  - [ContinuousDiD](https://diff-diff.readthedocs.io/en/stable/api/continuous_did.html) - Callaway, Goodman-Bacon & Sant'Anna (2024) continuous treatment DiD with dose-response curves
167
168
  - [HeterogeneousAdoptionDiD](https://diff-diff.readthedocs.io/en/stable/api/had.html) - de Chaisemartin, Ciccia, D'Haultfœuille & Knau (2026) for designs where **no unit remains untreated**; local-linear estimator at the dose support boundary returning Weighted Average Slope (WAS) on Design 1' (`d̲ = 0` / QUG) or `WAS_{d̲}` on Design 1 (`d̲ > 0`, continuous-near-d̲ or mass-point), with a multi-period event-study extension (last-treatment cohort, pointwise CIs). **Panel-only** in this release - repeated cross-sections rejected by the validator. Alias `HAD`.
169
+ - [RegressionDiscontinuity](https://diff-diff.readthedocs.io/en/stable/api/regression_discontinuity.html) - Calonico, Cattaneo & Titiunik (2014) sharp, fuzzy, AND covariate-adjusted regression discontinuity with robust bias-corrected inference and rdrobust-parity bandwidth selection (all 10 selectors, mass-point handling; fuzzy via `treatment_col=` with a first-stage block and weak-identification warning; covariates via `covariates=` - CCFT 2019, same estimand, covariate-aware bandwidths). Canonical `att` is the bias-corrected estimate with a coherent robust CI (rdrobust's printed headline is `att_conventional`). Alias `RDD`.
168
170
  - [StackedDiD](https://diff-diff.readthedocs.io/en/stable/api/stacked_did.html) - Wing, Freedman & Hollingsworth (2024) stacked DiD with Q-weights and sub-experiments; optional covariate balancing (Ustyuzhanin 2026)
169
171
  - [EfficientDiD](https://diff-diff.readthedocs.io/en/stable/api/efficient_did.html) - Chen, Sant'Anna & Xie (2025) efficient DiD with optimal weighting for tighter SEs
170
172
  - [TROP](https://diff-diff.readthedocs.io/en/stable/api/trop.html) - Triply Robust Panel estimator (Athey et al. 2025) with nuclear norm factor adjustment
171
173
  - [StaggeredTripleDifference](https://diff-diff.readthedocs.io/en/stable/api/staggered.html#staggeredtripledifference) - Ortiz-Villavicencio & Sant'Anna (2025) staggered DDD with group-time ATT
172
174
  - [WooldridgeDiD](https://diff-diff.readthedocs.io/en/stable/api/wooldridge_etwfe.html) - Wooldridge (2023, 2025) ETWFE: saturated OLS, logit/Poisson QMLE (ASF-based ATT). Alias `ETWFE`.
173
175
  - [LPDiD](https://diff-diff.readthedocs.io/en/stable/api/lpdid.html) - Dube, Girardi, Jorda & Taylor (2025) Local Projections DiD: per-horizon long-difference event study on clean controls (no negative weighting), variance- or equally-weighted ATT, for absorbing or non-absorbing (reversible) treatment
176
+ - [ChangesInChanges](https://diff-diff.readthedocs.io/en/stable/api/changes_in_changes.html) - Athey & Imbens (2006) nonlinear/distributional DiD for the 2x2 design: full counterfactual distribution and quantile treatment effects via CDF transformation, plus the QDiD comparison estimator; bootstrap inference; R qte parity. Alias `CiC`
174
177
  - [BaconDecomposition](https://diff-diff.readthedocs.io/en/stable/api/bacon.html) - Goodman-Bacon (2021) decomposition for diagnosing TWFE bias in staggered settings
175
178
 
176
179
  ## Diagnostics & Sensitivity
@@ -190,6 +193,7 @@ Most estimators accept an optional `survey_design` parameter (or `survey=` / `we
190
193
  - **Variance methods**: Taylor Series Linearization (TSL via Binder 1983), replicate weights (BRR / Fay / JK1 / JKn / SDR), survey-aware bootstrap
191
194
  - **Diagnostics**: DEFF per coefficient, effective n, subpopulation analysis, weight trimming, CV on estimates
192
195
  - **Repeated cross-sections**: `CallawaySantAnna(panel=False)` for BRFSS, ACS, CPS
196
+ - **Weight calibration / raking**: upstream by design - pair with Meta's [balance](https://import-balance.org/) package, whose `balance.interop.diff_diff` adapter hands raked samples straight to diff-diff; see the [composition-drift tutorial](https://diff-diff.readthedocs.io/en/stable/tutorials/26_composition_drift_calibration.html)
193
197
 
194
198
  No other Python or R DiD package offers design-based variance estimation for modern heterogeneity-robust estimators.
195
199
 
@@ -112,12 +112,14 @@ Full guide: `diff_diff.get_llm_guide("practitioner")`.
112
112
  - [TripleDifference](https://diff-diff.readthedocs.io/en/stable/api/triple_diff.html) - triple difference (DDD) estimator for designs requiring two criteria for treatment eligibility
113
113
  - [ContinuousDiD](https://diff-diff.readthedocs.io/en/stable/api/continuous_did.html) - Callaway, Goodman-Bacon & Sant'Anna (2024) continuous treatment DiD with dose-response curves
114
114
  - [HeterogeneousAdoptionDiD](https://diff-diff.readthedocs.io/en/stable/api/had.html) - de Chaisemartin, Ciccia, D'Haultfœuille & Knau (2026) for designs where **no unit remains untreated**; local-linear estimator at the dose support boundary returning Weighted Average Slope (WAS) on Design 1' (`d̲ = 0` / QUG) or `WAS_{d̲}` on Design 1 (`d̲ > 0`, continuous-near-d̲ or mass-point), with a multi-period event-study extension (last-treatment cohort, pointwise CIs). **Panel-only** in this release - repeated cross-sections rejected by the validator. Alias `HAD`.
115
+ - [RegressionDiscontinuity](https://diff-diff.readthedocs.io/en/stable/api/regression_discontinuity.html) - Calonico, Cattaneo & Titiunik (2014) sharp, fuzzy, AND covariate-adjusted regression discontinuity with robust bias-corrected inference and rdrobust-parity bandwidth selection (all 10 selectors, mass-point handling; fuzzy via `treatment_col=` with a first-stage block and weak-identification warning; covariates via `covariates=` - CCFT 2019, same estimand, covariate-aware bandwidths). Canonical `att` is the bias-corrected estimate with a coherent robust CI (rdrobust's printed headline is `att_conventional`). Alias `RDD`.
115
116
  - [StackedDiD](https://diff-diff.readthedocs.io/en/stable/api/stacked_did.html) - Wing, Freedman & Hollingsworth (2024) stacked DiD with Q-weights and sub-experiments; optional covariate balancing (Ustyuzhanin 2026)
116
117
  - [EfficientDiD](https://diff-diff.readthedocs.io/en/stable/api/efficient_did.html) - Chen, Sant'Anna & Xie (2025) efficient DiD with optimal weighting for tighter SEs
117
118
  - [TROP](https://diff-diff.readthedocs.io/en/stable/api/trop.html) - Triply Robust Panel estimator (Athey et al. 2025) with nuclear norm factor adjustment
118
119
  - [StaggeredTripleDifference](https://diff-diff.readthedocs.io/en/stable/api/staggered.html#staggeredtripledifference) - Ortiz-Villavicencio & Sant'Anna (2025) staggered DDD with group-time ATT
119
120
  - [WooldridgeDiD](https://diff-diff.readthedocs.io/en/stable/api/wooldridge_etwfe.html) - Wooldridge (2023, 2025) ETWFE: saturated OLS, logit/Poisson QMLE (ASF-based ATT). Alias `ETWFE`.
120
121
  - [LPDiD](https://diff-diff.readthedocs.io/en/stable/api/lpdid.html) - Dube, Girardi, Jorda & Taylor (2025) Local Projections DiD: per-horizon long-difference event study on clean controls (no negative weighting), variance- or equally-weighted ATT, for absorbing or non-absorbing (reversible) treatment
122
+ - [ChangesInChanges](https://diff-diff.readthedocs.io/en/stable/api/changes_in_changes.html) - Athey & Imbens (2006) nonlinear/distributional DiD for the 2x2 design: full counterfactual distribution and quantile treatment effects via CDF transformation, plus the QDiD comparison estimator; bootstrap inference; R qte parity. Alias `CiC`
121
123
  - [BaconDecomposition](https://diff-diff.readthedocs.io/en/stable/api/bacon.html) - Goodman-Bacon (2021) decomposition for diagnosing TWFE bias in staggered settings
122
124
 
123
125
  ## Diagnostics & Sensitivity
@@ -137,6 +139,7 @@ Most estimators accept an optional `survey_design` parameter (or `survey=` / `we
137
139
  - **Variance methods**: Taylor Series Linearization (TSL via Binder 1983), replicate weights (BRR / Fay / JK1 / JKn / SDR), survey-aware bootstrap
138
140
  - **Diagnostics**: DEFF per coefficient, effective n, subpopulation analysis, weight trimming, CV on estimates
139
141
  - **Repeated cross-sections**: `CallawaySantAnna(panel=False)` for BRFSS, ACS, CPS
142
+ - **Weight calibration / raking**: upstream by design - pair with Meta's [balance](https://import-balance.org/) package, whose `balance.interop.diff_diff` adapter hands raked samples straight to diff-diff; see the [composition-drift tutorial](https://diff-diff.readthedocs.io/en/stable/tutorials/26_composition_drift_calibration.html)
140
143
 
141
144
  No other Python or R DiD package offers design-based variance estimation for modern heterogeneity-robust estimators.
142
145
 
@@ -28,13 +28,58 @@ from diff_diff._backend import (
28
28
  _rust_project_simplex,
29
29
  _rust_solve_ols,
30
30
  )
31
-
31
+ from diff_diff._guides_api import get_llm_guide
32
+ from diff_diff.agent_workflow import agent_workflow
32
33
  from diff_diff.bacon import (
33
34
  BaconDecomposition,
34
35
  BaconDecompositionResults,
35
36
  Comparison2x2,
36
37
  bacon_decompose,
37
38
  )
39
+ from diff_diff.business_report import (
40
+ BUSINESS_REPORT_SCHEMA_VERSION,
41
+ BusinessContext,
42
+ BusinessReport,
43
+ )
44
+ from diff_diff.chaisemartin_dhaultfoeuille import (
45
+ ChaisemartinDHaultfoeuille,
46
+ TWFEWeightsResult,
47
+ chaisemartin_dhaultfoeuille,
48
+ twowayfeweights,
49
+ )
50
+ from diff_diff.chaisemartin_dhaultfoeuille_results import (
51
+ ChaisemartinDHaultfoeuilleResults,
52
+ DCDHBootstrapResults,
53
+ )
54
+ from diff_diff.changes_in_changes import (
55
+ ChangesInChanges,
56
+ QDiD,
57
+ )
58
+ from diff_diff.changes_in_changes_results import (
59
+ ChangesInChangesResults,
60
+ QDiDResults,
61
+ )
62
+ from diff_diff.continuous_did import (
63
+ ContinuousDiD,
64
+ ContinuousDiDResults,
65
+ DoseResponseCurve,
66
+ )
67
+ from diff_diff.datasets import (
68
+ clear_cache,
69
+ list_datasets,
70
+ load_card_krueger,
71
+ load_castle_doctrine,
72
+ load_dataset,
73
+ load_divorce_laws,
74
+ load_mpdta,
75
+ load_prop99,
76
+ load_walmart,
77
+ )
78
+ from diff_diff.diagnostic_report import (
79
+ DIAGNOSTIC_REPORT_SCHEMA_VERSION,
80
+ DiagnosticReport,
81
+ DiagnosticReportResults,
82
+ )
38
83
  from diff_diff.diagnostics import (
39
84
  PlaceboTestResults,
40
85
  leave_one_out_test,
@@ -44,22 +89,16 @@ from diff_diff.diagnostics import (
44
89
  run_all_placebo_tests,
45
90
  run_placebo_test,
46
91
  )
47
- from diff_diff.linalg import (
48
- InferenceResult,
49
- LinearRegression,
92
+ from diff_diff.efficient_did import (
93
+ EDiDBootstrapResults,
94
+ EfficientDiD,
95
+ EfficientDiDResults,
50
96
  )
51
- from diff_diff.local_linear import (
52
- KERNELS,
53
- BandwidthResult,
54
- BiasCorrectedFit,
55
- LocalLinearFit,
56
- bias_corrected_local_linear,
57
- epanechnikov_kernel,
58
- kernel_moments,
59
- local_linear_fit,
60
- mse_optimal_bandwidth,
61
- triangular_kernel,
62
- uniform_kernel,
97
+ from diff_diff.estimators import (
98
+ DifferenceInDifferences,
99
+ MultiPeriodDiD,
100
+ SyntheticDiD,
101
+ TwoWayFixedEffects,
63
102
  )
64
103
  from diff_diff.had import (
65
104
  HeterogeneousAdoptionDiD,
@@ -80,12 +119,6 @@ from diff_diff.had_pretests import (
80
119
  stute_test,
81
120
  yatchew_hr_test,
82
121
  )
83
- from diff_diff.estimators import (
84
- DifferenceInDifferences,
85
- MultiPeriodDiD,
86
- SyntheticDiD,
87
- TwoWayFixedEffects,
88
- )
89
122
  from diff_diff.honest_did import (
90
123
  DeltaRM,
91
124
  DeltaSD,
@@ -96,6 +129,31 @@ from diff_diff.honest_did import (
96
129
  compute_honest_did,
97
130
  sensitivity_plot,
98
131
  )
132
+ from diff_diff.imputation import (
133
+ ImputationBootstrapResults,
134
+ ImputationDiD,
135
+ ImputationDiDResults,
136
+ imputation_did,
137
+ )
138
+ from diff_diff.linalg import (
139
+ InferenceResult,
140
+ LinearRegression,
141
+ )
142
+ from diff_diff.local_linear import (
143
+ KERNELS,
144
+ BandwidthResult,
145
+ BiasCorrectedFit,
146
+ LocalLinearFit,
147
+ bias_corrected_local_linear,
148
+ epanechnikov_kernel,
149
+ kernel_moments,
150
+ local_linear_fit,
151
+ mse_optimal_bandwidth,
152
+ triangular_kernel,
153
+ uniform_kernel,
154
+ )
155
+ from diff_diff.lpdid import LPDiD
156
+ from diff_diff.lpdid_results import LPDiDResults
99
157
  from diff_diff.power import (
100
158
  PowerAnalysis,
101
159
  PowerResults,
@@ -110,22 +168,16 @@ from diff_diff.power import (
110
168
  simulate_power,
111
169
  simulate_sample_size,
112
170
  )
113
- from diff_diff.pretrends import (
114
- PreTrendsPower,
115
- PreTrendsPowerCurve,
116
- PreTrendsPowerResults,
117
- compute_mdv,
118
- compute_pretrends_power,
119
- )
171
+ from diff_diff.practitioner import practitioner_next_steps
120
172
  from diff_diff.prep import (
121
173
  aggregate_survey,
122
174
  aggregate_to_cohorts,
123
175
  balance_panel,
124
176
  create_event_time,
125
177
  generate_continuous_did_data,
126
- generate_did_data,
127
178
  generate_ddd_data,
128
179
  generate_ddd_panel_data,
180
+ generate_did_data,
129
181
  generate_event_study_data,
130
182
  generate_factor_data,
131
183
  generate_panel_data,
@@ -142,55 +194,44 @@ from diff_diff.prep import (
142
194
  validate_did_data,
143
195
  wide_to_long,
144
196
  )
197
+ from diff_diff.pretrends import (
198
+ PreTrendsPower,
199
+ PreTrendsPowerCurve,
200
+ PreTrendsPowerResults,
201
+ compute_mdv,
202
+ compute_pretrends_power,
203
+ )
204
+ from diff_diff.profile import (
205
+ Alert,
206
+ OutcomeShape,
207
+ PanelProfile,
208
+ TreatmentDoseShape,
209
+ profile_panel,
210
+ )
211
+ from diff_diff.rdd import (
212
+ RegressionDiscontinuity,
213
+ RegressionDiscontinuityResults,
214
+ )
145
215
  from diff_diff.results import (
146
216
  DiDResults,
147
217
  MultiPeriodDiDResults,
148
218
  PeriodEffect,
219
+ SpilloverDiDResults, # re-export
149
220
  SyntheticDiDResults,
150
221
  )
151
- from diff_diff.survey import (
152
- DEFFDiagnostics,
153
- SurveyDesign,
154
- SurveyMetadata,
155
- compute_deff_diagnostics,
156
- make_pweight_design,
157
- )
158
- from diff_diff.staggered import (
159
- CallawaySantAnna,
160
- CallawaySantAnnaResults,
161
- CSBootstrapResults,
162
- GroupTimeEffect,
163
- )
164
- from diff_diff.imputation import (
165
- ImputationBootstrapResults,
166
- ImputationDiD,
167
- ImputationDiDResults,
168
- imputation_did,
169
- )
170
- from diff_diff.two_stage import (
171
- TwoStageBootstrapResults,
172
- TwoStageDiD,
173
- TwoStageDiDResults,
174
- two_stage_did,
175
- )
176
222
  from diff_diff.spillover import (
177
223
  SpilloverDiD,
178
224
  )
179
- from diff_diff.results import SpilloverDiDResults # re-export
180
225
  from diff_diff.stacked_did import (
181
226
  StackedDiD,
182
227
  StackedDiDResults,
183
228
  stacked_did,
184
229
  )
185
- from diff_diff.sun_abraham import (
186
- SABootstrapResults,
187
- SunAbraham,
188
- SunAbrahamResults,
189
- )
190
- from diff_diff.triple_diff import (
191
- TripleDifference,
192
- TripleDifferenceResults,
193
- triple_difference,
230
+ from diff_diff.staggered import (
231
+ CallawaySantAnna,
232
+ CallawaySantAnnaResults,
233
+ CSBootstrapResults,
234
+ GroupTimeEffect,
194
235
  )
195
236
  from diff_diff.staggered_triple_diff import (
196
237
  StaggeredTripleDifference,
@@ -198,40 +239,39 @@ from diff_diff.staggered_triple_diff import (
198
239
  from diff_diff.staggered_triple_diff_results import (
199
240
  StaggeredTripleDiffResults,
200
241
  )
201
- from diff_diff.continuous_did import (
202
- ContinuousDiD,
203
- ContinuousDiDResults,
204
- DoseResponseCurve,
242
+ from diff_diff.sun_abraham import (
243
+ SABootstrapResults,
244
+ SunAbraham,
245
+ SunAbrahamResults,
205
246
  )
206
- from diff_diff.efficient_did import (
207
- EfficientDiD,
208
- EfficientDiDResults,
209
- EDiDBootstrapResults,
247
+ from diff_diff.survey import (
248
+ DEFFDiagnostics,
249
+ SurveyDesign,
250
+ SurveyMetadata,
251
+ compute_deff_diagnostics,
252
+ make_pweight_design,
210
253
  )
211
- from diff_diff.chaisemartin_dhaultfoeuille import (
212
- ChaisemartinDHaultfoeuille,
213
- TWFEWeightsResult,
214
- chaisemartin_dhaultfoeuille,
215
- twowayfeweights,
254
+ from diff_diff.synthetic_control import (
255
+ SyntheticControl,
256
+ synthetic_control,
216
257
  )
217
- from diff_diff.chaisemartin_dhaultfoeuille_results import (
218
- ChaisemartinDHaultfoeuilleResults,
219
- DCDHBootstrapResults,
258
+ from diff_diff.synthetic_control_results import SyntheticControlResults
259
+ from diff_diff.triple_diff import (
260
+ TripleDifference,
261
+ TripleDifferenceResults,
262
+ triple_difference,
220
263
  )
221
264
  from diff_diff.trop import (
222
265
  TROP,
223
266
  TROPResults,
224
267
  trop,
225
268
  )
226
- from diff_diff.synthetic_control import (
227
- SyntheticControl,
228
- synthetic_control,
269
+ from diff_diff.two_stage import (
270
+ TwoStageBootstrapResults,
271
+ TwoStageDiD,
272
+ TwoStageDiDResults,
273
+ two_stage_did,
229
274
  )
230
- from diff_diff.synthetic_control_results import SyntheticControlResults
231
- from diff_diff.wooldridge import WooldridgeDiD
232
- from diff_diff.wooldridge_results import WooldridgeDiDResults
233
- from diff_diff.lpdid import LPDiD
234
- from diff_diff.lpdid_results import LPDiDResults
235
275
  from diff_diff.utils import (
236
276
  WildBootstrapResults,
237
277
  check_parallel_trends,
@@ -252,35 +292,8 @@ from diff_diff.visualization import (
252
292
  plot_staircase,
253
293
  plot_synth_weights,
254
294
  )
255
- from diff_diff.practitioner import practitioner_next_steps
256
- from diff_diff.business_report import (
257
- BUSINESS_REPORT_SCHEMA_VERSION,
258
- BusinessContext,
259
- BusinessReport,
260
- )
261
- from diff_diff.diagnostic_report import (
262
- DIAGNOSTIC_REPORT_SCHEMA_VERSION,
263
- DiagnosticReport,
264
- DiagnosticReportResults,
265
- )
266
- from diff_diff._guides_api import get_llm_guide
267
- from diff_diff.agent_workflow import agent_workflow
268
- from diff_diff.profile import (
269
- Alert,
270
- OutcomeShape,
271
- PanelProfile,
272
- TreatmentDoseShape,
273
- profile_panel,
274
- )
275
- from diff_diff.datasets import (
276
- clear_cache,
277
- list_datasets,
278
- load_card_krueger,
279
- load_castle_doctrine,
280
- load_dataset,
281
- load_divorce_laws,
282
- load_mpdta,
283
- )
295
+ from diff_diff.wooldridge import WooldridgeDiD
296
+ from diff_diff.wooldridge_results import WooldridgeDiDResults
284
297
 
285
298
  # Estimator aliases — short names for convenience
286
299
  DiD = DifferenceInDifferences
@@ -300,8 +313,10 @@ EDiD = EfficientDiD
300
313
  ETWFE = WooldridgeDiD
301
314
  DCDH = ChaisemartinDHaultfoeuille
302
315
  HAD = HeterogeneousAdoptionDiD
316
+ CiC = ChangesInChanges
317
+ RDD = RegressionDiscontinuity
303
318
 
304
- __version__ = "3.6.2"
319
+ __version__ = "3.8.0"
305
320
  __all__ = [
306
321
  # Estimators
307
322
  "DifferenceInDifferences",
@@ -310,6 +325,8 @@ __all__ = [
310
325
  "SyntheticDiD",
311
326
  "CallawaySantAnna",
312
327
  "ChaisemartinDHaultfoeuille",
328
+ "ChangesInChanges",
329
+ "QDiD",
313
330
  "ContinuousDiD",
314
331
  "SunAbraham",
315
332
  "ImputationDiD",
@@ -327,6 +344,7 @@ __all__ = [
327
344
  "CS",
328
345
  "CDiD",
329
346
  "DCDH",
347
+ "CiC",
330
348
  "SA",
331
349
  "BJS",
332
350
  "Gardner",
@@ -347,6 +365,8 @@ __all__ = [
347
365
  "CallawaySantAnnaResults",
348
366
  "CSBootstrapResults",
349
367
  "GroupTimeEffect",
368
+ "ChangesInChangesResults",
369
+ "QDiDResults",
350
370
  "ContinuousDiDResults",
351
371
  "DoseResponseCurve",
352
372
  "SunAbrahamResults",
@@ -495,6 +515,10 @@ __all__ = [
495
515
  "HeterogeneousAdoptionDiDResults",
496
516
  "HeterogeneousAdoptionDiDEventStudyResults",
497
517
  "HAD",
518
+ # RegressionDiscontinuity (sharp RD, rdrobust parity)
519
+ "RegressionDiscontinuity",
520
+ "RegressionDiscontinuityResults",
521
+ "RDD",
498
522
  # HeterogeneousAdoptionDiD pre-test diagnostics (Phase 3)
499
523
  "qug_test",
500
524
  "stute_test",
@@ -515,6 +539,8 @@ __all__ = [
515
539
  "load_castle_doctrine",
516
540
  "load_divorce_laws",
517
541
  "load_mpdta",
542
+ "load_prop99",
543
+ "load_walmart",
518
544
  "load_dataset",
519
545
  "list_datasets",
520
546
  "clear_cache",
@@ -18,27 +18,59 @@ _backend_env = os.environ.get("DIFF_DIFF_BACKEND", "auto").lower()
18
18
  # Try to import Rust backend for accelerated operations
19
19
  try:
20
20
  from diff_diff._rust_backend import (
21
- generate_bootstrap_weights_batch as _rust_bootstrap_weights,
22
- project_simplex as _rust_project_simplex,
23
- solve_ols as _rust_solve_ols,
21
+ bootstrap_trop_variance as _rust_bootstrap_trop_variance,
22
+ )
23
+ from diff_diff._rust_backend import (
24
+ bootstrap_trop_variance_global as _rust_bootstrap_trop_variance_global,
25
+ )
26
+ from diff_diff._rust_backend import (
27
+ compute_noise_level as _rust_compute_noise_level,
28
+ )
29
+ from diff_diff._rust_backend import (
24
30
  compute_robust_vcov as _rust_compute_robust_vcov,
31
+ )
32
+ from diff_diff._rust_backend import (
33
+ # SDID weights (Frank-Wolfe matching R's synthdid)
34
+ compute_sdid_unit_weights as _rust_sdid_unit_weights,
35
+ )
36
+ from diff_diff._rust_backend import (
37
+ compute_time_weights as _rust_compute_time_weights,
38
+ )
39
+ from diff_diff._rust_backend import (
25
40
  # TROP estimator acceleration (local method)
26
41
  compute_unit_distance_matrix as _rust_unit_distance_matrix,
42
+ )
43
+ from diff_diff._rust_backend import (
44
+ generate_bootstrap_weights_batch as _rust_bootstrap_weights,
45
+ )
46
+ from diff_diff._rust_backend import (
27
47
  loocv_grid_search as _rust_loocv_grid_search,
28
- bootstrap_trop_variance as _rust_bootstrap_trop_variance,
48
+ )
49
+ from diff_diff._rust_backend import (
29
50
  # TROP estimator acceleration (global method)
30
51
  loocv_grid_search_global as _rust_loocv_grid_search_global,
31
- bootstrap_trop_variance_global as _rust_bootstrap_trop_variance_global,
32
- # SDID weights (Frank-Wolfe matching R's synthdid)
33
- compute_sdid_unit_weights as _rust_sdid_unit_weights,
34
- compute_time_weights as _rust_compute_time_weights,
35
- compute_noise_level as _rust_compute_noise_level,
52
+ )
53
+ from diff_diff._rust_backend import (
54
+ project_simplex as _rust_project_simplex,
55
+ )
56
+ from diff_diff._rust_backend import (
57
+ # Diagnostics
58
+ rust_backend_info as _rust_backend_info,
59
+ )
60
+ from diff_diff._rust_backend import (
36
61
  sc_weight_fw as _rust_sc_weight_fw,
37
- sc_weight_fw_with_convergence as _rust_sc_weight_fw_with_convergence,
62
+ )
63
+ from diff_diff._rust_backend import (
38
64
  sc_weight_fw_weighted as _rust_sc_weight_fw_weighted,
65
+ )
66
+ from diff_diff._rust_backend import (
39
67
  sc_weight_fw_weighted_with_convergence as _rust_sc_weight_fw_weighted_with_convergence,
40
- # Diagnostics
41
- rust_backend_info as _rust_backend_info,
68
+ )
69
+ from diff_diff._rust_backend import (
70
+ sc_weight_fw_with_convergence as _rust_sc_weight_fw_with_convergence,
71
+ )
72
+ from diff_diff._rust_backend import (
73
+ solve_ols as _rust_solve_ols,
42
74
  )
43
75
 
44
76
  _rust_available = True
@@ -73,6 +105,37 @@ try:
73
105
  except ImportError:
74
106
  _rust_demean_map = None
75
107
 
108
+ # Batched ridge-regularized SPD solve (EfficientDiD per-unit weights):
109
+ # imported independently for the same mixed-version reason as demean_map.
110
+ try:
111
+ from diff_diff._rust_backend import (
112
+ batched_ridge_chol_solve_ones as _rust_batched_ridge_chol_solve,
113
+ )
114
+ except ImportError:
115
+ _rust_batched_ridge_chol_solve = None
116
+
117
+ # HC2 (leverage-corrected) robust vcov: imported independently for the same
118
+ # mixed-version reason as demean_map (a stale extension missing only this
119
+ # newer symbol degrades HC2 to the NumPy path without disabling the older
120
+ # Rust accelerations).
121
+ try:
122
+ from diff_diff._rust_backend import (
123
+ compute_robust_vcov_hc2 as _rust_compute_robust_vcov_hc2,
124
+ )
125
+ except ImportError:
126
+ _rust_compute_robust_vcov_hc2 = None
127
+
128
+ # Opt-in normal-equations Cholesky OLS fast path: imported independently
129
+ # for the same mixed-version reason as demean_map. A stale extension
130
+ # missing only this symbol keeps every older Rust acceleration: Rust-eligible
131
+ # fits fall back to the legacy SVD solve_ols kernel (the knob simply has no
132
+ # Rust acceleration there), while numpy-lane fits (weighted, non-hc1,
133
+ # forced-python) still use the numpy Cholesky twin.
134
+ try:
135
+ from diff_diff._rust_backend import solve_ols_chol as _rust_solve_ols_chol
136
+ except ImportError:
137
+ _rust_solve_ols_chol = None
138
+
76
139
  # Determine final backend based on environment variable and availability
77
140
  if _backend_env == "python":
78
141
  # Force pure Python mode - disable Rust even if available
@@ -83,6 +146,12 @@ if _backend_env == "python":
83
146
  _rust_compute_robust_vcov = None
84
147
  # FE-absorption MAP demeaning kernel
85
148
  _rust_demean_map = None
149
+ # Batched ridge-regularized SPD solve
150
+ _rust_batched_ridge_chol_solve = None
151
+ # HC2 robust vcov
152
+ _rust_compute_robust_vcov_hc2 = None
153
+ # Opt-in normal-equations Cholesky OLS fast path
154
+ _rust_solve_ols_chol = None
86
155
  # TROP estimator acceleration (local method)
87
156
  _rust_unit_distance_matrix = None
88
157
  _rust_loocv_grid_search = None
@@ -134,8 +203,12 @@ __all__ = [
134
203
  "_rust_project_simplex",
135
204
  "_rust_solve_ols",
136
205
  "_rust_compute_robust_vcov",
206
+ # Opt-in normal-equations Cholesky OLS fast path
207
+ "_rust_solve_ols_chol",
137
208
  # FE-absorption MAP demeaning kernel
138
209
  "_rust_demean_map",
210
+ # Batched ridge-regularized SPD solve (EfficientDiD per-unit weights)
211
+ "_rust_batched_ridge_chol_solve",
139
212
  # TROP estimator acceleration (local method)
140
213
  "_rust_unit_distance_matrix",
141
214
  "_rust_loocv_grid_search",