panelkit 0.1.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 (71) hide show
  1. panelkit-0.1.0/BENCHMARKS.md +70 -0
  2. panelkit-0.1.0/Cargo.lock +1116 -0
  3. panelkit-0.1.0/Cargo.toml +40 -0
  4. panelkit-0.1.0/GUIDE.md +198 -0
  5. panelkit-0.1.0/LICENSE-APACHE +201 -0
  6. panelkit-0.1.0/LICENSE-MIT +21 -0
  7. panelkit-0.1.0/PKG-INFO +231 -0
  8. panelkit-0.1.0/README.md +206 -0
  9. panelkit-0.1.0/crates/estimators/Cargo.toml +20 -0
  10. panelkit-0.1.0/crates/estimators/benches/estimators.rs +66 -0
  11. panelkit-0.1.0/crates/estimators/src/did/bacon.rs +183 -0
  12. panelkit-0.1.0/crates/estimators/src/did/callaway.rs +216 -0
  13. panelkit-0.1.0/crates/estimators/src/did/mod.rs +16 -0
  14. panelkit-0.1.0/crates/estimators/src/did/sunab.rs +195 -0
  15. panelkit-0.1.0/crates/estimators/src/did/twfe.rs +99 -0
  16. panelkit-0.1.0/crates/estimators/src/fe/mod.rs +5 -0
  17. panelkit-0.1.0/crates/estimators/src/fe/within.rs +72 -0
  18. panelkit-0.1.0/crates/estimators/src/lib.rs +21 -0
  19. panelkit-0.1.0/crates/estimators/src/mcnnm/mod.rs +5 -0
  20. panelkit-0.1.0/crates/estimators/src/mcnnm/softimpute.rs +240 -0
  21. panelkit-0.1.0/crates/estimators/src/panel.rs +155 -0
  22. panelkit-0.1.0/crates/estimators/src/result.rs +51 -0
  23. panelkit-0.1.0/crates/estimators/src/sc/augmented.rs +142 -0
  24. panelkit-0.1.0/crates/estimators/src/sc/cpasc.rs +273 -0
  25. panelkit-0.1.0/crates/estimators/src/sc/mod.rs +15 -0
  26. panelkit-0.1.0/crates/estimators/src/sc/sdid.rs +201 -0
  27. panelkit-0.1.0/crates/estimators/src/sc/synthetic.rs +131 -0
  28. panelkit-0.1.0/crates/estimators/tests/cpasc.rs +105 -0
  29. panelkit-0.1.0/crates/estimators/tests/did.rs +226 -0
  30. panelkit-0.1.0/crates/estimators/tests/sc.rs +84 -0
  31. panelkit-0.1.0/crates/estimators/tests/sc_family.rs +105 -0
  32. panelkit-0.1.0/crates/inference/Cargo.toml +18 -0
  33. panelkit-0.1.0/crates/inference/src/bootstrap.rs +149 -0
  34. panelkit-0.1.0/crates/inference/src/ci.rs +57 -0
  35. panelkit-0.1.0/crates/inference/src/lib.rs +19 -0
  36. panelkit-0.1.0/crates/inference/src/parallel.rs +58 -0
  37. panelkit-0.1.0/crates/inference/src/placebo.rs +98 -0
  38. panelkit-0.1.0/crates/inference/tests/inference.rs +117 -0
  39. panelkit-0.1.0/crates/linalg/Cargo.toml +21 -0
  40. panelkit-0.1.0/crates/linalg/src/error.rs +43 -0
  41. panelkit-0.1.0/crates/linalg/src/factor/cholesky.rs +112 -0
  42. panelkit-0.1.0/crates/linalg/src/factor/eig_sym.rs +122 -0
  43. panelkit-0.1.0/crates/linalg/src/factor/mod.rs +13 -0
  44. panelkit-0.1.0/crates/linalg/src/factor/qr.rs +156 -0
  45. panelkit-0.1.0/crates/linalg/src/factor/svd.rs +218 -0
  46. panelkit-0.1.0/crates/linalg/src/factor/svd_gram.rs +89 -0
  47. panelkit-0.1.0/crates/linalg/src/lib.rs +75 -0
  48. panelkit-0.1.0/crates/linalg/src/matrix.rs +215 -0
  49. panelkit-0.1.0/crates/linalg/src/ops/matmul.rs +154 -0
  50. panelkit-0.1.0/crates/linalg/src/ops/mod.rs +10 -0
  51. panelkit-0.1.0/crates/linalg/src/ops/norms.rs +58 -0
  52. panelkit-0.1.0/crates/linalg/src/ops/transform.rs +138 -0
  53. panelkit-0.1.0/crates/linalg/src/opt/mod.rs +8 -0
  54. panelkit-0.1.0/crates/linalg/src/opt/simplex.rs +262 -0
  55. panelkit-0.1.0/crates/linalg/src/opt/softthresh.rs +33 -0
  56. panelkit-0.1.0/crates/linalg/src/rng.rs +116 -0
  57. panelkit-0.1.0/crates/linalg/src/solve/lstsq.rs +63 -0
  58. panelkit-0.1.0/crates/linalg/src/solve/mod.rs +10 -0
  59. panelkit-0.1.0/crates/linalg/src/solve/spd.rs +17 -0
  60. panelkit-0.1.0/crates/linalg/tests/numerics.rs +309 -0
  61. panelkit-0.1.0/crates/pypanelkit/Cargo.toml +31 -0
  62. panelkit-0.1.0/crates/pypanelkit/src/api_did.rs +109 -0
  63. panelkit-0.1.0/crates/pypanelkit/src/api_sc.rs +201 -0
  64. panelkit-0.1.0/crates/pypanelkit/src/convert.rs +40 -0
  65. panelkit-0.1.0/crates/pypanelkit/src/lib.rs +41 -0
  66. panelkit-0.1.0/crates/pypanelkit/src/results.rs +194 -0
  67. panelkit-0.1.0/pyproject.toml +36 -0
  68. panelkit-0.1.0/python/panelkit/__init__.py +33 -0
  69. panelkit-0.1.0/python/panelkit/_panelkit.pyi +113 -0
  70. panelkit-0.1.0/python/panelkit/estimators.py +511 -0
  71. panelkit-0.1.0/python/panelkit/py.typed +0 -0
@@ -0,0 +1,70 @@
1
+ # Benchmarks
2
+
3
+ Measured on an **Apple M4 Pro (14 cores)**, release build, panel size
4
+ **200 units × 130 periods (104 pre / 26 post)** — the scale of a realistic geo
5
+ experiment. Absolute times vary by hardware; re-run to regenerate.
6
+
7
+ Reproduce (regenerates the figures + `assets/bench_results.txt`):
8
+
9
+ ```bash
10
+ maturin develop --release --manifest-path crates/pypanelkit/Cargo.toml
11
+ python benchmarks/make_plots.py # the figures used in the README
12
+ python benchmarks/bench_sc.py # single SC fit vs NumPy+SLSQP
13
+ python benchmarks/bench_placebo.py # full placebo inference vs NumPy+SLSQP
14
+ cargo bench -p panelkit-estimators # Rust-side criterion micro-benchmarks
15
+ ```
16
+
17
+ ## Single synthetic-control fit vs reference
18
+
19
+ The reference is the textbook implementation: simplex-constrained least squares
20
+ solved with `scipy.optimize` SLSQP. panelkit uses its from-scratch away-step
21
+ Frank–Wolfe solver in Rust. Median over 5 panels per size:
22
+
23
+ | N units | panelkit (ms) | reference (ms) | speedup |
24
+ |--------:|---------------:|---------------:|--------:|
25
+ | 20 | 0.032 | 1.43 | ~45× |
26
+ | 50 | 0.089 | 5.43 | ~61× |
27
+ | 100 | 0.371 | 23.99 | ~65× |
28
+ | 150 | 0.945 | 68.95 | ~73× |
29
+ | 200 | 2.040 | 121.40 | ~60× |
30
+
31
+ Estimates are identical (ATT |Δ| ≈ 1e-11). See `assets/bench_scaling.png`.
32
+
33
+ > **Robustness note.** SciPy SLSQP has occasional convergence cliffs on
34
+ > near-collinear donor panels — in this sweep individual panels ranged from tens
35
+ > of ms up to **9.5 s** at N=200 when SLSQP iterated to its cap. The table
36
+ > reports the **median** (typical case); the *mean* reference time is far worse.
37
+ > panelkit's Frank–Wolfe solver has no such cliffs.
38
+
39
+ ## Full placebo inference (1 + 199 leave-one-out fits)
40
+
41
+ Where the per-fit speedup compounds and panelkit's multithreading (rayon) kicks
42
+ in. Both compute the same in-space placebo p-value.
43
+
44
+ | method | p-value | seconds |
45
+ |------------------------------|--------:|--------:|
46
+ | panelkit (Rust, parallel) | 0.0050 | 0.056 |
47
+ | reference (NumPy + SLSQP) | 0.0050 | 82.2 |
48
+
49
+ **≈ 1467× faster**, identical p-value. See `assets/bench_speedup.png`.
50
+
51
+ ## Rust-side estimator micro-benchmarks (criterion)
52
+
53
+ Single fit, 200 × 130:
54
+
55
+ | estimator | time |
56
+ |-----------|-----:|
57
+ | SC | ~2.4 ms |
58
+ | ASC | ~3.3 ms |
59
+ | SDID | ~20 ms |
60
+ | MC-NNM | ~0.5–1.1 s (full SVD per SoftImpute iteration — the intrinsically heavy one) |
61
+
62
+ ## Notes
63
+
64
+ - Determinism: the multiplier bootstrap and parallel placebo produce
65
+ **bit-identical** output regardless of `RAYON_NUM_THREADS`, because every
66
+ replicate draws from an independent seed-derived substream
67
+ (`Xoshiro256pp::substream(seed, b)`). Verified in CI at 1 and 8 threads.
68
+ - The reference numbers exist to anchor the speed comparison against a standard,
69
+ widely-used approach — not to claim the reference is the fastest possible
70
+ Python implementation.