diff-diff 3.7.0__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 (103) hide show
  1. {diff_diff-3.7.0 → diff_diff-3.8.0}/PKG-INFO +6 -4
  2. {diff_diff-3.7.0 → diff_diff-3.8.0}/README.md +2 -0
  3. {diff_diff-3.7.0 → diff_diff-3.8.0}/diff_diff/__init__.py +145 -119
  4. {diff_diff-3.7.0 → diff_diff-3.8.0}/diff_diff/_backend.py +59 -12
  5. diff_diff-3.8.0/diff_diff/_rdrobust_port.py +1913 -0
  6. {diff_diff-3.7.0 → diff_diff-3.8.0}/diff_diff/bacon.py +5 -2
  7. {diff_diff-3.7.0 → diff_diff-3.8.0}/diff_diff/bootstrap_chunking.py +18 -3
  8. {diff_diff-3.7.0 → diff_diff-3.8.0}/diff_diff/bootstrap_utils.py +7 -4
  9. {diff_diff-3.7.0 → diff_diff-3.8.0}/diff_diff/business_report.py +1 -1
  10. {diff_diff-3.7.0 → diff_diff-3.8.0}/diff_diff/chaisemartin_dhaultfoeuille.py +18 -9
  11. {diff_diff-3.7.0 → 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.7.0 → diff_diff-3.8.0}/diff_diff/conformal.py +163 -19
  15. {diff_diff-3.7.0 → diff_diff-3.8.0}/diff_diff/continuous_did.py +11 -5
  16. {diff_diff-3.7.0 → diff_diff-3.8.0}/diff_diff/datasets.py +414 -5
  17. {diff_diff-3.7.0 → diff_diff-3.8.0}/diff_diff/diagnostic_report.py +13 -2
  18. {diff_diff-3.7.0 → diff_diff-3.8.0}/diff_diff/efficient_did.py +13 -3
  19. {diff_diff-3.7.0 → diff_diff-3.8.0}/diff_diff/efficient_did_bootstrap.py +7 -2
  20. {diff_diff-3.7.0 → diff_diff-3.8.0}/diff_diff/efficient_did_covariates.py +2 -0
  21. {diff_diff-3.7.0 → diff_diff-3.8.0}/diff_diff/estimators.py +107 -17
  22. {diff_diff-3.7.0 → diff_diff-3.8.0}/diff_diff/guides/llms-autonomous.txt +11 -2
  23. {diff_diff-3.7.0 → diff_diff-3.8.0}/diff_diff/guides/llms-full.txt +155 -4
  24. {diff_diff-3.7.0 → diff_diff-3.8.0}/diff_diff/guides/llms.txt +6 -3
  25. {diff_diff-3.7.0 → diff_diff-3.8.0}/diff_diff/had.py +1 -1
  26. {diff_diff-3.7.0 → diff_diff-3.8.0}/diff_diff/had_pretests.py +110 -30
  27. {diff_diff-3.7.0 → diff_diff-3.8.0}/diff_diff/honest_did.py +2 -4
  28. {diff_diff-3.7.0 → diff_diff-3.8.0}/diff_diff/imputation.py +154 -46
  29. {diff_diff-3.7.0 → diff_diff-3.8.0}/diff_diff/linalg.py +787 -125
  30. {diff_diff-3.7.0 → diff_diff-3.8.0}/diff_diff/local_linear.py +3 -10
  31. {diff_diff-3.7.0 → diff_diff-3.8.0}/diff_diff/power.py +6 -8
  32. {diff_diff-3.7.0 → diff_diff-3.8.0}/diff_diff/practitioner.py +603 -1
  33. {diff_diff-3.7.0 → diff_diff-3.8.0}/diff_diff/prep_dgp.py +4 -5
  34. {diff_diff-3.7.0 → diff_diff-3.8.0}/diff_diff/pretrends.py +1 -1
  35. diff_diff-3.8.0/diff_diff/rdd.py +1218 -0
  36. {diff_diff-3.7.0 → diff_diff-3.8.0}/diff_diff/results.py +26 -0
  37. {diff_diff-3.7.0 → diff_diff-3.8.0}/diff_diff/spillover.py +88 -40
  38. {diff_diff-3.7.0 → diff_diff-3.8.0}/diff_diff/staggered.py +21 -8
  39. {diff_diff-3.7.0 → diff_diff-3.8.0}/diff_diff/staggered_aggregation.py +47 -10
  40. {diff_diff-3.7.0 → diff_diff-3.8.0}/diff_diff/staggered_bootstrap.py +8 -0
  41. {diff_diff-3.7.0 → diff_diff-3.8.0}/diff_diff/staggered_triple_diff.py +12 -2
  42. {diff_diff-3.7.0 → diff_diff-3.8.0}/diff_diff/sun_abraham.py +45 -6
  43. {diff_diff-3.7.0 → diff_diff-3.8.0}/diff_diff/survey.py +22 -1
  44. {diff_diff-3.7.0 → diff_diff-3.8.0}/diff_diff/synthetic_control_results.py +203 -3
  45. {diff_diff-3.7.0 → diff_diff-3.8.0}/diff_diff/synthetic_did.py +9 -2
  46. {diff_diff-3.7.0 → diff_diff-3.8.0}/diff_diff/triple_diff.py +7 -5
  47. {diff_diff-3.7.0 → diff_diff-3.8.0}/diff_diff/trop_local.py +0 -1
  48. {diff_diff-3.7.0 → diff_diff-3.8.0}/diff_diff/twfe.py +34 -13
  49. {diff_diff-3.7.0 → diff_diff-3.8.0}/diff_diff/two_stage.py +172 -75
  50. {diff_diff-3.7.0 → diff_diff-3.8.0}/diff_diff/two_stage_bootstrap.py +70 -48
  51. {diff_diff-3.7.0 → diff_diff-3.8.0}/diff_diff/utils.py +59 -5
  52. {diff_diff-3.7.0 → diff_diff-3.8.0}/diff_diff/wooldridge.py +2 -2
  53. {diff_diff-3.7.0 → diff_diff-3.8.0}/diff_diff/wooldridge_results.py +2 -2
  54. {diff_diff-3.7.0 → diff_diff-3.8.0}/pyproject.toml +44 -4
  55. {diff_diff-3.7.0 → diff_diff-3.8.0}/rust/Cargo.lock +35 -35
  56. {diff_diff-3.7.0 → diff_diff-3.8.0}/rust/Cargo.toml +1 -1
  57. {diff_diff-3.7.0 → diff_diff-3.8.0}/rust/src/lib.rs +1 -0
  58. {diff_diff-3.7.0 → diff_diff-3.8.0}/rust/src/linalg.rs +561 -7
  59. {diff_diff-3.7.0 → diff_diff-3.8.0}/LICENSE +0 -0
  60. {diff_diff-3.7.0 → diff_diff-3.8.0}/diff_diff/_guides_api.py +0 -0
  61. {diff_diff-3.7.0 → diff_diff-3.8.0}/diff_diff/_nprobust_port.py +0 -0
  62. {diff_diff-3.7.0 → diff_diff-3.8.0}/diff_diff/_reporting_helpers.py +0 -0
  63. {diff_diff-3.7.0 → diff_diff-3.8.0}/diff_diff/agent_workflow.py +0 -0
  64. {diff_diff-3.7.0 → diff_diff-3.8.0}/diff_diff/balancing.py +0 -0
  65. {diff_diff-3.7.0 → diff_diff-3.8.0}/diff_diff/chaisemartin_dhaultfoeuille_results.py +0 -0
  66. {diff_diff-3.7.0 → diff_diff-3.8.0}/diff_diff/conley.py +0 -0
  67. {diff_diff-3.7.0 → diff_diff-3.8.0}/diff_diff/continuous_did_bspline.py +0 -0
  68. {diff_diff-3.7.0 → diff_diff-3.8.0}/diff_diff/continuous_did_results.py +0 -0
  69. {diff_diff-3.7.0 → diff_diff-3.8.0}/diff_diff/diagnostics.py +0 -0
  70. {diff_diff-3.7.0 → diff_diff-3.8.0}/diff_diff/efficient_did_results.py +0 -0
  71. {diff_diff-3.7.0 → diff_diff-3.8.0}/diff_diff/efficient_did_weights.py +0 -0
  72. {diff_diff-3.7.0 → diff_diff-3.8.0}/diff_diff/guides/__init__.py +0 -0
  73. {diff_diff-3.7.0 → diff_diff-3.8.0}/diff_diff/guides/llms-practitioner.txt +0 -0
  74. {diff_diff-3.7.0 → diff_diff-3.8.0}/diff_diff/imputation_bootstrap.py +0 -0
  75. {diff_diff-3.7.0 → diff_diff-3.8.0}/diff_diff/imputation_results.py +0 -0
  76. {diff_diff-3.7.0 → diff_diff-3.8.0}/diff_diff/lpdid.py +0 -0
  77. {diff_diff-3.7.0 → diff_diff-3.8.0}/diff_diff/lpdid_results.py +0 -0
  78. {diff_diff-3.7.0 → diff_diff-3.8.0}/diff_diff/prep.py +0 -0
  79. {diff_diff-3.7.0 → diff_diff-3.8.0}/diff_diff/profile.py +0 -0
  80. {diff_diff-3.7.0 → diff_diff-3.8.0}/diff_diff/stacked_did.py +0 -0
  81. {diff_diff-3.7.0 → diff_diff-3.8.0}/diff_diff/stacked_did_results.py +0 -0
  82. {diff_diff-3.7.0 → diff_diff-3.8.0}/diff_diff/staggered_results.py +0 -0
  83. {diff_diff-3.7.0 → diff_diff-3.8.0}/diff_diff/staggered_triple_diff_results.py +0 -0
  84. {diff_diff-3.7.0 → diff_diff-3.8.0}/diff_diff/synthetic_control.py +0 -0
  85. {diff_diff-3.7.0 → diff_diff-3.8.0}/diff_diff/trop.py +1 -1
  86. {diff_diff-3.7.0 → diff_diff-3.8.0}/diff_diff/trop_global.py +0 -0
  87. {diff_diff-3.7.0 → diff_diff-3.8.0}/diff_diff/trop_results.py +0 -0
  88. {diff_diff-3.7.0 → diff_diff-3.8.0}/diff_diff/two_stage_results.py +0 -0
  89. {diff_diff-3.7.0 → diff_diff-3.8.0}/diff_diff/visualization/__init__.py +0 -0
  90. {diff_diff-3.7.0 → diff_diff-3.8.0}/diff_diff/visualization/_common.py +0 -0
  91. {diff_diff-3.7.0 → diff_diff-3.8.0}/diff_diff/visualization/_continuous.py +0 -0
  92. {diff_diff-3.7.0 → diff_diff-3.8.0}/diff_diff/visualization/_diagnostic.py +0 -0
  93. {diff_diff-3.7.0 → diff_diff-3.8.0}/diff_diff/visualization/_event_study.py +0 -0
  94. {diff_diff-3.7.0 → diff_diff-3.8.0}/diff_diff/visualization/_power.py +0 -0
  95. {diff_diff-3.7.0 → diff_diff-3.8.0}/diff_diff/visualization/_staggered.py +0 -0
  96. {diff_diff-3.7.0 → diff_diff-3.8.0}/diff_diff/visualization/_synthetic.py +0 -0
  97. {diff_diff-3.7.0 → diff_diff-3.8.0}/rust/build.rs +0 -0
  98. {diff_diff-3.7.0 → diff_diff-3.8.0}/rust/src/alloc_profile.rs +0 -0
  99. {diff_diff-3.7.0 → diff_diff-3.8.0}/rust/src/batched_solve.rs +0 -0
  100. {diff_diff-3.7.0 → diff_diff-3.8.0}/rust/src/bootstrap.rs +0 -0
  101. {diff_diff-3.7.0 → diff_diff-3.8.0}/rust/src/demean.rs +0 -0
  102. {diff_diff-3.7.0 → diff_diff-3.8.0}/rust/src/trop.rs +0 -0
  103. {diff_diff-3.7.0 → 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.7.0
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'
@@ -166,12 +166,14 @@ Full guide: `diff_diff.get_llm_guide("practitioner")`.
166
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
167
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
168
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`.
169
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)
170
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
171
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
172
173
  - [StaggeredTripleDifference](https://diff-diff.readthedocs.io/en/stable/api/staggered.html#staggeredtripledifference) - Ortiz-Villavicencio & Sant'Anna (2025) staggered DDD with group-time ATT
173
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`.
174
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`
175
177
  - [BaconDecomposition](https://diff-diff.readthedocs.io/en/stable/api/bacon.html) - Goodman-Bacon (2021) decomposition for diagnosing TWFE bias in staggered settings
176
178
 
177
179
  ## Diagnostics & Sensitivity
@@ -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
@@ -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.7.0"
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
@@ -93,6 +125,17 @@ try:
93
125
  except ImportError:
94
126
  _rust_compute_robust_vcov_hc2 = None
95
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
+
96
139
  # Determine final backend based on environment variable and availability
97
140
  if _backend_env == "python":
98
141
  # Force pure Python mode - disable Rust even if available
@@ -107,6 +150,8 @@ if _backend_env == "python":
107
150
  _rust_batched_ridge_chol_solve = None
108
151
  # HC2 robust vcov
109
152
  _rust_compute_robust_vcov_hc2 = None
153
+ # Opt-in normal-equations Cholesky OLS fast path
154
+ _rust_solve_ols_chol = None
110
155
  # TROP estimator acceleration (local method)
111
156
  _rust_unit_distance_matrix = None
112
157
  _rust_loocv_grid_search = None
@@ -158,6 +203,8 @@ __all__ = [
158
203
  "_rust_project_simplex",
159
204
  "_rust_solve_ols",
160
205
  "_rust_compute_robust_vcov",
206
+ # Opt-in normal-equations Cholesky OLS fast path
207
+ "_rust_solve_ols_chol",
161
208
  # FE-absorption MAP demeaning kernel
162
209
  "_rust_demean_map",
163
210
  # Batched ridge-regularized SPD solve (EfficientDiD per-unit weights)