lme-python 0.1.8__tar.gz → 0.1.9__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 (265) hide show
  1. lme_python-0.1.9/.JuliaFormatter.toml +8 -0
  2. {lme_python-0.1.8 → lme_python-0.1.9}/.github/workflows/audit.yml +10 -28
  3. {lme_python-0.1.8 → lme_python-0.1.9}/.github/workflows/benchmarks.yml +24 -4
  4. {lme_python-0.1.8 → lme_python-0.1.9}/.github/workflows/ci.yml +24 -46
  5. {lme_python-0.1.8 → lme_python-0.1.9}/.github/workflows/python-release.yml +2 -8
  6. {lme_python-0.1.8 → lme_python-0.1.9}/.github/workflows/repo-metadata.yml +2 -5
  7. {lme_python-0.1.8 → lme_python-0.1.9}/.gitignore +1 -0
  8. {lme_python-0.1.8 → lme_python-0.1.9}/AGENTS.md +22 -3
  9. lme_python-0.1.9/BENCHMARKS.md +386 -0
  10. lme_python-0.1.9/BENCHMARK_COVERAGE.md +106 -0
  11. lme_python-0.1.9/CHANGELOG.md +174 -0
  12. {lme_python-0.1.8 → lme_python-0.1.9}/CONTRIBUTING.md +39 -24
  13. {lme_python-0.1.8 → lme_python-0.1.9}/Cargo.lock +29 -28
  14. {lme_python-0.1.8 → lme_python-0.1.9}/Cargo.toml +22 -2
  15. {lme_python-0.1.8 → lme_python-0.1.9}/GUIDE.md +52 -12
  16. lme_python-0.1.9/OPTIMIZATION.md +488 -0
  17. {lme_python-0.1.8 → lme_python-0.1.9}/PKG-INFO +3 -1
  18. {lme_python-0.1.8 → lme_python-0.1.9}/README.md +16 -11
  19. {lme_python-0.1.8 → lme_python-0.1.9}/RELEASING.md +3 -11
  20. lme_python-0.1.9/REPO_COMPLETION_BY_AREA.md +102 -0
  21. {lme_python-0.1.8 → lme_python-0.1.9}/Taskfile.yml +46 -0
  22. lme_python-0.1.9/USABILITY.md +178 -0
  23. lme_python-0.1.9/benchmarks/fair-rust-julia-reference-2026-07-04.json +97 -0
  24. lme_python-0.1.9/benchmarks/fair-rust-julia-reference-2026-07-06.json +99 -0
  25. {lme_python-0.1.8 → lme_python-0.1.9}/comparisons/COMPARISONS.md +5 -2
  26. lme_python-0.1.9/comparisons/bench_fair_julia_perf.jl +95 -0
  27. lme_python-0.1.9/comparisons/bench_fair_julia_timing.jl +135 -0
  28. lme_python-0.1.9/comparisons/bench_fair_rust_julia.rs +464 -0
  29. lme_python-0.1.9/comparisons/bench_perf_breakdown.rs +141 -0
  30. {lme_python-0.1.8 → lme_python-0.1.9}/comparisons/categorical_anova.R +3 -2
  31. {lme_python-0.1.8 → lme_python-0.1.9}/comparisons/categorical_anova.jl +1 -1
  32. {lme_python-0.1.8 → lme_python-0.1.9}/comparisons/glmm_cbpp.R +8 -5
  33. {lme_python-0.1.8 → lme_python-0.1.9}/comparisons/glmm_cbpp.jl +9 -9
  34. {lme_python-0.1.8 → lme_python-0.1.9}/comparisons/glmm_gaussian.R +3 -6
  35. {lme_python-0.1.8 → lme_python-0.1.9}/comparisons/glmm_grouseticks.R +1 -0
  36. {lme_python-0.1.8 → lme_python-0.1.9}/comparisons/glmm_grouseticks.jl +11 -11
  37. {lme_python-0.1.8 → lme_python-0.1.9}/comparisons/lmer_weighted.R +1 -0
  38. {lme_python-0.1.8 → lme_python-0.1.9}/comparisons/lmer_weighted.jl +2 -1
  39. {lme_python-0.1.8 → lme_python-0.1.9}/comparisons/lmm_dyestuff.jl +2 -2
  40. {lme_python-0.1.8 → lme_python-0.1.9}/comparisons/lmm_pastes.R +2 -1
  41. {lme_python-0.1.8 → lme_python-0.1.9}/comparisons/lmm_pastes.jl +8 -8
  42. {lme_python-0.1.8 → lme_python-0.1.9}/comparisons/lmm_penicillin.jl +10 -10
  43. lme_python-0.1.9/comparisons/parity/glmm_offset.R +21 -0
  44. lme_python-0.1.9/comparisons/parity/glmm_offset.jl +27 -0
  45. lme_python-0.1.9/comparisons/parity/glmm_probit.R +21 -0
  46. lme_python-0.1.9/comparisons/parity/glmm_probit.jl +27 -0
  47. lme_python-0.1.9/comparisons/parity/glmm_weighted.R +22 -0
  48. lme_python-0.1.9/comparisons/parity/glmm_weighted.jl +27 -0
  49. lme_python-0.1.9/comparisons/parity/parity_r_setup.R +6 -0
  50. lme_python-0.1.9/comparisons/parity/sleepstudy_offset.R +21 -0
  51. lme_python-0.1.9/comparisons/parity/sleepstudy_offset.jl +27 -0
  52. lme_python-0.1.9/comparisons/parity_export.rs +125 -0
  53. lme_python-0.1.9/comparisons/r_setup.R +3 -0
  54. {lme_python-0.1.8 → lme_python-0.1.9}/comparisons/sleepstudy.R +1 -0
  55. {lme_python-0.1.8 → lme_python-0.1.9}/comparisons/sleepstudy.jl +12 -12
  56. {lme_python-0.1.8 → lme_python-0.1.9}/comparisons/sleepstudy_ml.jl +1 -1
  57. lme_python-0.1.9/examples/nlmm_fixture_dump.rs +40 -0
  58. {lme_python-0.1.8 → lme_python-0.1.9}/lefthook.yml +14 -0
  59. {lme_python-0.1.8 → lme_python-0.1.9}/pyproject.toml +5 -0
  60. {lme_python-0.1.8 → lme_python-0.1.9}/python/Cargo.lock +23 -23
  61. {lme_python-0.1.8 → lme_python-0.1.9}/python/Cargo.toml +1 -1
  62. {lme_python-0.1.8 → lme_python-0.1.9}/python/PYTHON_GUIDE.md +94 -19
  63. {lme_python-0.1.8 → lme_python-0.1.9}/python/lme_python.pyi +38 -14
  64. {lme_python-0.1.8 → lme_python-0.1.9}/python/src/lib.rs +296 -14
  65. {lme_python-0.1.8 → lme_python-0.1.9}/python/tests/test_api_parity.py +51 -0
  66. lme_python-0.1.9/python/tests/test_dataframe_inputs.py +45 -0
  67. lme_python-0.1.9/python/tests/test_golden_parity.py +112 -0
  68. lme_python-0.1.9/python/tests/test_nlmer_custom_mean.py +54 -0
  69. lme_python-0.1.9/python/uv.lock +2289 -0
  70. {lme_python-0.1.8 → lme_python-0.1.9}/scripts/ci/README.md +2 -2
  71. lme_python-0.1.9/scripts/ci/julia_format.jl +56 -0
  72. lme_python-0.1.9/scripts/ci/lme_ci.py +710 -0
  73. lme_python-0.1.9/scripts/ci/r_format.R +19 -0
  74. lme_python-0.1.9/scripts/run_fair_rust_julia_benchmark.py +655 -0
  75. lme_python-0.1.9/scripts/run_perf_breakdown.py +342 -0
  76. lme_python-0.1.9/scripts/verify_cross_language_parity.py +331 -0
  77. {lme_python-0.1.8 → lme_python-0.1.9}/src/anova.rs +51 -0
  78. {lme_python-0.1.8 → lme_python-0.1.9}/src/anova_contrasts.rs +36 -2
  79. {lme_python-0.1.8 → lme_python-0.1.9}/src/family.rs +194 -33
  80. {lme_python-0.1.8 → lme_python-0.1.9}/src/glmm_math.rs +15 -179
  81. lme_python-0.1.9/src/intercept_blocked.rs +1237 -0
  82. {lme_python-0.1.8 → lme_python-0.1.9}/src/lib.rs +244 -137
  83. lme_python-0.1.9/src/math.rs +1699 -0
  84. {lme_python-0.1.8 → lme_python-0.1.9}/src/model_matrix.rs +281 -63
  85. lme_python-0.1.9/src/nlmm/fit.rs +1075 -0
  86. lme_python-0.1.9/src/nlmm/formula.rs +284 -0
  87. lme_python-0.1.9/src/nlmm/mean.rs +25 -0
  88. lme_python-0.1.9/src/nlmm/mean_fn.rs +151 -0
  89. lme_python-0.1.9/src/nlmm/mod.rs +87 -0
  90. lme_python-0.1.9/src/nlmm/predict.rs +104 -0
  91. lme_python-0.1.9/src/nlmm/re_cov.rs +125 -0
  92. lme_python-0.1.9/src/nlmm/self_start.rs +214 -0
  93. lme_python-0.1.9/src/nlmm/ssasymp.rs +33 -0
  94. lme_python-0.1.9/src/nlmm/ssgompertz.rs +47 -0
  95. lme_python-0.1.9/src/nlmm/ssmicmen.rs +27 -0
  96. {lme_python-0.1.8 → lme_python-0.1.9}/src/optimizer.rs +344 -24
  97. lme_python-0.1.9/src/perf_diag.rs +302 -0
  98. lme_python-0.1.9/src/quadrature.rs +187 -0
  99. {lme_python-0.1.8 → lme_python-0.1.9}/src/satterthwaite.rs +2 -0
  100. lme_python-0.1.9/tests/data/cbpp_binary.csv +843 -0
  101. lme_python-0.1.9/tests/data/cbpp_binary_weighted.csv +843 -0
  102. lme_python-0.1.9/tests/data/glmm_binomial_probit.json +872 -0
  103. lme_python-0.1.9/tests/data/glmm_binomial_weighted.json +872 -0
  104. lme_python-0.1.9/tests/data/glmm_poisson_offset.json +536 -0
  105. {lme_python-0.1.8 → lme_python-0.1.9}/tests/data/golden_parity_manifest.json +374 -36
  106. lme_python-0.1.9/tests/data/grouseticks.csv +404 -0
  107. lme_python-0.1.9/tests/data/orange_nlmer.json +12 -0
  108. lme_python-0.1.9/tests/data/pastes_cask_reml.json +100 -0
  109. lme_python-0.1.9/tests/data/sleepstudy.csv +181 -0
  110. lme_python-0.1.9/tests/data/sleepstudy_offset_reml.json +246 -0
  111. lme_python-0.1.9/tests/data/ssasymp_synthetic.csv +61 -0
  112. lme_python-0.1.9/tests/data/ssfol_nlmer.json +10 -0
  113. lme_python-0.1.9/tests/data/ssgompertz_nlmer.json +10 -0
  114. lme_python-0.1.9/tests/data/ssgompertz_synthetic.csv +61 -0
  115. lme_python-0.1.9/tests/data/ssmicmen_nlmer.json +10 -0
  116. lme_python-0.1.9/tests/data/ssmicmen_synthetic.csv +61 -0
  117. lme_python-0.1.9/tests/gen_nlmm_extras.R +54 -0
  118. lme_python-0.1.9/tests/generate_nlmm_fixtures.R +65 -0
  119. lme_python-0.1.9/tests/generate_test_data.R +895 -0
  120. {lme_python-0.1.8 → lme_python-0.1.9}/tests/test_anova.rs +2 -0
  121. {lme_python-0.1.8 → lme_python-0.1.9}/tests/test_anova_types.rs +18 -0
  122. {lme_python-0.1.8 → lme_python-0.1.9}/tests/test_contrast.rs +4 -0
  123. {lme_python-0.1.8 → lme_python-0.1.9}/tests/test_coverage_gaps.rs +2 -0
  124. {lme_python-0.1.8 → lme_python-0.1.9}/tests/test_crossed_mock.rs +14 -0
  125. {lme_python-0.1.8 → lme_python-0.1.9}/tests/test_errors.rs +20 -21
  126. lme_python-0.1.9/tests/test_glmm_links.rs +78 -0
  127. lme_python-0.1.9/tests/test_glmm_offset_grouseticks.rs +43 -0
  128. {lme_python-0.1.8 → lme_python-0.1.9}/tests/test_golden_parity.rs +81 -12
  129. lme_python-0.1.9/tests/test_nlmm_agq.rs +37 -0
  130. lme_python-0.1.9/tests/test_nlmm_custom_mean.rs +51 -0
  131. lme_python-0.1.9/tests/test_nlmm_orange.rs +154 -0
  132. lme_python-0.1.9/tests/test_nlmm_orange_multi_re.rs +92 -0
  133. lme_python-0.1.8/tests/test_nlmm_orange.rs → lme_python-0.1.9/tests/test_nlmm_self_start.rs +11 -22
  134. lme_python-0.1.9/tests/test_nlmm_ssasymp.rs +79 -0
  135. lme_python-0.1.9/tests/test_nlmm_ssfol.rs +98 -0
  136. lme_python-0.1.9/tests/test_nlmm_ssmicmen.rs +37 -0
  137. {lme_python-0.1.8 → lme_python-0.1.9}/tests/test_production_load.rs +60 -3
  138. {lme_python-0.1.8 → lme_python-0.1.9}/tests/test_sandwich_math.R +3 -3
  139. lme_python-0.1.8/BENCHMARKS.md +0 -183
  140. lme_python-0.1.8/CHANGELOG.md +0 -118
  141. lme_python-0.1.8/REPO_COMPLETION_BY_AREA.md +0 -74
  142. lme_python-0.1.8/python/requirements-ci.txt +0 -87
  143. lme_python-0.1.8/scripts/ci/lme_ci.py +0 -404
  144. lme_python-0.1.8/src/math.rs +0 -420
  145. lme_python-0.1.8/src/nlmm/fit.rs +0 -528
  146. lme_python-0.1.8/src/nlmm/formula.rs +0 -124
  147. lme_python-0.1.8/src/nlmm/mod.rs +0 -37
  148. lme_python-0.1.8/tests/data/cbpp_binary.csv +0 -843
  149. lme_python-0.1.8/tests/data/grouseticks.csv +0 -404
  150. lme_python-0.1.8/tests/data/orange_nlmer.json +0 -15
  151. lme_python-0.1.8/tests/data/pastes_cask_reml.json +0 -17
  152. lme_python-0.1.8/tests/data/sleepstudy.csv +0 -181
  153. lme_python-0.1.8/tests/generate_test_data.R +0 -506
  154. {lme_python-0.1.8 → lme_python-0.1.9}/.github/workflows/crate-publish-dry-run.yml +0 -0
  155. {lme_python-0.1.8 → lme_python-0.1.9}/.github/workflows/fuzz-smoke.yml +0 -0
  156. {lme_python-0.1.8 → lme_python-0.1.9}/LICENSE +0 -0
  157. {lme_python-0.1.8 → lme_python-0.1.9}/benches/bench_load_production.rs +0 -0
  158. {lme_python-0.1.8 → lme_python-0.1.9}/benches/bench_math.rs +0 -0
  159. {lme_python-0.1.8 → lme_python-0.1.9}/comparisons/categorical_anova.py +0 -0
  160. {lme_python-0.1.8 → lme_python-0.1.9}/comparisons/categorical_anova.rs +0 -0
  161. {lme_python-0.1.8 → lme_python-0.1.9}/comparisons/comparison_chart.png +0 -0
  162. {lme_python-0.1.8 → lme_python-0.1.9}/comparisons/glmm_cbpp.py +0 -0
  163. {lme_python-0.1.8 → lme_python-0.1.9}/comparisons/glmm_cbpp.rs +0 -0
  164. {lme_python-0.1.8 → lme_python-0.1.9}/comparisons/glmm_gaussian.jl +0 -0
  165. {lme_python-0.1.8 → lme_python-0.1.9}/comparisons/glmm_gaussian.py +0 -0
  166. {lme_python-0.1.8 → lme_python-0.1.9}/comparisons/glmm_gaussian.rs +0 -0
  167. {lme_python-0.1.8 → lme_python-0.1.9}/comparisons/glmm_grouseticks.py +0 -0
  168. {lme_python-0.1.8 → lme_python-0.1.9}/comparisons/glmm_grouseticks.rs +0 -0
  169. {lme_python-0.1.8 → lme_python-0.1.9}/comparisons/lmer_weighted.py +0 -0
  170. {lme_python-0.1.8 → lme_python-0.1.9}/comparisons/lmer_weighted.rs +0 -0
  171. {lme_python-0.1.8 → lme_python-0.1.9}/comparisons/lmm_dyestuff.R +0 -0
  172. {lme_python-0.1.8 → lme_python-0.1.9}/comparisons/lmm_dyestuff.py +0 -0
  173. {lme_python-0.1.8 → lme_python-0.1.9}/comparisons/lmm_dyestuff.rs +0 -0
  174. {lme_python-0.1.8 → lme_python-0.1.9}/comparisons/lmm_pastes.py +0 -0
  175. {lme_python-0.1.8 → lme_python-0.1.9}/comparisons/lmm_pastes.rs +0 -0
  176. {lme_python-0.1.8 → lme_python-0.1.9}/comparisons/lmm_penicillin.R +0 -0
  177. {lme_python-0.1.8 → lme_python-0.1.9}/comparisons/lmm_penicillin.py +0 -0
  178. {lme_python-0.1.8 → lme_python-0.1.9}/comparisons/lmm_penicillin.rs +0 -0
  179. {lme_python-0.1.8 → lme_python-0.1.9}/comparisons/sleepstudy.py +0 -0
  180. {lme_python-0.1.8 → lme_python-0.1.9}/comparisons/sleepstudy.rs +0 -0
  181. {lme_python-0.1.8 → lme_python-0.1.9}/comparisons/sleepstudy_ml.R +0 -0
  182. {lme_python-0.1.8 → lme_python-0.1.9}/comparisons/sleepstudy_ml.py +0 -0
  183. {lme_python-0.1.8 → lme_python-0.1.9}/comparisons/sleepstudy_ml.rs +0 -0
  184. {lme_python-0.1.8 → lme_python-0.1.9}/docs/benchmarks/app.js +0 -0
  185. {lme_python-0.1.8 → lme_python-0.1.9}/docs/benchmarks/index.html +0 -0
  186. {lme_python-0.1.8 → lme_python-0.1.9}/docs/benchmarks/styles.css +0 -0
  187. {lme_python-0.1.8 → lme_python-0.1.9}/docs/index.html +0 -0
  188. {lme_python-0.1.8 → lme_python-0.1.9}/mise.toml +0 -0
  189. {lme_python-0.1.8 → lme_python-0.1.9}/python/examples/glmer_cbpp.py +0 -0
  190. {lme_python-0.1.8 → lme_python-0.1.9}/python/examples/glmer_grouseticks.py +0 -0
  191. {lme_python-0.1.8 → lme_python-0.1.9}/python/examples/lm_basics.py +0 -0
  192. {lme_python-0.1.8 → lme_python-0.1.9}/python/examples/lmer_sleepstudy.py +0 -0
  193. {lme_python-0.1.8 → lme_python-0.1.9}/python/examples/model_comparison.py +0 -0
  194. {lme_python-0.1.8 → lme_python-0.1.9}/python/examples/plotting_demo/.gitignore +0 -0
  195. {lme_python-0.1.8 → lme_python-0.1.9}/python/examples/plotting_demo/README.md +0 -0
  196. {lme_python-0.1.8 → lme_python-0.1.9}/python/examples/plotting_demo/compare_plots.py +0 -0
  197. {lme_python-0.1.8 → lme_python-0.1.9}/python/examples/plotting_demo/figure_specs.py +0 -0
  198. {lme_python-0.1.8 → lme_python-0.1.9}/python/examples/plotting_demo/find_rscript.py +0 -0
  199. {lme_python-0.1.8 → lme_python-0.1.9}/python/examples/plotting_demo/numeric_overlay.py +0 -0
  200. {lme_python-0.1.8 → lme_python-0.1.9}/python/examples/plotting_demo/paths.py +0 -0
  201. {lme_python-0.1.8 → lme_python-0.1.9}/python/examples/plotting_demo/plot_demo.py +0 -0
  202. {lme_python-0.1.8 → lme_python-0.1.9}/python/examples/plotting_demo/plot_r.R +0 -0
  203. {lme_python-0.1.8 → lme_python-0.1.9}/python/examples/plotting_demo/run_all.py +0 -0
  204. {lme_python-0.1.8 → lme_python-0.1.9}/python/examples/verification_project/README.md +0 -0
  205. {lme_python-0.1.8 → lme_python-0.1.9}/python/examples/verification_project/conftest.py +0 -0
  206. {lme_python-0.1.8 → lme_python-0.1.9}/python/examples/verification_project/parity.py +0 -0
  207. {lme_python-0.1.8 → lme_python-0.1.9}/python/examples/verification_project/paths.py +0 -0
  208. {lme_python-0.1.8 → lme_python-0.1.9}/python/examples/verification_project/run.py +0 -0
  209. {lme_python-0.1.8 → lme_python-0.1.9}/python/examples/verification_project/test_parity.py +0 -0
  210. {lme_python-0.1.8 → lme_python-0.1.9}/python/tests/test_basic.py +0 -0
  211. {lme_python-0.1.8 → lme_python-0.1.9}/scripts/ast_explorations/test_fiasto.rs +0 -0
  212. {lme_python-0.1.8 → lme_python-0.1.9}/scripts/ast_explorations/test_fiasto_offset.rs +0 -0
  213. {lme_python-0.1.8 → lme_python-0.1.9}/scripts/build_benchmark_site.py +0 -0
  214. {lme_python-0.1.8 → lme_python-0.1.9}/scripts/ci/run.sh +0 -0
  215. {lme_python-0.1.8 → lme_python-0.1.9}/scripts/dump_dyestuff.R +0 -0
  216. {lme_python-0.1.8 → lme_python-0.1.9}/scripts/dump_pastes.R +0 -0
  217. {lme_python-0.1.8 → lme_python-0.1.9}/scripts/local_ci.ps1 +0 -0
  218. {lme_python-0.1.8 → lme_python-0.1.9}/scripts/local_ci.sh +0 -0
  219. {lme_python-0.1.8 → lme_python-0.1.9}/scripts/make_penicillin_csv.py +0 -0
  220. {lme_python-0.1.8 → lme_python-0.1.9}/scripts/plot_comparisons.py +0 -0
  221. {lme_python-0.1.8 → lme_python-0.1.9}/scripts/run_cross_language_benchmarks.py +0 -0
  222. {lme_python-0.1.8 → lme_python-0.1.9}/scripts/sync_github_repo_metadata.py +0 -0
  223. {lme_python-0.1.8 → lme_python-0.1.9}/src/contrast.rs +0 -0
  224. {lme_python-0.1.8 → lme_python-0.1.9}/src/ddf.rs +0 -0
  225. {lme_python-0.1.8 → lme_python-0.1.9}/src/formula.rs +0 -0
  226. {lme_python-0.1.8 → lme_python-0.1.9}/src/kenward_roger.rs +0 -0
  227. {lme_python-0.1.8 → lme_python-0.1.9}/src/kr_modcomp.rs +0 -0
  228. {lme_python-0.1.8 → lme_python-0.1.9}/src/kr_vcov_adj.rs +0 -0
  229. {lme_python-0.1.8 → lme_python-0.1.9}/src/nlmm/sslogis.rs +0 -0
  230. {lme_python-0.1.8 → lme_python-0.1.9}/src/robust.rs +0 -0
  231. {lme_python-0.1.8 → lme_python-0.1.9}/tests/categorical_anova_test.rs +0 -0
  232. {lme_python-0.1.8 → lme_python-0.1.9}/tests/data/dyestuff.csv +0 -0
  233. {lme_python-0.1.8 → lme_python-0.1.9}/tests/data/glmm_binomial.json +0 -0
  234. {lme_python-0.1.8 → lme_python-0.1.9}/tests/data/glmm_poisson.json +0 -0
  235. {lme_python-0.1.8 → lme_python-0.1.9}/tests/data/intercept_only.json +0 -0
  236. {lme_python-0.1.8 → lme_python-0.1.9}/tests/data/mock_crossed.json +0 -0
  237. {lme_python-0.1.8 → lme_python-0.1.9}/tests/data/mock_ml.json +0 -0
  238. {lme_python-0.1.8 → lme_python-0.1.9}/tests/data/orange.csv +0 -0
  239. {lme_python-0.1.8 → lme_python-0.1.9}/tests/data/pastes.csv +0 -0
  240. {lme_python-0.1.8 → lme_python-0.1.9}/tests/data/penicillin.csv +0 -0
  241. {lme_python-0.1.8 → lme_python-0.1.9}/tests/data/penicillin.json +0 -0
  242. {lme_python-0.1.8 → lme_python-0.1.9}/tests/data/random_slopes.json +0 -0
  243. {lme_python-0.1.8 → lme_python-0.1.9}/tests/generate_mock_data.py +0 -0
  244. {lme_python-0.1.8 → lme_python-0.1.9}/tests/test_conditional_real.rs +0 -0
  245. {lme_python-0.1.8 → lme_python-0.1.9}/tests/test_confint_simulate.rs +0 -0
  246. {lme_python-0.1.8 → lme_python-0.1.9}/tests/test_coverage_edge_cases.rs +0 -0
  247. {lme_python-0.1.8 → lme_python-0.1.9}/tests/test_e2e_lmer.rs +0 -0
  248. {lme_python-0.1.8 → lme_python-0.1.9}/tests/test_edge_cases.rs +0 -0
  249. {lme_python-0.1.8 → lme_python-0.1.9}/tests/test_failure_modes.rs +0 -0
  250. {lme_python-0.1.8 → lme_python-0.1.9}/tests/test_formula.rs +0 -0
  251. {lme_python-0.1.8 → lme_python-0.1.9}/tests/test_formula_stress.rs +0 -0
  252. {lme_python-0.1.8 → lme_python-0.1.9}/tests/test_gaps.rs +0 -0
  253. {lme_python-0.1.8 → lme_python-0.1.9}/tests/test_glmm.rs +0 -0
  254. {lme_python-0.1.8 → lme_python-0.1.9}/tests/test_glmm_weighted.rs +0 -0
  255. {lme_python-0.1.8 → lme_python-0.1.9}/tests/test_intercept_only.rs +0 -0
  256. {lme_python-0.1.8 → lme_python-0.1.9}/tests/test_kenward_roger.rs +0 -0
  257. {lme_python-0.1.8 → lme_python-0.1.9}/tests/test_kr_modcomp_pastes.rs +0 -0
  258. {lme_python-0.1.8 → lme_python-0.1.9}/tests/test_ml_optimization.rs +0 -0
  259. {lme_python-0.1.8 → lme_python-0.1.9}/tests/test_no_intercept.rs +0 -0
  260. {lme_python-0.1.8 → lme_python-0.1.9}/tests/test_numerical_parity.rs +0 -0
  261. {lme_python-0.1.8 → lme_python-0.1.9}/tests/test_predict.rs +0 -0
  262. {lme_python-0.1.8 → lme_python-0.1.9}/tests/test_random_slopes.rs +0 -0
  263. {lme_python-0.1.8 → lme_python-0.1.9}/tests/test_robust.rs +0 -0
  264. {lme_python-0.1.8 → lme_python-0.1.9}/tests/test_satterthwaite.rs +0 -0
  265. {lme_python-0.1.8 → lme_python-0.1.9}/tests/test_statistical_identities.rs +0 -0
@@ -0,0 +1,8 @@
1
+ # JuliaFormatter defaults for comparison / parity scripts under comparisons/.
2
+ indent = 4
3
+ margin = 92
4
+ always_for_in = true
5
+ whitespace_typedefs = true
6
+ whitespace_ops_in_indices = true
7
+ remove_extra_newlines = true
8
+ join_lines_based_on_source = true
@@ -1,24 +1,10 @@
1
1
  name: Security audit
2
2
 
3
3
  on:
4
- schedule:
5
- # Weekly: Mondays 12:00 UTC
6
- - cron: "0 12 * * 1"
7
4
  workflow_dispatch:
8
5
  push:
9
- branches: [master]
10
- paths:
11
- - "**/Cargo.toml"
12
- - "**/Cargo.lock"
13
- - "python/pyproject.toml"
14
- - "python/requirements-ci.txt"
15
- pull_request:
16
- branches: [master]
17
- paths:
18
- - "**/Cargo.toml"
19
- - "**/Cargo.lock"
20
- - "python/pyproject.toml"
21
- - "python/requirements-ci.txt"
6
+ tags:
7
+ - "v*"
22
8
 
23
9
  permissions:
24
10
  contents: read
@@ -49,25 +35,21 @@ jobs:
49
35
  run: cargo audit
50
36
 
51
37
  pip-audit:
52
- name: pip-audit (python lockfile)
38
+ name: pip-audit (uv.lock)
53
39
  runs-on: ubuntu-latest
54
40
  steps:
55
41
  - uses: actions/checkout@v6
56
42
 
57
- - name: Set up Python
58
- uses: actions/setup-python@v6
43
+ - name: Set up uv
44
+ uses: astral-sh/setup-uv@v6
59
45
  with:
60
46
  python-version: "3.11"
61
- cache: pip
62
- cache-dependency-path: python/requirements-ci.txt
47
+ enable-cache: true
48
+ cache-dependency-glob: "python/uv.lock"
63
49
 
64
- - name: Install locked CI dependencies
50
+ - name: pip-audit
65
51
  working-directory: python
66
52
  run: |
67
53
  set -euo pipefail
68
- python -m pip install -U pip
69
- python -m pip install -r requirements-ci.txt
70
-
71
- - name: pip-audit
72
- working-directory: python
73
- run: python -m pip_audit
54
+ uv sync --extra dev --no-install-project
55
+ uv run pip-audit
@@ -122,13 +122,24 @@ jobs:
122
122
  - name: Install R benchmark dependencies
123
123
  run: |
124
124
  mkdir -p "$R_LIBS_USER"
125
- Rscript -e 'install.packages("lme4", repos="https://cloud.r-project.org", lib=Sys.getenv("R_LIBS_USER"))'
125
+ Rscript -e 'install.packages(c("lme4", "lmerTest", "car", "rlang", "styler"), repos="https://cloud.r-project.org", lib=Sys.getenv("R_LIBS_USER"))'
126
126
 
127
127
  - name: Install Julia benchmark dependencies
128
- run: julia -e 'using Pkg; Pkg.add(["CSV", "DataFrames", "MixedModels"])'
128
+ run: julia -e 'using Pkg; Pkg.add(["CSV", "DataFrames", "JSON", "MixedModels", "GLM", "JuliaFormatter"])'
129
+
130
+ - name: Check comparison script formatting
131
+ run: python3 scripts/ci/lme_ci.py comparison-format-check --required
129
132
 
130
133
  - name: Build Rust examples
131
- run: cargo build --release --examples
134
+ run: cargo build --release --locked --examples
135
+
136
+ - name: Run fair Rust vs Julia fit benchmark
137
+ run: |
138
+ python scripts/run_fair_rust_julia_benchmark.py \
139
+ --warmups "$BENCH_WARMUPS" \
140
+ --repeats "$BENCH_REPEATS" \
141
+ --output "benchmark-results/fair-rust-julia-${{ github.sha }}.json" \
142
+ --skip-rust-build
132
143
 
133
144
  - name: Run cross-language benchmark script
134
145
  id: cross_language_run
@@ -149,7 +160,9 @@ jobs:
149
160
  uses: actions/upload-artifact@v7
150
161
  with:
151
162
  name: cross-language-${{ github.sha }}
152
- path: benchmark-results/cross-language-${{ github.sha }}.json
163
+ path: |
164
+ benchmark-results/cross-language-${{ github.sha }}.json
165
+ benchmark-results/fair-rust-julia-${{ github.sha }}.json
153
166
 
154
167
  - name: Attach cross-language artifact to GitHub Release
155
168
  if: always() && startsWith(github.ref, 'refs/tags/')
@@ -164,10 +177,17 @@ jobs:
164
177
  fi
165
178
  }
166
179
  gh release upload "${GITHUB_REF_NAME}" "benchmark-results/cross-language-${{ github.sha }}.json" --clobber
180
+ if [ -f "benchmark-results/fair-rust-julia-${{ github.sha }}.json" ]; then
181
+ gh release upload "${GITHUB_REF_NAME}" "benchmark-results/fair-rust-julia-${{ github.sha }}.json" --clobber
182
+ fi
167
183
 
168
184
  - name: Fail if cross-language benchmarks failed
169
185
  if: steps.cross_language_run.outputs.status != '0'
170
186
  run: |
187
+ json="benchmark-results/cross-language-${{ github.sha }}.json"
188
+ if [ -f "$json" ]; then
189
+ python3 scripts/ci/lme_ci.py benchmark-failures "$json" >&2 || true
190
+ fi
171
191
  echo "Cross-language benchmark script failed with exit code ${{ steps.cross_language_run.outputs.status }}." >&2
172
192
  exit 1
173
193
 
@@ -2,15 +2,9 @@ name: CI
2
2
 
3
3
  on:
4
4
  push:
5
- branches: [master]
6
- paths-ignore:
7
- - "**/*.md"
8
- - "LICENSE"
9
- pull_request:
10
- branches: [master]
11
- paths-ignore:
12
- - "**/*.md"
13
- - "LICENSE"
5
+ tags:
6
+ - "v*"
7
+ workflow_dispatch:
14
8
 
15
9
  permissions:
16
10
  contents: read
@@ -77,35 +71,25 @@ jobs:
77
71
  if: matrix.os == 'macos-latest'
78
72
  run: echo "OPENBLAS_TARGET=ARMV8" >> "$GITHUB_ENV"
79
73
 
80
- - name: Build
81
- run: cargo build --verbose --locked
82
-
83
74
  - name: Run tests
84
75
  run: cargo test --verbose --locked
85
76
 
86
- - name: Set up Python
87
- uses: actions/setup-python@v6
77
+ - name: Set up uv
78
+ uses: astral-sh/setup-uv@v6
88
79
  with:
89
80
  python-version: "3.11"
90
- cache: pip
91
- cache-dependency-path: python/requirements-ci.txt
81
+ enable-cache: true
82
+ cache-dependency-glob: "python/uv.lock"
92
83
 
93
84
  - name: Python bindings (maturin develop, pytest, wheel install, pytest)
94
85
  working-directory: python
95
86
  shell: bash
96
87
  run: |
97
88
  set -euo pipefail
98
- python -m venv .venv
99
- if [ -f .venv/Scripts/python.exe ]; then
100
- VPY=.venv/Scripts/python.exe
101
- else
102
- VPY=.venv/bin/python
103
- fi
104
- "$VPY" -m pip install -U pip
105
- "$VPY" -m pip install -r requirements-ci.txt
106
- "$VPY" -m maturin develop --release
107
- "$VPY" -m pytest tests/ -v
108
- "$VPY" -m maturin build --release -o dist
89
+ uv sync --extra dev --no-install-project
90
+ uv run maturin develop --release
91
+ uv run pytest tests/ -v
92
+ uv run maturin build --release -o dist
109
93
  shopt -s nullglob
110
94
  wheels=(dist/lme_python-*.whl)
111
95
  if [ ${#wheels[@]} -eq 0 ]; then
@@ -113,8 +97,8 @@ jobs:
113
97
  ls -la dist 2>/dev/null || true
114
98
  exit 1
115
99
  fi
116
- "$VPY" -m pip install --force-reinstall "${wheels[0]}"
117
- "$VPY" -m pytest tests/ -v
100
+ uv run pip install --force-reinstall "${wheels[0]}"
101
+ uv run pytest tests/ -v
118
102
 
119
103
  rust-all-targets:
120
104
  name: Rust check (all targets)
@@ -205,28 +189,22 @@ jobs:
205
189
  target
206
190
  key: ubuntu-cargo-${{ hashFiles('**/Cargo.lock') }}
207
191
  restore-keys: ubuntu-cargo-
208
- - name: Set up Python
209
- uses: actions/setup-python@v6
192
+ - name: Set up uv
193
+ uses: astral-sh/setup-uv@v6
210
194
  with:
211
195
  python-version: ${{ matrix.python-version }}
212
- cache: pip
213
- cache-dependency-path: python/requirements-ci.txt
196
+ enable-cache: true
197
+ cache-dependency-glob: "python/uv.lock"
198
+
214
199
  - name: Python bindings (maturin develop, pytest, wheel install, pytest)
215
200
  working-directory: python
216
201
  shell: bash
217
202
  run: |
218
203
  set -euo pipefail
219
- python -m venv .venv
220
- if [ -f .venv/Scripts/python.exe ]; then
221
- VPY=.venv/Scripts/python.exe
222
- else
223
- VPY=.venv/bin/python
224
- fi
225
- "$VPY" -m pip install -U pip
226
- "$VPY" -m pip install -r requirements-ci.txt
227
- "$VPY" -m maturin develop --release
228
- "$VPY" -m pytest tests/ -v
229
- "$VPY" -m maturin build --release -o dist
204
+ uv sync --extra dev --no-install-project
205
+ uv run maturin develop --release
206
+ uv run pytest tests/ -v
207
+ uv run maturin build --release -o dist
230
208
  shopt -s nullglob
231
209
  wheels=(dist/lme_python-*.whl)
232
210
  if [ ${#wheels[@]} -eq 0 ]; then
@@ -234,8 +212,8 @@ jobs:
234
212
  ls -la dist 2>/dev/null || true
235
213
  exit 1
236
214
  fi
237
- "$VPY" -m pip install --force-reinstall "${wheels[0]}"
238
- "$VPY" -m pytest tests/ -v
215
+ uv run pip install --force-reinstall "${wheels[0]}"
216
+ uv run pytest tests/ -v
239
217
 
240
218
  docs:
241
219
  name: Build docs
@@ -1,16 +1,10 @@
1
1
  name: Build and Publish Python Wheels
2
2
 
3
- # Trigger on pushes to the master branch or when a release tag (v*) is pushed
3
+ # Trigger automatically only for release tags; use workflow_dispatch for manual builds.
4
4
  on:
5
5
  push:
6
- branches:
7
- - master
8
6
  tags:
9
- - 'v*'
10
- pull_request:
11
- paths:
12
- - 'python/**'
13
- - 'src/**'
7
+ - "v*"
14
8
  workflow_dispatch:
15
9
 
16
10
  permissions:
@@ -2,11 +2,8 @@ name: Sync Repository Metadata
2
2
 
3
3
  on:
4
4
  push:
5
- branches: [master]
6
- paths:
7
- - Cargo.toml
8
- - scripts/sync_github_repo_metadata.py
9
- - .github/workflows/repo-metadata.yml
5
+ tags:
6
+ - "v*"
10
7
  workflow_dispatch:
11
8
 
12
9
  permissions:
@@ -10,6 +10,7 @@ flamegraph.svg
10
10
  artifacts/
11
11
  benchmark-results/
12
12
  benchmark-site/
13
+ .r-lib/
13
14
  site/
14
15
 
15
16
  # Python bindings
@@ -38,7 +38,7 @@ flowchart TD
38
38
  | [`scripts/ci/lme_ci.py`](lme_ci.py) | One cross-platform implementation (stdlib Python 3.10+) |
39
39
  | [`lefthook.yml`](../lefthook.yml) | Declarative hooks, **parallel** pre-commit, `stage_fixed` auto-staging |
40
40
  | [`mise.toml`](../mise.toml) | Pins Rust, Python 3.11, uv, lefthook, task — reproducible dev env |
41
- | [`uv`](https://docs.astral.sh/uv/) | Fast venv creation (`uv venv --python 3.11`), no repo-root `.venv` backup dance |
41
+ | [`uv`](https://docs.astral.sh/uv/) | Locked Python env (`uv sync` + `uv.lock`); Ruff via `uv tool run` |
42
42
  | **Ruff** | `python/tests` + `python/examples` on `task lint`; staged auto-fix on commit |
43
43
  | **pre-push hook** | Automatic `preflight` (lint + `cargo check --all-targets` + `cargo audit` + repo metadata dry-run) |
44
44
 
@@ -65,8 +65,11 @@ task hooks:install
65
65
  |---|---|---|
66
66
  | `**/*.rs` | `fmt` then `clippy` | `stage_fixed: true` re-stages rustfmt fixes |
67
67
  | `python/**/*.py` | `ruff-staged --fix` | Ruff check + format; auto-stages fixes |
68
+ | `comparisons/**/*.R`, `tests/*.R` | `r-format-staged --fix` | **styler** when Rscript + styler are installed; skips otherwise |
69
+ | `comparisons/**/*.jl` | `julia-format-staged --fix` | **JuliaFormatter** when julia + JuliaFormatter are installed; skips otherwise |
68
70
  | `Cargo.toml`, `Cargo.lock`, `python/Cargo.toml`, `python/Cargo.lock` | `cargo check --all-targets` | Catches link/BLAS issues on your platform when manifests change |
69
71
  | `Cargo.toml`, `scripts/sync_github_repo_metadata.py` | `repo-metadata` dry-run (+ token verify if `REPO_ADMIN_TOKEN` set) | Validates About-box payload before GHA metadata sync |
72
+ | `comparisons/**`, benchmark script/workflow | `benchmarks-smoke` | Rust sleepstudy example timing (release build) |
70
73
 
71
74
  Runs **in parallel** where safe (Ruff vs Rust fmt). Clippy waits on fmt (`priority`); manifest `check` runs after clippy (`priority` 3).
72
75
 
@@ -96,18 +99,25 @@ If GHA reports `401 Bad credentials` on **Sync Repository Metadata**, rotate the
96
99
 
97
100
  Bypass: `git push --no-verify`.
98
101
 
99
- **macOS Apple Silicon BLAS** (`openblas-static` vs MKL) is only exercised on `macos-latest` in GHA — Windows/Linux preflights cannot catch that matrix cell. After changing `Cargo.toml` BLAS target tables or release workflows, run `task ci` or wait for the macOS CI job.
102
+ **macOS Apple Silicon BLAS** (`openblas-static` vs MKL) is only exercised on `macos-latest` in GHA — Windows/Linux preflights cannot catch that matrix cell. GHA now runs automatically only for `v*` tags (plus manual dispatch), so after changing `Cargo.toml` BLAS target tables or release workflows, run `task ci` locally or manually dispatch the CI workflow before tagging.
103
+
104
+ **Cross-language benchmarks** (R + Julia, tag-only [`.github/workflows/benchmarks.yml`](.github/workflows/benchmarks.yml)): pre-commit runs `benchmarks-smoke` when `comparisons/**` changes (Rust `sleepstudy` example only). Full matrix needs R (`lme4`, `lmerTest`, `car`, `rlang`, `styler`) and Julia (`JuliaFormatter`) — run it through the tag/manual GHA workflow or `task benchmarks:preflight` with R installed. Comparison script formatting is checked in that GHA job; locally use `task lint:comparisons` (skips when tools are missing) or `task lint:comparisons:required` when R/Julia formatters are installed.
100
105
 
101
106
  ## 3. Before finishing work (manual)
102
107
 
108
+ If you changed **LMM fit throughput** ([`src/math.rs`](src/math.rs) intercept path, [`src/optimizer.rs`](src/optimizer.rs) θ search), read **[OPTIMIZATION.md](OPTIMIZATION.md)** and re-run the fair harness cases listed there.
109
+
103
110
  ### Quick path
104
111
 
105
112
  ```powershell
106
113
  task lint
114
+ task test:fast # unit tests only (~seconds after compile)
107
115
  task preflight # same as pre-push hook (without pip-audit)
108
116
  task audit # full security audit incl. pip-audit
109
117
  ```
110
118
 
119
+ Full integration tests: `task test` or `cargo test --locked` (uses `[profile.test] opt-level = 2` in [`Cargo.toml`](Cargo.toml)).
120
+
111
121
  Runs Rust (`fmt --check` + clippy) and Python Ruff on `python/tests` and `python/examples`.
112
122
 
113
123
  If you changed **Python bindings**:
@@ -150,7 +160,7 @@ python scripts/ci/lme_ci.py ci
150
160
  python scripts/ci/lme_ci.py ci --reuse-venv --skip-wheel-reinstall
151
161
  ```
152
162
 
153
- **CI-only:** multi-OS matrix, Python 3.10/3.12/3.13, production-load gates, `cargo audit` / `pip-audit`.
163
+ **GHA-only:** multi-OS matrix, Python 3.10/3.12/3.13, production-load gates, and `pip-audit`. These workflows are release-oriented: automatic runs are limited to `v*` tags, with manual dispatch available for pre-release checks.
154
164
 
155
165
  ## `lme_ci.py` commands
156
166
 
@@ -161,8 +171,17 @@ python scripts/ci/lme_ci.py ci --reuse-venv --skip-wheel-reinstall
161
171
  | `preflight` | Pre-push: lint + check + cargo audit + repo metadata |
162
172
  | `audit` | cargo audit + pip-audit (GHA mirror) |
163
173
  | `repo-metadata` | Dry-run GitHub About sync; verify token if `REPO_ADMIN_TOKEN` set |
174
+ | `benchmarks-smoke` | Release examples + one Rust cross-language benchmark |
175
+ | `benchmarks-preflight` | `benchmarks-smoke` + optional `sleepstudy.R` when R/lme4 present |
176
+ | `benchmarks-fair-rust-julia` | Fair fit-only Rust vs MixedModels.jl timing (tier-A cases; see [BENCHMARK_COVERAGE.md](../BENCHMARK_COVERAGE.md); skip if Julia/packages missing) |
177
+ | `perf-breakdown` | Rust `LME_PERF_DIAG` vs Julia `optsum.feval`; reports `prepare` / `fit_prepared` / cold `lmer` |
164
178
  | `rust-lint` | `fmt --check` + clippy |
165
179
  | `ruff-lint` | Ruff on `python/tests` + `python/examples` |
180
+ | `comparison-format-check` | Optional styler/JuliaFormatter check on `comparisons/` (+ `tests/*.R`); use `--required` in GHA |
181
+ | `r-format-staged --fix` | Staged R comparison/golden-parity scripts |
182
+ | `julia-format-staged --fix` | Staged Julia comparison scripts |
183
+ | `build-test` | `cargo test` (full suite) |
184
+ | `test-fast` | `cargo test --lib` only (quick unit tests) |
166
185
  | `rust-all` | Rust slice without Python bindings tests |
167
186
  | `python` | Maturin + pytest (+ wheel pass) |
168
187
  | `ruff-staged --fix` | Staged Python lint/format |