lme-python 0.1.9__tar.gz → 0.2.1__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 (330) hide show
  1. lme_python-0.2.1/.github/dependabot.yml +10 -0
  2. lme_python-0.2.1/.github/workflows/audit.yml +62 -0
  3. {lme_python-0.1.9 → lme_python-0.2.1}/.github/workflows/benchmarks.yml +21 -12
  4. lme_python-0.2.1/.github/workflows/cache-prime.yml +115 -0
  5. lme_python-0.2.1/.github/workflows/ci.yml +254 -0
  6. lme_python-0.2.1/.github/workflows/crate-publish-dry-run.yml +48 -0
  7. {lme_python-0.1.9 → lme_python-0.2.1}/.github/workflows/fuzz-smoke.yml +17 -6
  8. lme_python-0.2.1/.github/workflows/python-release.yml +182 -0
  9. {lme_python-0.1.9 → lme_python-0.2.1}/.github/workflows/repo-metadata.yml +4 -1
  10. lme_python-0.2.1/AGENTS.md +100 -0
  11. {lme_python-0.1.9 → lme_python-0.2.1}/BENCHMARKS.md +124 -23
  12. {lme_python-0.1.9 → lme_python-0.2.1}/BENCHMARK_COVERAGE.md +18 -15
  13. {lme_python-0.1.9 → lme_python-0.2.1}/CHANGELOG.md +72 -2
  14. lme_python-0.2.1/CI_PERFORMANCE.md +63 -0
  15. {lme_python-0.1.9 → lme_python-0.2.1}/CONTRIBUTING.md +38 -12
  16. {lme_python-0.1.9 → lme_python-0.2.1}/Cargo.lock +11 -173
  17. {lme_python-0.1.9 → lme_python-0.2.1}/Cargo.toml +21 -4
  18. {lme_python-0.1.9 → lme_python-0.2.1}/GUIDE.md +246 -16
  19. lme_python-0.2.1/LICENSES/Apache-2.0.txt +193 -0
  20. lme_python-0.2.1/LICENSES/BSD-3-Clause-OpenBLAS.txt +31 -0
  21. lme_python-0.2.1/LICENSES/GPL-2.0-or-later.txt +342 -0
  22. lme_python-0.2.1/LICENSES/Intel-Simplified-Software-License.txt +79 -0
  23. lme_python-0.2.1/LICENSES/LGPL-2.1-only.txt +412 -0
  24. {lme_python-0.1.9 → lme_python-0.2.1}/OPTIMIZATION.md +161 -32
  25. {lme_python-0.1.9 → lme_python-0.2.1}/PKG-INFO +1 -1
  26. {lme_python-0.1.9 → lme_python-0.2.1}/README.md +15 -10
  27. lme_python-0.2.1/RELEASING.md +260 -0
  28. lme_python-0.2.1/RELINKING.md +22 -0
  29. lme_python-0.2.1/REPO_COMPLETION_BY_AREA.md +110 -0
  30. lme_python-0.2.1/THIRD_PARTY_NOTICES.md +18 -0
  31. {lme_python-0.1.9 → lme_python-0.2.1}/Taskfile.yml +53 -3
  32. {lme_python-0.1.9 → lme_python-0.2.1}/USABILITY.md +23 -16
  33. {lme_python-0.1.9 → lme_python-0.2.1}/benches/bench_math.rs +33 -7
  34. lme_python-0.2.1/benchmarks/fair-rust-julia-reference-2026-07-08.json +82 -0
  35. lme_python-0.2.1/benchmarks/fair-rust-julia-reference-2026-07-09-direct-intercept-gram.json +24 -0
  36. lme_python-0.2.1/benchmarks/fair-rust-julia-reference-2026-07-09-full-lmm.json +46 -0
  37. lme_python-0.2.1/benchmarks/fair-rust-julia-reference-2026-07-09-glmm.json +26 -0
  38. lme_python-0.2.1/benchmarks/fair-rust-julia-reference-2026-07-09-large-intercept-setup.json +26 -0
  39. lme_python-0.2.1/benchmarks/fair-rust-julia-reference-2026-07-09-large-slopes-linear-cache.json +23 -0
  40. lme_python-0.2.1/benchmarks/fair-rust-julia-reference-2026-07-09-large-slopes.json +23 -0
  41. lme_python-0.2.1/benchmarks/fair-rust-julia-reference-2026-07-09-sleepstudy-slopes.json +54 -0
  42. lme_python-0.2.1/benchmarks/fair-rust-julia-reference-2026-07-09.json +83 -0
  43. lme_python-0.2.1/benchmarks/fair-rust-julia-reference-2026-07-10-cold-setup-followup.json +24 -0
  44. lme_python-0.2.1/benchmarks/fair-rust-julia-reference-2026-07-16-cold-fit-lt1.json +363 -0
  45. lme_python-0.2.1/benchmarks/fair-rust-julia-reference-2026-07-22-full-tier-a.json +1593 -0
  46. {lme_python-0.1.9 → lme_python-0.2.1}/comparisons/COMPARISONS.md +31 -4
  47. {lme_python-0.1.9 → lme_python-0.2.1}/comparisons/bench_fair_julia_timing.jl +3 -2
  48. {lme_python-0.1.9 → lme_python-0.2.1}/comparisons/bench_fair_rust_julia.rs +38 -9
  49. {lme_python-0.1.9 → lme_python-0.2.1}/comparisons/bench_perf_breakdown.rs +6 -0
  50. lme_python-0.2.1/comparisons/nlmm_sspower.R +60 -0
  51. {lme_python-0.1.9 → lme_python-0.2.1}/comparisons/parity_export.rs +1 -6
  52. lme_python-0.2.1/completion_manifest.json +20 -0
  53. lme_python-0.2.1/docs/CALO_CALIBRATION.md +124 -0
  54. lme_python-0.2.1/examples/batch_sspower_cpu.rs +221 -0
  55. lme_python-0.2.1/examples/dump_cascade_fixtures.rs +339 -0
  56. {lme_python-0.1.9 → lme_python-0.2.1}/examples/nlmm_fixture_dump.rs +11 -0
  57. lme_python-0.2.1/legal/dependency-license-exceptions.json +17 -0
  58. lme_python-0.2.1/legal/fixture-provenance.json +45 -0
  59. {lme_python-0.1.9 → lme_python-0.2.1}/python/Cargo.lock +13 -174
  60. {lme_python-0.1.9 → lme_python-0.2.1}/python/Cargo.toml +1 -1
  61. {lme_python-0.1.9 → lme_python-0.2.1}/python/PYTHON_GUIDE.md +173 -13
  62. {lme_python-0.1.9 → lme_python-0.2.1}/python/lme_python.pyi +158 -2
  63. {lme_python-0.1.9 → lme_python-0.2.1}/python/src/lib.rs +754 -25
  64. lme_python-0.2.1/python/tests/test_cv.py +102 -0
  65. {lme_python-0.1.9 → lme_python-0.2.1}/python/tests/test_golden_parity.py +9 -0
  66. {lme_python-0.1.9 → lme_python-0.2.1}/python/tests/test_nlmer_custom_mean.py +25 -0
  67. lme_python-0.2.1/python/tests/test_simulate_scale.py +43 -0
  68. lme_python-0.2.1/python/tests/test_wheel_notices.py +86 -0
  69. {lme_python-0.1.9 → lme_python-0.2.1}/scripts/ci/README.md +2 -2
  70. lme_python-0.2.1/scripts/ci/check_completion_score.py +101 -0
  71. lme_python-0.2.1/scripts/ci/check_legal_compliance.py +99 -0
  72. {lme_python-0.1.9 → lme_python-0.2.1}/scripts/ci/lme_ci.py +252 -33
  73. lme_python-0.2.1/scripts/ci/package_wheel_notices.py +165 -0
  74. {lme_python-0.1.9 → lme_python-0.2.1}/scripts/run_fair_rust_julia_benchmark.py +11 -3
  75. lme_python-0.2.1/src/bootstrap.rs +523 -0
  76. lme_python-0.2.1/src/cv.rs +720 -0
  77. lme_python-0.2.1/src/formula.rs +653 -0
  78. {lme_python-0.1.9 → lme_python-0.2.1}/src/glmm_math.rs +74 -36
  79. {lme_python-0.1.9 → lme_python-0.2.1}/src/intercept_blocked.rs +643 -58
  80. {lme_python-0.1.9 → lme_python-0.2.1}/src/kenward_roger.rs +48 -20
  81. {lme_python-0.1.9 → lme_python-0.2.1}/src/lib.rs +419 -157
  82. {lme_python-0.1.9 → lme_python-0.2.1}/src/math.rs +782 -57
  83. {lme_python-0.1.9 → lme_python-0.2.1}/src/model_matrix.rs +709 -110
  84. {lme_python-0.1.9 → lme_python-0.2.1}/src/nlmm/fit.rs +178 -33
  85. {lme_python-0.1.9 → lme_python-0.2.1}/src/nlmm/formula.rs +57 -4
  86. {lme_python-0.1.9 → lme_python-0.2.1}/src/nlmm/mean.rs +11 -0
  87. {lme_python-0.1.9 → lme_python-0.2.1}/src/nlmm/mean_fn.rs +31 -1
  88. {lme_python-0.1.9 → lme_python-0.2.1}/src/nlmm/mod.rs +20 -3
  89. {lme_python-0.1.9 → lme_python-0.2.1}/src/nlmm/self_start.rs +162 -2
  90. lme_python-0.2.1/src/nlmm/ssasympoff.rs +46 -0
  91. lme_python-0.2.1/src/nlmm/ssasymporig.rs +43 -0
  92. lme_python-0.2.1/src/nlmm/ssbiexp.rs +49 -0
  93. lme_python-0.2.1/src/nlmm/ssfpl.rs +50 -0
  94. lme_python-0.2.1/src/nlmm/sspower.rs +45 -0
  95. lme_python-0.2.1/src/nlmm/ssweibull.rs +53 -0
  96. {lme_python-0.1.9 → lme_python-0.2.1}/src/optimizer.rs +97 -13
  97. {lme_python-0.1.9 → lme_python-0.2.1}/src/perf_diag.rs +2 -1
  98. lme_python-0.2.1/src/profile_ci.rs +473 -0
  99. {lme_python-0.1.9 → lme_python-0.2.1}/src/robust.rs +1 -1
  100. {lme_python-0.1.9 → lme_python-0.2.1}/src/satterthwaite.rs +1 -0
  101. lme_python-0.2.1/src/simulate.rs +237 -0
  102. lme_python-0.2.1/tests/ci_consolidated.rs +102 -0
  103. lme_python-0.2.1/tests/data/dyestuff_intercept_reml.json +17 -0
  104. lme_python-0.2.1/tests/data/glmm_binomial_agq.json +9 -0
  105. lme_python-0.2.1/tests/data/glmm_binomial_cloglog.json +19 -0
  106. lme_python-0.2.1/tests/data/glmm_gamma_dyestuff.json +15 -0
  107. {lme_python-0.1.9 → lme_python-0.2.1}/tests/data/golden_parity_manifest.json +309 -0
  108. lme_python-0.2.1/tests/data/sleepstudy_confint_profile.json +11 -0
  109. lme_python-0.2.1/tests/data/ssasympoff_nlmer.json +10 -0
  110. lme_python-0.2.1/tests/data/ssasympoff_synthetic.csv +61 -0
  111. lme_python-0.2.1/tests/data/ssasymporig_nlmer.json +10 -0
  112. lme_python-0.2.1/tests/data/ssasymporig_synthetic.csv +61 -0
  113. lme_python-0.2.1/tests/data/ssbiexp_nlmer.json +10 -0
  114. lme_python-0.2.1/tests/data/ssbiexp_synthetic.csv +97 -0
  115. lme_python-0.2.1/tests/data/ssfpl_nlmer.json +10 -0
  116. lme_python-0.2.1/tests/data/ssfpl_synthetic.csv +61 -0
  117. lme_python-0.2.1/tests/data/sspower_nlmer.json +10 -0
  118. lme_python-0.2.1/tests/data/sspower_synthetic.csv +61 -0
  119. lme_python-0.2.1/tests/data/ssweibull_nlmer.json +10 -0
  120. lme_python-0.2.1/tests/data/ssweibull_synthetic.csv +109 -0
  121. lme_python-0.2.1/tests/generate_nlmm_fixtures.R +343 -0
  122. {lme_python-0.1.9 → lme_python-0.2.1}/tests/generate_test_data.R +84 -0
  123. {lme_python-0.1.9 → lme_python-0.2.1}/tests/test_anova.rs +1 -0
  124. lme_python-0.2.1/tests/test_bootstrap.rs +316 -0
  125. lme_python-0.2.1/tests/test_confint_profile.rs +119 -0
  126. {lme_python-0.1.9 → lme_python-0.2.1}/tests/test_confint_simulate.rs +71 -0
  127. {lme_python-0.1.9 → lme_python-0.2.1}/tests/test_coverage_gaps.rs +1 -0
  128. lme_python-0.2.1/tests/test_cv.rs +223 -0
  129. {lme_python-0.1.9 → lme_python-0.2.1}/tests/test_e2e_lmer.rs +1 -1
  130. {lme_python-0.1.9 → lme_python-0.2.1}/tests/test_failure_modes.rs +14 -9
  131. lme_python-0.2.1/tests/test_formula.rs +19 -0
  132. {lme_python-0.1.9 → lme_python-0.2.1}/tests/test_formula_stress.rs +188 -28
  133. {lme_python-0.1.9 → lme_python-0.2.1}/tests/test_glmm.rs +10 -3
  134. {lme_python-0.1.9 → lme_python-0.2.1}/tests/test_golden_parity.rs +1 -4
  135. {lme_python-0.1.9 → lme_python-0.2.1}/tests/test_intercept_only.rs +4 -1
  136. lme_python-0.2.1/tests/test_nlmm_bounds.rs +153 -0
  137. {lme_python-0.1.9 → lme_python-0.2.1}/tests/test_nlmm_orange.rs +2 -2
  138. lme_python-0.2.1/tests/test_nlmm_ss_new_means.rs +132 -0
  139. lme_python-0.2.1/tests/test_nlmm_ssasymp_off_orig.rs +76 -0
  140. lme_python-0.2.1/tests/test_nlmm_sspower.rs +99 -0
  141. {lme_python-0.1.9 → lme_python-0.2.1}/tests/test_statistical_identities.rs +1 -1
  142. lme_python-0.1.9/.github/workflows/audit.yml +0 -55
  143. lme_python-0.1.9/.github/workflows/ci.yml +0 -225
  144. lme_python-0.1.9/.github/workflows/crate-publish-dry-run.yml +0 -28
  145. lme_python-0.1.9/.github/workflows/python-release.yml +0 -132
  146. lme_python-0.1.9/AGENTS.md +0 -192
  147. lme_python-0.1.9/RELEASING.md +0 -247
  148. lme_python-0.1.9/REPO_COMPLETION_BY_AREA.md +0 -102
  149. lme_python-0.1.9/scripts/ast_explorations/test_fiasto.rs +0 -6
  150. lme_python-0.1.9/scripts/ast_explorations/test_fiasto_offset.rs +0 -6
  151. lme_python-0.1.9/src/formula.rs +0 -372
  152. lme_python-0.1.9/tests/generate_nlmm_fixtures.R +0 -65
  153. lme_python-0.1.9/tests/test_formula.rs +0 -11
  154. {lme_python-0.1.9 → lme_python-0.2.1}/.JuliaFormatter.toml +0 -0
  155. {lme_python-0.1.9 → lme_python-0.2.1}/.gitignore +0 -0
  156. {lme_python-0.1.9 → lme_python-0.2.1}/LICENSE +0 -0
  157. {lme_python-0.1.9 → lme_python-0.2.1}/benches/bench_load_production.rs +0 -0
  158. {lme_python-0.1.9 → lme_python-0.2.1}/benchmarks/fair-rust-julia-reference-2026-07-04.json +0 -0
  159. {lme_python-0.1.9 → lme_python-0.2.1}/benchmarks/fair-rust-julia-reference-2026-07-06.json +0 -0
  160. {lme_python-0.1.9 → lme_python-0.2.1}/comparisons/bench_fair_julia_perf.jl +0 -0
  161. {lme_python-0.1.9 → lme_python-0.2.1}/comparisons/categorical_anova.R +0 -0
  162. {lme_python-0.1.9 → lme_python-0.2.1}/comparisons/categorical_anova.jl +0 -0
  163. {lme_python-0.1.9 → lme_python-0.2.1}/comparisons/categorical_anova.py +0 -0
  164. {lme_python-0.1.9 → lme_python-0.2.1}/comparisons/categorical_anova.rs +0 -0
  165. {lme_python-0.1.9 → lme_python-0.2.1}/comparisons/comparison_chart.png +0 -0
  166. {lme_python-0.1.9 → lme_python-0.2.1}/comparisons/glmm_cbpp.R +0 -0
  167. {lme_python-0.1.9 → lme_python-0.2.1}/comparisons/glmm_cbpp.jl +0 -0
  168. {lme_python-0.1.9 → lme_python-0.2.1}/comparisons/glmm_cbpp.py +0 -0
  169. {lme_python-0.1.9 → lme_python-0.2.1}/comparisons/glmm_cbpp.rs +0 -0
  170. {lme_python-0.1.9 → lme_python-0.2.1}/comparisons/glmm_gaussian.R +0 -0
  171. {lme_python-0.1.9 → lme_python-0.2.1}/comparisons/glmm_gaussian.jl +0 -0
  172. {lme_python-0.1.9 → lme_python-0.2.1}/comparisons/glmm_gaussian.py +0 -0
  173. {lme_python-0.1.9 → lme_python-0.2.1}/comparisons/glmm_gaussian.rs +0 -0
  174. {lme_python-0.1.9 → lme_python-0.2.1}/comparisons/glmm_grouseticks.R +0 -0
  175. {lme_python-0.1.9 → lme_python-0.2.1}/comparisons/glmm_grouseticks.jl +0 -0
  176. {lme_python-0.1.9 → lme_python-0.2.1}/comparisons/glmm_grouseticks.py +0 -0
  177. {lme_python-0.1.9 → lme_python-0.2.1}/comparisons/glmm_grouseticks.rs +0 -0
  178. {lme_python-0.1.9 → lme_python-0.2.1}/comparisons/lmer_weighted.R +0 -0
  179. {lme_python-0.1.9 → lme_python-0.2.1}/comparisons/lmer_weighted.jl +0 -0
  180. {lme_python-0.1.9 → lme_python-0.2.1}/comparisons/lmer_weighted.py +0 -0
  181. {lme_python-0.1.9 → lme_python-0.2.1}/comparisons/lmer_weighted.rs +0 -0
  182. {lme_python-0.1.9 → lme_python-0.2.1}/comparisons/lmm_dyestuff.R +0 -0
  183. {lme_python-0.1.9 → lme_python-0.2.1}/comparisons/lmm_dyestuff.jl +0 -0
  184. {lme_python-0.1.9 → lme_python-0.2.1}/comparisons/lmm_dyestuff.py +0 -0
  185. {lme_python-0.1.9 → lme_python-0.2.1}/comparisons/lmm_dyestuff.rs +0 -0
  186. {lme_python-0.1.9 → lme_python-0.2.1}/comparisons/lmm_pastes.R +0 -0
  187. {lme_python-0.1.9 → lme_python-0.2.1}/comparisons/lmm_pastes.jl +0 -0
  188. {lme_python-0.1.9 → lme_python-0.2.1}/comparisons/lmm_pastes.py +0 -0
  189. {lme_python-0.1.9 → lme_python-0.2.1}/comparisons/lmm_pastes.rs +0 -0
  190. {lme_python-0.1.9 → lme_python-0.2.1}/comparisons/lmm_penicillin.R +0 -0
  191. {lme_python-0.1.9 → lme_python-0.2.1}/comparisons/lmm_penicillin.jl +0 -0
  192. {lme_python-0.1.9 → lme_python-0.2.1}/comparisons/lmm_penicillin.py +0 -0
  193. {lme_python-0.1.9 → lme_python-0.2.1}/comparisons/lmm_penicillin.rs +0 -0
  194. {lme_python-0.1.9 → lme_python-0.2.1}/comparisons/parity/glmm_offset.R +0 -0
  195. {lme_python-0.1.9 → lme_python-0.2.1}/comparisons/parity/glmm_offset.jl +0 -0
  196. {lme_python-0.1.9 → lme_python-0.2.1}/comparisons/parity/glmm_probit.R +0 -0
  197. {lme_python-0.1.9 → lme_python-0.2.1}/comparisons/parity/glmm_probit.jl +0 -0
  198. {lme_python-0.1.9 → lme_python-0.2.1}/comparisons/parity/glmm_weighted.R +0 -0
  199. {lme_python-0.1.9 → lme_python-0.2.1}/comparisons/parity/glmm_weighted.jl +0 -0
  200. {lme_python-0.1.9 → lme_python-0.2.1}/comparisons/parity/parity_r_setup.R +0 -0
  201. {lme_python-0.1.9 → lme_python-0.2.1}/comparisons/parity/sleepstudy_offset.R +0 -0
  202. {lme_python-0.1.9 → lme_python-0.2.1}/comparisons/parity/sleepstudy_offset.jl +0 -0
  203. {lme_python-0.1.9 → lme_python-0.2.1}/comparisons/r_setup.R +0 -0
  204. {lme_python-0.1.9 → lme_python-0.2.1}/comparisons/sleepstudy.R +0 -0
  205. {lme_python-0.1.9 → lme_python-0.2.1}/comparisons/sleepstudy.jl +0 -0
  206. {lme_python-0.1.9 → lme_python-0.2.1}/comparisons/sleepstudy.py +0 -0
  207. {lme_python-0.1.9 → lme_python-0.2.1}/comparisons/sleepstudy.rs +0 -0
  208. {lme_python-0.1.9 → lme_python-0.2.1}/comparisons/sleepstudy_ml.R +0 -0
  209. {lme_python-0.1.9 → lme_python-0.2.1}/comparisons/sleepstudy_ml.jl +0 -0
  210. {lme_python-0.1.9 → lme_python-0.2.1}/comparisons/sleepstudy_ml.py +0 -0
  211. {lme_python-0.1.9 → lme_python-0.2.1}/comparisons/sleepstudy_ml.rs +0 -0
  212. {lme_python-0.1.9 → lme_python-0.2.1}/docs/benchmarks/app.js +0 -0
  213. {lme_python-0.1.9 → lme_python-0.2.1}/docs/benchmarks/index.html +0 -0
  214. {lme_python-0.1.9 → lme_python-0.2.1}/docs/benchmarks/styles.css +0 -0
  215. {lme_python-0.1.9 → lme_python-0.2.1}/docs/index.html +0 -0
  216. {lme_python-0.1.9 → lme_python-0.2.1}/lefthook.yml +0 -0
  217. {lme_python-0.1.9 → lme_python-0.2.1}/mise.toml +0 -0
  218. {lme_python-0.1.9 → lme_python-0.2.1}/pyproject.toml +0 -0
  219. {lme_python-0.1.9 → lme_python-0.2.1}/python/examples/glmer_cbpp.py +0 -0
  220. {lme_python-0.1.9 → lme_python-0.2.1}/python/examples/glmer_grouseticks.py +0 -0
  221. {lme_python-0.1.9 → lme_python-0.2.1}/python/examples/lm_basics.py +0 -0
  222. {lme_python-0.1.9 → lme_python-0.2.1}/python/examples/lmer_sleepstudy.py +0 -0
  223. {lme_python-0.1.9 → lme_python-0.2.1}/python/examples/model_comparison.py +0 -0
  224. {lme_python-0.1.9 → lme_python-0.2.1}/python/examples/plotting_demo/.gitignore +0 -0
  225. {lme_python-0.1.9 → lme_python-0.2.1}/python/examples/plotting_demo/README.md +0 -0
  226. {lme_python-0.1.9 → lme_python-0.2.1}/python/examples/plotting_demo/compare_plots.py +0 -0
  227. {lme_python-0.1.9 → lme_python-0.2.1}/python/examples/plotting_demo/figure_specs.py +0 -0
  228. {lme_python-0.1.9 → lme_python-0.2.1}/python/examples/plotting_demo/find_rscript.py +0 -0
  229. {lme_python-0.1.9 → lme_python-0.2.1}/python/examples/plotting_demo/numeric_overlay.py +0 -0
  230. {lme_python-0.1.9 → lme_python-0.2.1}/python/examples/plotting_demo/paths.py +0 -0
  231. {lme_python-0.1.9 → lme_python-0.2.1}/python/examples/plotting_demo/plot_demo.py +0 -0
  232. {lme_python-0.1.9 → lme_python-0.2.1}/python/examples/plotting_demo/plot_r.R +0 -0
  233. {lme_python-0.1.9 → lme_python-0.2.1}/python/examples/plotting_demo/run_all.py +0 -0
  234. {lme_python-0.1.9 → lme_python-0.2.1}/python/examples/verification_project/README.md +0 -0
  235. {lme_python-0.1.9 → lme_python-0.2.1}/python/examples/verification_project/conftest.py +0 -0
  236. {lme_python-0.1.9 → lme_python-0.2.1}/python/examples/verification_project/parity.py +0 -0
  237. {lme_python-0.1.9 → lme_python-0.2.1}/python/examples/verification_project/paths.py +0 -0
  238. {lme_python-0.1.9 → lme_python-0.2.1}/python/examples/verification_project/run.py +0 -0
  239. {lme_python-0.1.9 → lme_python-0.2.1}/python/examples/verification_project/test_parity.py +0 -0
  240. {lme_python-0.1.9 → lme_python-0.2.1}/python/tests/test_api_parity.py +0 -0
  241. {lme_python-0.1.9 → lme_python-0.2.1}/python/tests/test_basic.py +0 -0
  242. {lme_python-0.1.9 → lme_python-0.2.1}/python/tests/test_dataframe_inputs.py +0 -0
  243. {lme_python-0.1.9 → lme_python-0.2.1}/python/uv.lock +0 -0
  244. {lme_python-0.1.9 → lme_python-0.2.1}/scripts/build_benchmark_site.py +0 -0
  245. {lme_python-0.1.9 → lme_python-0.2.1}/scripts/ci/julia_format.jl +0 -0
  246. {lme_python-0.1.9 → lme_python-0.2.1}/scripts/ci/r_format.R +0 -0
  247. {lme_python-0.1.9 → lme_python-0.2.1}/scripts/ci/run.sh +0 -0
  248. {lme_python-0.1.9 → lme_python-0.2.1}/scripts/dump_dyestuff.R +0 -0
  249. {lme_python-0.1.9 → lme_python-0.2.1}/scripts/dump_pastes.R +0 -0
  250. {lme_python-0.1.9 → lme_python-0.2.1}/scripts/local_ci.ps1 +0 -0
  251. {lme_python-0.1.9 → lme_python-0.2.1}/scripts/local_ci.sh +0 -0
  252. {lme_python-0.1.9 → lme_python-0.2.1}/scripts/make_penicillin_csv.py +0 -0
  253. {lme_python-0.1.9 → lme_python-0.2.1}/scripts/plot_comparisons.py +0 -0
  254. {lme_python-0.1.9 → lme_python-0.2.1}/scripts/run_cross_language_benchmarks.py +0 -0
  255. {lme_python-0.1.9 → lme_python-0.2.1}/scripts/run_perf_breakdown.py +0 -0
  256. {lme_python-0.1.9 → lme_python-0.2.1}/scripts/sync_github_repo_metadata.py +0 -0
  257. {lme_python-0.1.9 → lme_python-0.2.1}/scripts/verify_cross_language_parity.py +0 -0
  258. {lme_python-0.1.9 → lme_python-0.2.1}/src/anova.rs +0 -0
  259. {lme_python-0.1.9 → lme_python-0.2.1}/src/anova_contrasts.rs +0 -0
  260. {lme_python-0.1.9 → lme_python-0.2.1}/src/contrast.rs +0 -0
  261. {lme_python-0.1.9 → lme_python-0.2.1}/src/ddf.rs +0 -0
  262. {lme_python-0.1.9 → lme_python-0.2.1}/src/family.rs +0 -0
  263. {lme_python-0.1.9 → lme_python-0.2.1}/src/kr_modcomp.rs +0 -0
  264. {lme_python-0.1.9 → lme_python-0.2.1}/src/kr_vcov_adj.rs +0 -0
  265. {lme_python-0.1.9 → lme_python-0.2.1}/src/nlmm/predict.rs +0 -0
  266. {lme_python-0.1.9 → lme_python-0.2.1}/src/nlmm/re_cov.rs +0 -0
  267. {lme_python-0.1.9 → lme_python-0.2.1}/src/nlmm/ssasymp.rs +0 -0
  268. {lme_python-0.1.9 → lme_python-0.2.1}/src/nlmm/ssgompertz.rs +0 -0
  269. {lme_python-0.1.9 → lme_python-0.2.1}/src/nlmm/sslogis.rs +0 -0
  270. {lme_python-0.1.9 → lme_python-0.2.1}/src/nlmm/ssmicmen.rs +0 -0
  271. {lme_python-0.1.9 → lme_python-0.2.1}/src/quadrature.rs +0 -0
  272. {lme_python-0.1.9 → lme_python-0.2.1}/tests/categorical_anova_test.rs +0 -0
  273. {lme_python-0.1.9 → lme_python-0.2.1}/tests/data/cbpp_binary.csv +0 -0
  274. {lme_python-0.1.9 → lme_python-0.2.1}/tests/data/cbpp_binary_weighted.csv +0 -0
  275. {lme_python-0.1.9 → lme_python-0.2.1}/tests/data/dyestuff.csv +0 -0
  276. {lme_python-0.1.9 → lme_python-0.2.1}/tests/data/glmm_binomial.json +0 -0
  277. {lme_python-0.1.9 → lme_python-0.2.1}/tests/data/glmm_binomial_probit.json +0 -0
  278. {lme_python-0.1.9 → lme_python-0.2.1}/tests/data/glmm_binomial_weighted.json +0 -0
  279. {lme_python-0.1.9 → lme_python-0.2.1}/tests/data/glmm_poisson.json +0 -0
  280. {lme_python-0.1.9 → lme_python-0.2.1}/tests/data/glmm_poisson_offset.json +0 -0
  281. {lme_python-0.1.9 → lme_python-0.2.1}/tests/data/grouseticks.csv +0 -0
  282. {lme_python-0.1.9 → lme_python-0.2.1}/tests/data/intercept_only.json +0 -0
  283. {lme_python-0.1.9 → lme_python-0.2.1}/tests/data/mock_crossed.json +0 -0
  284. {lme_python-0.1.9 → lme_python-0.2.1}/tests/data/mock_ml.json +0 -0
  285. {lme_python-0.1.9 → lme_python-0.2.1}/tests/data/orange.csv +0 -0
  286. {lme_python-0.1.9 → lme_python-0.2.1}/tests/data/orange_nlmer.json +0 -0
  287. {lme_python-0.1.9 → lme_python-0.2.1}/tests/data/pastes.csv +0 -0
  288. {lme_python-0.1.9 → lme_python-0.2.1}/tests/data/pastes_cask_reml.json +0 -0
  289. {lme_python-0.1.9 → lme_python-0.2.1}/tests/data/penicillin.csv +0 -0
  290. {lme_python-0.1.9 → lme_python-0.2.1}/tests/data/penicillin.json +0 -0
  291. {lme_python-0.1.9 → lme_python-0.2.1}/tests/data/random_slopes.json +0 -0
  292. {lme_python-0.1.9 → lme_python-0.2.1}/tests/data/sleepstudy.csv +0 -0
  293. {lme_python-0.1.9 → lme_python-0.2.1}/tests/data/sleepstudy_offset_reml.json +0 -0
  294. {lme_python-0.1.9 → lme_python-0.2.1}/tests/data/ssasymp_synthetic.csv +0 -0
  295. {lme_python-0.1.9 → lme_python-0.2.1}/tests/data/ssfol_nlmer.json +0 -0
  296. {lme_python-0.1.9 → lme_python-0.2.1}/tests/data/ssgompertz_nlmer.json +0 -0
  297. {lme_python-0.1.9 → lme_python-0.2.1}/tests/data/ssgompertz_synthetic.csv +0 -0
  298. {lme_python-0.1.9 → lme_python-0.2.1}/tests/data/ssmicmen_nlmer.json +0 -0
  299. {lme_python-0.1.9 → lme_python-0.2.1}/tests/data/ssmicmen_synthetic.csv +0 -0
  300. {lme_python-0.1.9 → lme_python-0.2.1}/tests/gen_nlmm_extras.R +0 -0
  301. {lme_python-0.1.9 → lme_python-0.2.1}/tests/generate_mock_data.py +0 -0
  302. {lme_python-0.1.9 → lme_python-0.2.1}/tests/test_anova_types.rs +0 -0
  303. {lme_python-0.1.9 → lme_python-0.2.1}/tests/test_conditional_real.rs +0 -0
  304. {lme_python-0.1.9 → lme_python-0.2.1}/tests/test_contrast.rs +0 -0
  305. {lme_python-0.1.9 → lme_python-0.2.1}/tests/test_coverage_edge_cases.rs +0 -0
  306. {lme_python-0.1.9 → lme_python-0.2.1}/tests/test_crossed_mock.rs +0 -0
  307. {lme_python-0.1.9 → lme_python-0.2.1}/tests/test_edge_cases.rs +0 -0
  308. {lme_python-0.1.9 → lme_python-0.2.1}/tests/test_errors.rs +0 -0
  309. {lme_python-0.1.9 → lme_python-0.2.1}/tests/test_gaps.rs +0 -0
  310. {lme_python-0.1.9 → lme_python-0.2.1}/tests/test_glmm_links.rs +0 -0
  311. {lme_python-0.1.9 → lme_python-0.2.1}/tests/test_glmm_offset_grouseticks.rs +0 -0
  312. {lme_python-0.1.9 → lme_python-0.2.1}/tests/test_glmm_weighted.rs +0 -0
  313. {lme_python-0.1.9 → lme_python-0.2.1}/tests/test_kenward_roger.rs +0 -0
  314. {lme_python-0.1.9 → lme_python-0.2.1}/tests/test_kr_modcomp_pastes.rs +0 -0
  315. {lme_python-0.1.9 → lme_python-0.2.1}/tests/test_ml_optimization.rs +0 -0
  316. {lme_python-0.1.9 → lme_python-0.2.1}/tests/test_nlmm_agq.rs +0 -0
  317. {lme_python-0.1.9 → lme_python-0.2.1}/tests/test_nlmm_custom_mean.rs +0 -0
  318. {lme_python-0.1.9 → lme_python-0.2.1}/tests/test_nlmm_orange_multi_re.rs +0 -0
  319. {lme_python-0.1.9 → lme_python-0.2.1}/tests/test_nlmm_self_start.rs +0 -0
  320. {lme_python-0.1.9 → lme_python-0.2.1}/tests/test_nlmm_ssasymp.rs +0 -0
  321. {lme_python-0.1.9 → lme_python-0.2.1}/tests/test_nlmm_ssfol.rs +0 -0
  322. {lme_python-0.1.9 → lme_python-0.2.1}/tests/test_nlmm_ssmicmen.rs +0 -0
  323. {lme_python-0.1.9 → lme_python-0.2.1}/tests/test_no_intercept.rs +0 -0
  324. {lme_python-0.1.9 → lme_python-0.2.1}/tests/test_numerical_parity.rs +0 -0
  325. {lme_python-0.1.9 → lme_python-0.2.1}/tests/test_predict.rs +0 -0
  326. {lme_python-0.1.9 → lme_python-0.2.1}/tests/test_production_load.rs +0 -0
  327. {lme_python-0.1.9 → lme_python-0.2.1}/tests/test_random_slopes.rs +0 -0
  328. {lme_python-0.1.9 → lme_python-0.2.1}/tests/test_robust.rs +0 -0
  329. {lme_python-0.1.9 → lme_python-0.2.1}/tests/test_sandwich_math.R +0 -0
  330. {lme_python-0.1.9 → lme_python-0.2.1}/tests/test_satterthwaite.rs +0 -0
@@ -0,0 +1,10 @@
1
+ version: 2
2
+ updates:
3
+ - package-ecosystem: github-actions
4
+ directory: /
5
+ schedule:
6
+ interval: weekly
7
+ groups:
8
+ github-actions:
9
+ patterns:
10
+ - "*"
@@ -0,0 +1,62 @@
1
+ name: Security audit
2
+
3
+ # Release CI calls this workflow as a required publication gate.
4
+ # A weekly schedule and workflow_dispatch provide continuous/on-demand audits.
5
+
6
+ on:
7
+ workflow_call:
8
+ workflow_dispatch:
9
+ schedule:
10
+ - cron: "17 4 * * 1"
11
+
12
+ permissions:
13
+ contents: read
14
+
15
+ concurrency:
16
+ group: audit-${{ github.workflow }}-${{ github.ref }}
17
+ cancel-in-progress: true
18
+
19
+ jobs:
20
+ audit:
21
+ name: cargo audit
22
+ runs-on: ubuntu-latest
23
+ steps:
24
+ - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
25
+
26
+ - uses: dtolnay/rust-toolchain@4cda84d5c5c54efe2404f9d843567869ab1699d4 # stable
27
+ with:
28
+ toolchain: stable
29
+
30
+ - name: Install cargo-audit
31
+ uses: taiki-e/install-action@c44f6b046f1c29ae5918b1e0bfdbb2f1813836fd # v2
32
+ with:
33
+ tool: cargo-audit@0.22.1
34
+
35
+ - name: Run cargo audit (root)
36
+ # paste is required by argmin 0.11; RUSTSEC-2024-0436 is informational
37
+ # and has no patched argmin release. Deny every other warning.
38
+ run: cargo audit --deny warnings --ignore RUSTSEC-2024-0436
39
+
40
+ - name: Run cargo audit (python/)
41
+ working-directory: python
42
+ run: cargo audit --deny warnings --ignore RUSTSEC-2024-0436
43
+
44
+ pip-audit:
45
+ name: pip-audit (uv.lock)
46
+ runs-on: ubuntu-latest
47
+ steps:
48
+ - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
49
+
50
+ - name: Set up uv
51
+ uses: astral-sh/setup-uv@c771a70e6277c0a99b617c7a806ffedaca235ff9 # v9.0.0
52
+ with:
53
+ python-version: "3.11"
54
+ enable-cache: true
55
+ cache-dependency-glob: "python/uv.lock"
56
+
57
+ - name: pip-audit
58
+ working-directory: python
59
+ run: |
60
+ set -euo pipefail
61
+ uv sync --extra dev --no-install-project
62
+ uv run --no-sync pip-audit
@@ -29,15 +29,17 @@ jobs:
29
29
  name: Criterion Benchmarks
30
30
  runs-on: ubuntu-latest
31
31
  steps:
32
- - uses: actions/checkout@v6
32
+ - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
33
33
 
34
- - uses: dtolnay/rust-toolchain@stable
34
+ - uses: dtolnay/rust-toolchain@4cda84d5c5c54efe2404f9d843567869ab1699d4 # stable
35
+ with:
36
+ toolchain: stable
35
37
 
36
38
  - name: Install OpenBLAS
37
39
  run: sudo apt-get update && sudo apt-get install -y libopenblas-dev
38
40
 
39
41
  - name: Cache cargo registry and build outputs
40
- uses: actions/cache@v5
42
+ uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0
41
43
  with:
42
44
  path: |
43
45
  ~/.cargo/registry
@@ -55,7 +57,7 @@ jobs:
55
57
  tar -czf "benchmark-results/criterion-${{ github.sha }}.tar.gz" target/criterion
56
58
 
57
59
  - name: Upload Criterion artifact
58
- uses: actions/upload-artifact@v7
60
+ uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
59
61
  with:
60
62
  name: criterion-${{ github.sha }}
61
63
  path: benchmark-results/criterion-${{ github.sha }}.tar.gz
@@ -82,11 +84,13 @@ jobs:
82
84
  BENCH_REPEATS: ${{ github.event_name == 'workflow_dispatch' && inputs.repeats || '3' }}
83
85
  R_LIBS_USER: ${{ github.workspace }}/.r-lib
84
86
  steps:
85
- - uses: actions/checkout@v6
87
+ - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
86
88
 
87
- - uses: dtolnay/rust-toolchain@stable
89
+ - uses: dtolnay/rust-toolchain@4cda84d5c5c54efe2404f9d843567869ab1699d4 # stable
90
+ with:
91
+ toolchain: stable
88
92
 
89
- - uses: actions/setup-python@v6
93
+ - uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0
90
94
  with:
91
95
  python-version: "3.11"
92
96
 
@@ -101,7 +105,7 @@ jobs:
101
105
  julia --version
102
106
 
103
107
  - name: Cache cargo registry and build outputs
104
- uses: actions/cache@v5
108
+ uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0
105
109
  with:
106
110
  path: |
107
111
  ~/.cargo/registry
@@ -157,9 +161,10 @@ jobs:
157
161
 
158
162
  - name: Upload cross-language artifact
159
163
  if: always()
160
- uses: actions/upload-artifact@v7
164
+ uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
161
165
  with:
162
166
  name: cross-language-${{ github.sha }}
167
+ if-no-files-found: ignore
163
168
  path: |
164
169
  benchmark-results/cross-language-${{ github.sha }}.json
165
170
  benchmark-results/fair-rust-julia-${{ github.sha }}.json
@@ -176,9 +181,13 @@ jobs:
176
181
  gh release create "${GITHUB_REF_NAME}" --title "${GITHUB_REF_NAME}"
177
182
  fi
178
183
  }
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
184
+ cross_json="benchmark-results/cross-language-${{ github.sha }}.json"
185
+ fair_json="benchmark-results/fair-rust-julia-${{ github.sha }}.json"
186
+ if [ -f "$cross_json" ]; then
187
+ gh release upload "${GITHUB_REF_NAME}" "$cross_json" --clobber
188
+ fi
189
+ if [ -f "$fair_json" ]; then
190
+ gh release upload "${GITHUB_REF_NAME}" "$fair_json" --clobber
182
191
  fi
183
192
 
184
193
  - name: Fail if cross-language benchmarks failed
@@ -0,0 +1,115 @@
1
+ name: Prime Rust caches
2
+
3
+ # PR caches are scoped to a single pull request. Keep trusted default-branch
4
+ # dependency caches warm so new PRs do not start by rebuilding Polars and BLAS.
5
+
6
+ on:
7
+ push:
8
+ branches:
9
+ - master
10
+ paths:
11
+ - "Cargo.toml"
12
+ - "Cargo.lock"
13
+ - "python/Cargo.toml"
14
+ - "python/Cargo.lock"
15
+ - "rust-toolchain"
16
+ - "rust-toolchain.toml"
17
+ - ".cargo/**"
18
+ - ".github/workflows/ci.yml"
19
+ - ".github/workflows/cache-prime.yml"
20
+ schedule:
21
+ - cron: "17 3 * * 1"
22
+ workflow_dispatch:
23
+
24
+ permissions:
25
+ contents: read
26
+
27
+ concurrency:
28
+ group: cache-prime-${{ github.ref }}
29
+ cancel-in-progress: true
30
+
31
+ env:
32
+ CARGO_TERM_COLOR: always
33
+ CARGO_INCREMENTAL: "0"
34
+ CARGO_PROFILE_DEV_DEBUG: "0"
35
+ CARGO_PROFILE_TEST_DEBUG: "0"
36
+
37
+ jobs:
38
+ rust-dependencies:
39
+ name: Rust dependencies (${{ matrix.os }})
40
+ runs-on: ${{ matrix.os }}
41
+ strategy:
42
+ fail-fast: false
43
+ matrix:
44
+ os: [ubuntu-latest, windows-latest, macos-latest]
45
+ steps:
46
+ - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
47
+ - uses: dtolnay/rust-toolchain@4cda84d5c5c54efe2404f9d843567869ab1699d4 # stable
48
+ with:
49
+ toolchain: stable
50
+ - name: Install OpenBLAS (Ubuntu)
51
+ if: matrix.os == 'ubuntu-latest'
52
+ run: sudo apt-get update && sudo apt-get install -y libopenblas-dev
53
+ - name: Set OpenBLAS target (macOS)
54
+ if: matrix.os == 'macos-latest'
55
+ run: echo "OPENBLAS_TARGET=ARMV8" >> "$GITHUB_ENV"
56
+ - name: Cache Rust dependencies
57
+ uses: Swatinem/rust-cache@e18b497796c12c097a38f9edb9d0641fb99eee32 # v2
58
+ with:
59
+ shared-key: ci-v2-${{ runner.os }}-rust-test
60
+ cache-workspace-crates: ${{ runner.os != 'Linux' }}
61
+ - name: Compile canonical test dependencies
62
+ if: matrix.os == 'ubuntu-latest'
63
+ run: cargo test --locked --no-run
64
+ - name: Compile consolidated test dependencies
65
+ if: matrix.os != 'ubuntu-latest'
66
+ run: python scripts/ci/lme_ci.py consolidated-test --no-run
67
+
68
+ production-dependencies:
69
+ name: Production-load dependencies (ubuntu)
70
+ runs-on: ubuntu-latest
71
+ steps:
72
+ - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
73
+ - uses: dtolnay/rust-toolchain@4cda84d5c5c54efe2404f9d843567869ab1699d4 # stable
74
+ with:
75
+ toolchain: stable
76
+ - name: Install OpenBLAS
77
+ run: sudo apt-get update && sudo apt-get install -y libopenblas-dev
78
+ - name: Cache production-load Rust dependencies
79
+ uses: Swatinem/rust-cache@e18b497796c12c097a38f9edb9d0641fb99eee32 # v2
80
+ with:
81
+ shared-key: ci-v2-${{ runner.os }}-rust-release
82
+ cache-workspace-crates: true
83
+ - name: Compile production-load dependencies
84
+ run: cargo test --release --locked --test test_production_load --no-run
85
+
86
+ python-dependencies:
87
+ name: Python dependencies (${{ matrix.os }})
88
+ runs-on: ${{ matrix.os }}
89
+ strategy:
90
+ fail-fast: false
91
+ matrix:
92
+ os: [ubuntu-latest, windows-latest, macos-latest]
93
+ steps:
94
+ - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
95
+ - uses: dtolnay/rust-toolchain@4cda84d5c5c54efe2404f9d843567869ab1699d4 # stable
96
+ with:
97
+ toolchain: stable
98
+ - uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0
99
+ with:
100
+ python-version: "3.11"
101
+ - name: Install OpenBLAS (Ubuntu)
102
+ if: matrix.os == 'ubuntu-latest'
103
+ run: sudo apt-get update && sudo apt-get install -y libopenblas-dev
104
+ - name: Set OpenBLAS target (macOS)
105
+ if: matrix.os == 'macos-latest'
106
+ run: echo "OPENBLAS_TARGET=ARMV8" >> "$GITHUB_ENV"
107
+ - name: Cache Python Rust dependencies
108
+ uses: Swatinem/rust-cache@e18b497796c12c097a38f9edb9d0641fb99eee32 # v2
109
+ with:
110
+ shared-key: ci-${{ runner.os }}-python
111
+ workspaces: python -> target
112
+ - name: Compile Python binding dependencies
113
+ env:
114
+ PYO3_PYTHON: python
115
+ run: cargo build --release --manifest-path python/Cargo.toml
@@ -0,0 +1,254 @@
1
+ name: CI
2
+
3
+ # Automatic runs: pull requests and v* release tags. Use workflow_dispatch for
4
+ # an intentional full check on any branch (Actions → CI → Run workflow).
5
+
6
+ on:
7
+ pull_request:
8
+ push:
9
+ tags:
10
+ - "v*"
11
+ workflow_dispatch:
12
+
13
+ permissions:
14
+ contents: read
15
+
16
+ concurrency:
17
+ group: ci-${{ github.workflow }}-${{ github.ref }}
18
+ cancel-in-progress: true
19
+
20
+ env:
21
+ CARGO_TERM_COLOR: always
22
+ CARGO_INCREMENTAL: "0"
23
+ CARGO_PROFILE_DEV_DEBUG: "0"
24
+ CARGO_PROFILE_TEST_DEBUG: "0"
25
+
26
+ jobs:
27
+ release-policy:
28
+ name: Release policy checks
29
+ runs-on: ubuntu-latest
30
+ steps:
31
+ - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
32
+ - uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0
33
+ with:
34
+ python-version: "3.11"
35
+ - name: Validate legal notices and provenance
36
+ run: python3 scripts/ci/lme_ci.py legal
37
+ - name: Validate completion score claims
38
+ run: python3 scripts/ci/lme_ci.py completion-check
39
+
40
+ security-audit:
41
+ name: Dependency security audit
42
+ permissions:
43
+ contents: read
44
+ uses: ./.github/workflows/audit.yml
45
+
46
+ rust-ubuntu:
47
+ name: Rust validation (ubuntu)
48
+ runs-on: ubuntu-latest
49
+ steps:
50
+ - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
51
+ - uses: dtolnay/rust-toolchain@4cda84d5c5c54efe2404f9d843567869ab1699d4 # stable
52
+ with:
53
+ toolchain: stable
54
+ - name: Install OpenBLAS
55
+ run: sudo apt-get update && sudo apt-get install -y libopenblas-dev
56
+ - name: Cache Rust dependencies
57
+ uses: Swatinem/rust-cache@e18b497796c12c097a38f9edb9d0641fb99eee32 # v2
58
+ with:
59
+ shared-key: ci-v2-${{ runner.os }}-rust-test
60
+ save-if: ${{ github.event_name == 'pull_request' || github.ref == 'refs/heads/master' }}
61
+ - name: rustfmt --check
62
+ id: rustfmt
63
+ continue-on-error: true
64
+ run: python3 scripts/ci/lme_ci.py fmt-check
65
+ - name: clippy
66
+ id: clippy
67
+ continue-on-error: true
68
+ run: python3 scripts/ci/lme_ci.py clippy
69
+ - name: cargo check --workspace --all-targets
70
+ id: check
71
+ continue-on-error: true
72
+ run: python3 scripts/ci/lme_ci.py check
73
+ - name: Run tests
74
+ id: tests
75
+ continue-on-error: true
76
+ run: python3 scripts/ci/lme_ci.py build-test
77
+ - name: Run doctests
78
+ id: doctests
79
+ continue-on-error: true
80
+ run: python3 scripts/ci/lme_ci.py doctest
81
+ - name: Build documentation
82
+ id: docs
83
+ continue-on-error: true
84
+ run: python3 scripts/ci/lme_ci.py doc
85
+ - name: Report Rust validation failures
86
+ if: >-
87
+ ${{ !cancelled() && (
88
+ steps.rustfmt.outcome == 'failure' ||
89
+ steps.clippy.outcome == 'failure' ||
90
+ steps.check.outcome == 'failure' ||
91
+ steps.tests.outcome == 'failure' ||
92
+ steps.doctests.outcome == 'failure' ||
93
+ steps.docs.outcome == 'failure'
94
+ ) }}
95
+ run: exit 1
96
+
97
+ test:
98
+ name: Test (${{ matrix.os }})
99
+ runs-on: ${{ matrix.os }}
100
+ strategy:
101
+ fail-fast: false
102
+ matrix:
103
+ os: [windows-latest, macos-latest]
104
+
105
+ steps:
106
+ - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
107
+
108
+ - name: Install Rust toolchain
109
+ uses: dtolnay/rust-toolchain@4cda84d5c5c54efe2404f9d843567869ab1699d4 # stable
110
+ with:
111
+ toolchain: stable
112
+
113
+ - name: Cache Rust dependencies
114
+ uses: Swatinem/rust-cache@e18b497796c12c097a38f9edb9d0641fb99eee32 # v2
115
+ with:
116
+ shared-key: ci-v2-${{ runner.os }}-rust-test
117
+ cache-workspace-crates: true
118
+ save-if: ${{ github.event_name == 'pull_request' || github.ref == 'refs/heads/master' }}
119
+
120
+ - name: Set OpenBLAS target (macOS)
121
+ if: matrix.os == 'macos-latest'
122
+ run: echo "OPENBLAS_TARGET=ARMV8" >> "$GITHUB_ENV"
123
+
124
+ - name: Run tests
125
+ run: python scripts/ci/lme_ci.py consolidated-test
126
+
127
+ production-load:
128
+ name: Production load & perf gates (ubuntu, release)
129
+ runs-on: ubuntu-latest
130
+ steps:
131
+ - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
132
+
133
+ - name: Install Rust toolchain
134
+ uses: dtolnay/rust-toolchain@4cda84d5c5c54efe2404f9d843567869ab1699d4 # stable
135
+ with:
136
+ toolchain: stable
137
+
138
+ - name: Install OpenBLAS (Ubuntu)
139
+ run: sudo apt-get update && sudo apt-get install -y libopenblas-dev
140
+
141
+ - name: Restore Rust dependencies
142
+ uses: Swatinem/rust-cache@e18b497796c12c097a38f9edb9d0641fb99eee32 # v2
143
+ with:
144
+ shared-key: ci-v2-${{ runner.os }}-rust-release
145
+ cache-workspace-crates: true
146
+ save-if: ${{ github.event_name == 'pull_request' || github.ref == 'refs/heads/master' }}
147
+
148
+ - name: Production load tests (smoke + release wall-clock gates)
149
+ run: cargo test --release --locked --verbose --test test_production_load
150
+
151
+ - name: Heavy production load tests (ignored)
152
+ if: github.event_name != 'pull_request'
153
+ run: cargo test --release --locked --verbose --test test_production_load -- --ignored --test-threads=1
154
+
155
+ python-bindings-versions:
156
+ name: Python ${{ matrix.python-version }} (ubuntu)
157
+ runs-on: ubuntu-latest
158
+ strategy:
159
+ fail-fast: false
160
+ matrix:
161
+ python-version: ["3.10", "3.11", "3.12", "3.13"]
162
+ steps:
163
+ - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
164
+ - uses: dtolnay/rust-toolchain@4cda84d5c5c54efe2404f9d843567869ab1699d4 # stable
165
+ with:
166
+ toolchain: stable
167
+ - name: Install OpenBLAS
168
+ run: sudo apt-get update && sudo apt-get install -y libopenblas-dev
169
+ - name: Cache Python Rust dependencies
170
+ uses: Swatinem/rust-cache@e18b497796c12c097a38f9edb9d0641fb99eee32 # v2
171
+ with:
172
+ shared-key: ci-${{ runner.os }}-python
173
+ workspaces: python -> target
174
+ save-if: ${{ matrix.python-version == '3.11' && (github.event_name == 'pull_request' || github.ref == 'refs/heads/master') }}
175
+ - name: Set up uv
176
+ uses: astral-sh/setup-uv@c771a70e6277c0a99b617c7a806ffedaca235ff9 # v9.0.0
177
+ with:
178
+ python-version: ${{ matrix.python-version }}
179
+ enable-cache: true
180
+ cache-dependency-glob: "python/uv.lock"
181
+
182
+ - name: Python bindings (canonical editable identity + isolated wheel)
183
+ if: matrix.python-version == '3.11'
184
+ run: python scripts/ci/lme_ci.py python --python-version ${{ matrix.python-version }}
185
+
186
+ - name: Python bindings (isolated wheel compatibility)
187
+ if: matrix.python-version != '3.11'
188
+ run: python scripts/ci/lme_ci.py python --python-version ${{ matrix.python-version }} --wheel-only
189
+
190
+ python-bindings-os:
191
+ name: Python 3.11 (${{ matrix.os }})
192
+ runs-on: ${{ matrix.os }}
193
+ strategy:
194
+ fail-fast: false
195
+ matrix:
196
+ os: [windows-latest, macos-latest]
197
+ steps:
198
+ - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
199
+ - uses: dtolnay/rust-toolchain@4cda84d5c5c54efe2404f9d843567869ab1699d4 # stable
200
+ with:
201
+ toolchain: stable
202
+ - name: Set OpenBLAS target (macOS)
203
+ if: matrix.os == 'macos-latest'
204
+ run: echo "OPENBLAS_TARGET=ARMV8" >> "$GITHUB_ENV"
205
+ - name: Cache Python Rust dependencies
206
+ uses: Swatinem/rust-cache@e18b497796c12c097a38f9edb9d0641fb99eee32 # v2
207
+ with:
208
+ shared-key: ci-${{ runner.os }}-python
209
+ workspaces: python -> target
210
+ save-if: ${{ github.event_name == 'pull_request' || github.ref == 'refs/heads/master' }}
211
+ - name: Set up uv
212
+ uses: astral-sh/setup-uv@c771a70e6277c0a99b617c7a806ffedaca235ff9 # v9.0.0
213
+ with:
214
+ python-version: "3.11"
215
+ enable-cache: true
216
+ cache-dependency-glob: "python/uv.lock"
217
+ - name: Python bindings (isolated wheel OS compatibility)
218
+ run: python scripts/ci/lme_ci.py python --python-version 3.11 --wheel-only
219
+
220
+ publish-crate:
221
+ name: Publish Rust crate after CI
222
+ if: startsWith(github.ref, 'refs/tags/v')
223
+ needs:
224
+ - release-policy
225
+ - security-audit
226
+ - rust-ubuntu
227
+ - test
228
+ - production-load
229
+ - python-bindings-versions
230
+ - python-bindings-os
231
+ permissions:
232
+ contents: read
233
+ uses: ./.github/workflows/crate-publish-dry-run.yml
234
+ with:
235
+ publish: true
236
+ secrets: inherit
237
+
238
+ publish-python:
239
+ name: Publish Python artifacts after CI
240
+ if: startsWith(github.ref, 'refs/tags/v')
241
+ needs:
242
+ - release-policy
243
+ - security-audit
244
+ - rust-ubuntu
245
+ - test
246
+ - production-load
247
+ - python-bindings-versions
248
+ - python-bindings-os
249
+ permissions:
250
+ contents: write
251
+ id-token: write
252
+ uses: ./.github/workflows/python-release.yml
253
+ with:
254
+ publish: true
@@ -0,0 +1,48 @@
1
+ name: Publish Rust crate
2
+
3
+ # CI calls this workflow after every release-tag validation job succeeds.
4
+ # Manual dispatch validates with cargo publish --dry-run and never publishes.
5
+
6
+ on:
7
+ workflow_call:
8
+ inputs:
9
+ publish:
10
+ description: Publish the validated release tag to crates.io
11
+ required: false
12
+ type: boolean
13
+ default: false
14
+ workflow_dispatch:
15
+
16
+ permissions:
17
+ contents: read
18
+
19
+ concurrency:
20
+ group: publish-crate-${{ github.workflow }}-${{ github.ref }}
21
+ cancel-in-progress: true
22
+
23
+ jobs:
24
+ publish:
25
+ name: cargo publish
26
+ runs-on: ubuntu-latest
27
+ steps:
28
+ - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
29
+
30
+ - uses: dtolnay/rust-toolchain@4cda84d5c5c54efe2404f9d843567869ab1699d4 # stable
31
+ with:
32
+ toolchain: stable
33
+
34
+ - name: Validate crate package (dry run)
35
+ run: cargo publish --dry-run --locked
36
+
37
+ - name: Publish root crate
38
+ if: inputs.publish && startsWith(github.ref, 'refs/tags/v')
39
+ env:
40
+ CARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_REGISTRY_TOKEN }}
41
+ run: |
42
+ VERSION=$(grep '^version' Cargo.toml | head -1 | sed 's/.*"\(.*\)".*/\1/')
43
+ if cargo search lme-rs --limit 1 2>/dev/null | grep -q "= \"$VERSION\""; then
44
+ echo "lme-rs $VERSION already on crates.io; skipping publish."
45
+ exit 0
46
+ fi
47
+ test -n "$CARGO_REGISTRY_TOKEN" || { echo "CARGO_REGISTRY_TOKEN repository secret is required to publish a new version" >&2; exit 1; }
48
+ cargo publish --locked
@@ -1,8 +1,17 @@
1
- # Manual libFuzzer smoke (long compile + short run). Trigger from the Actions tab.
2
- name: Fuzz (manual)
1
+ # Weekly and manually dispatched libFuzzer smoke.
2
+ name: Fuzz smoke
3
3
 
4
4
  on:
5
5
  workflow_dispatch:
6
+ schedule:
7
+ - cron: "43 3 * * 0"
8
+
9
+ permissions:
10
+ contents: read
11
+
12
+ concurrency:
13
+ group: fuzz-${{ github.workflow }}-${{ github.ref }}
14
+ cancel-in-progress: true
6
15
 
7
16
  jobs:
8
17
  libfuzzer-smoke:
@@ -13,14 +22,16 @@ jobs:
13
22
  working-directory: fuzz
14
23
 
15
24
  steps:
16
- - uses: actions/checkout@v4
25
+ - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
17
26
 
18
- - uses: dtolnay/rust-toolchain@nightly
27
+ - uses: dtolnay/rust-toolchain@4cda84d5c5c54efe2404f9d843567869ab1699d4 # nightly
28
+ with:
29
+ toolchain: nightly
19
30
 
20
31
  - name: Install cargo-fuzz
21
- run: cargo install cargo-fuzz --locked
32
+ run: cargo install cargo-fuzz@0.13.2 --locked
22
33
 
23
- - uses: Swatinem/rust-cache@v2
34
+ - uses: Swatinem/rust-cache@e18b497796c12c097a38f9edb9d0641fb99eee32 # v2
24
35
  with:
25
36
  workspaces: fuzz
26
37