lme-python 0.2.2__tar.gz → 0.2.4__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.
- lme_python-0.2.4/.github/FUNDING.yml +1 -0
- {lme_python-0.2.2 → lme_python-0.2.4}/.github/workflows/audit.yml +2 -2
- {lme_python-0.2.2 → lme_python-0.2.4}/.github/workflows/benchmarks.yml +76 -0
- {lme_python-0.2.2 → lme_python-0.2.4}/.github/workflows/cache-prime.yml +3 -3
- {lme_python-0.2.2 → lme_python-0.2.4}/.github/workflows/ci.yml +9 -7
- {lme_python-0.2.2 → lme_python-0.2.4}/.github/workflows/fuzz-smoke.yml +1 -1
- lme_python-0.2.4/.github/workflows/pages.yml +56 -0
- {lme_python-0.2.2 → lme_python-0.2.4}/.github/workflows/python-release.yml +1 -1
- lme_python-0.2.4/AGENTS.md +148 -0
- {lme_python-0.2.2 → lme_python-0.2.4}/BENCHMARKS.md +73 -29
- {lme_python-0.2.2 → lme_python-0.2.4}/BENCHMARK_COVERAGE.md +17 -9
- {lme_python-0.2.2 → lme_python-0.2.4}/CHANGELOG.md +101 -0
- {lme_python-0.2.2 → lme_python-0.2.4}/CI_PERFORMANCE.md +7 -1
- lme_python-0.2.4/CONTRIBUTING.md +235 -0
- {lme_python-0.2.2 → lme_python-0.2.4}/Cargo.lock +1 -1
- {lme_python-0.2.2 → lme_python-0.2.4}/Cargo.toml +4 -1
- {lme_python-0.2.2 → lme_python-0.2.4}/GUIDE.md +100 -41
- {lme_python-0.2.2 → lme_python-0.2.4}/OPTIMIZATION.md +88 -4
- lme_python-0.2.4/PKG-INFO +127 -0
- lme_python-0.2.4/README.md +220 -0
- lme_python-0.2.4/RELEASING.md +157 -0
- lme_python-0.2.4/REPO_COMPLETION_BY_AREA.md +132 -0
- {lme_python-0.2.2 → lme_python-0.2.4}/Taskfile.yml +15 -0
- lme_python-0.2.4/USABILITY.md +110 -0
- lme_python-0.2.4/benchmarks/fair-rust-julia-reference-2026-09-09-refactor.json +1693 -0
- lme_python-0.2.4/benchmarks/refactor-2026-09-09.json +1854 -0
- {lme_python-0.2.2 → lme_python-0.2.4}/comparisons/COMPARISONS.md +25 -4
- lme_python-0.2.4/completion_manifest.json +159 -0
- lme_python-0.2.4/docs/CALO_CALIBRATION.md +98 -0
- lme_python-0.2.4/docs/EXAMPLES.md +86 -0
- lme_python-0.2.4/docs/README.md +69 -0
- lme_python-0.2.4/docs/TROUBLESHOOTING.md +91 -0
- lme_python-0.2.4/docs/benchmarks/app.js +397 -0
- lme_python-0.2.4/docs/benchmarks/data/latest.json +834 -0
- lme_python-0.2.4/docs/benchmarks/index.html +133 -0
- {lme_python-0.2.2 → lme_python-0.2.4}/docs/benchmarks/styles.css +62 -3
- {lme_python-0.2.2 → lme_python-0.2.4}/docs/index.html +1 -1
- lme_python-0.2.4/docs/rustdoc.css +157 -0
- lme_python-0.2.4/docs/rustdoc.md +131 -0
- {lme_python-0.2.2 → lme_python-0.2.4}/lefthook.yml +4 -0
- lme_python-0.2.4/lme-rs-icon.png +0 -0
- lme_python-0.2.4/lme-rs.png +0 -0
- {lme_python-0.2.2 → lme_python-0.2.4}/python/Cargo.lock +2 -2
- {lme_python-0.2.2 → lme_python-0.2.4}/python/Cargo.toml +1 -1
- {lme_python-0.2.2 → lme_python-0.2.4}/python/PYTHON_GUIDE.md +163 -112
- lme_python-0.2.4/python/README.md +104 -0
- lme_python-0.2.4/python/examples/plotting_demo/README.md +101 -0
- lme_python-0.2.4/python/examples/verification_project/README.md +51 -0
- {lme_python-0.2.2 → lme_python-0.2.4}/python/lme_python.pyi +48 -10
- lme_python-0.2.4/python/src/controls.rs +61 -0
- lme_python-0.2.4/python/src/fitting.rs +597 -0
- lme_python-0.2.4/python/src/input.rs +107 -0
- {lme_python-0.2.2 → lme_python-0.2.4}/python/src/lib.rs +131 -727
- lme_python-0.2.4/python/tests/test_model_contracts.py +133 -0
- {lme_python-0.2.2 → lme_python-0.2.4}/python/uv.lock +4 -4
- lme_python-0.2.4/scripts/build_benchmark_site.py +508 -0
- lme_python-0.2.4/scripts/ci/README.md +55 -0
- {lme_python-0.2.2 → lme_python-0.2.4}/scripts/ci/check_completion_score.py +36 -3
- {lme_python-0.2.2 → lme_python-0.2.4}/scripts/ci/lme_ci.py +78 -2
- {lme_python-0.2.2 → lme_python-0.2.4}/scripts/explorations/README.md +5 -1
- {lme_python-0.2.2 → lme_python-0.2.4}/src/bootstrap.rs +108 -103
- {lme_python-0.2.2 → lme_python-0.2.4}/src/contrast.rs +117 -26
- {lme_python-0.2.2 → lme_python-0.2.4}/src/cv.rs +32 -86
- {lme_python-0.2.2 → lme_python-0.2.4}/src/ddf.rs +1 -1
- lme_python-0.2.4/src/display.rs +283 -0
- {lme_python-0.2.2 → lme_python-0.2.4}/src/emmeans.rs +8 -20
- lme_python-0.2.4/src/execution.rs +48 -0
- {lme_python-0.2.2 → lme_python-0.2.4}/src/formula.rs +2 -1
- {lme_python-0.2.2 → lme_python-0.2.4}/src/glmm_math.rs +149 -74
- {lme_python-0.2.2 → lme_python-0.2.4}/src/intercept_blocked.rs +144 -9
- lme_python-0.2.4/src/kenward_roger.rs +81 -0
- {lme_python-0.2.2 → lme_python-0.2.4}/src/kr_modcomp.rs +72 -77
- {lme_python-0.2.2 → lme_python-0.2.4}/src/kr_vcov_adj.rs +7 -12
- {lme_python-0.2.2 → lme_python-0.2.4}/src/lib.rs +210 -596
- {lme_python-0.2.2 → lme_python-0.2.4}/src/math.rs +99 -84
- {lme_python-0.2.2 → lme_python-0.2.4}/src/mcp.rs +33 -7
- lme_python-0.2.4/src/model.rs +240 -0
- {lme_python-0.2.2 → lme_python-0.2.4}/src/model_matrix.rs +62 -60
- lme_python-0.2.4/src/nlmm/block_solve.rs +132 -0
- {lme_python-0.2.2 → lme_python-0.2.4}/src/nlmm/fit.rs +263 -140
- {lme_python-0.2.2 → lme_python-0.2.4}/src/nlmm/mod.rs +1 -0
- lme_python-0.2.4/src/ols.rs +33 -0
- {lme_python-0.2.2 → lme_python-0.2.4}/src/optimizer.rs +138 -101
- {lme_python-0.2.2 → lme_python-0.2.4}/src/perf_diag.rs +1 -1
- lme_python-0.2.4/src/predict.rs +184 -0
- lme_python-0.2.4/src/prepared.rs +76 -0
- {lme_python-0.2.2 → lme_python-0.2.4}/src/profile_ci.rs +6 -11
- {lme_python-0.2.2 → lme_python-0.2.4}/src/robust.rs +17 -2
- {lme_python-0.2.2 → lme_python-0.2.4}/src/satterthwaite.rs +3 -10
- {lme_python-0.2.2 → lme_python-0.2.4}/src/simulate.rs +47 -22
- {lme_python-0.2.2 → lme_python-0.2.4}/src/studentized_range.rs +15 -0
- {lme_python-0.2.2 → lme_python-0.2.4}/tests/ci_consolidated.rs +13 -0
- {lme_python-0.2.2 → lme_python-0.2.4}/tests/test_anova.rs +1 -0
- lme_python-0.2.4/tests/test_bug_hunt.rs +353 -0
- lme_python-0.2.4/tests/test_bug_hunt_edges.rs +255 -0
- lme_python-0.2.4/tests/test_bug_hunt_more.rs +212 -0
- lme_python-0.2.4/tests/test_bug_hunt_numerics.rs +287 -0
- {lme_python-0.2.2 → lme_python-0.2.4}/tests/test_coverage_gaps.rs +2 -1
- {lme_python-0.2.2 → lme_python-0.2.4}/tests/test_failure_modes.rs +14 -14
- {lme_python-0.2.2 → lme_python-0.2.4}/tests/test_formula_stress.rs +1 -0
- lme_python-0.2.4/tests/test_inference_guards.rs +187 -0
- lme_python-0.2.4/tests/test_model_contracts.rs +333 -0
- {lme_python-0.2.2 → lme_python-0.2.4}/tests/test_predict.rs +4 -3
- lme_python-0.2.2/AGENTS.md +0 -112
- lme_python-0.2.2/CONTRIBUTING.md +0 -220
- lme_python-0.2.2/PKG-INFO +0 -67
- lme_python-0.2.2/README.md +0 -113
- lme_python-0.2.2/RELEASING.md +0 -273
- lme_python-0.2.2/REPO_COMPLETION_BY_AREA.md +0 -110
- lme_python-0.2.2/USABILITY.md +0 -185
- lme_python-0.2.2/completion_manifest.json +0 -20
- lme_python-0.2.2/docs/CALO_CALIBRATION.md +0 -124
- lme_python-0.2.2/docs/benchmarks/app.js +0 -207
- lme_python-0.2.2/docs/benchmarks/index.html +0 -92
- lme_python-0.2.2/python/README.md +0 -44
- lme_python-0.2.2/python/examples/plotting_demo/README.md +0 -129
- lme_python-0.2.2/python/examples/verification_project/README.md +0 -42
- lme_python-0.2.2/scripts/build_benchmark_site.py +0 -210
- lme_python-0.2.2/scripts/ci/README.md +0 -31
- lme_python-0.2.2/src/kenward_roger.rs +0 -357
- {lme_python-0.2.2 → lme_python-0.2.4}/.JuliaFormatter.toml +0 -0
- {lme_python-0.2.2 → lme_python-0.2.4}/.github/dependabot.yml +0 -0
- {lme_python-0.2.2 → lme_python-0.2.4}/.github/workflows/crate-publish-dry-run.yml +0 -0
- {lme_python-0.2.2 → lme_python-0.2.4}/.github/workflows/repo-metadata.yml +0 -0
- {lme_python-0.2.2 → lme_python-0.2.4}/.gitignore +0 -0
- {lme_python-0.2.2 → lme_python-0.2.4}/LICENSE +0 -0
- {lme_python-0.2.2 → lme_python-0.2.4}/LICENSES/Apache-2.0.txt +0 -0
- {lme_python-0.2.2 → lme_python-0.2.4}/LICENSES/BSD-3-Clause-OpenBLAS.txt +0 -0
- {lme_python-0.2.2 → lme_python-0.2.4}/LICENSES/GPL-2.0-or-later.txt +0 -0
- {lme_python-0.2.2 → lme_python-0.2.4}/LICENSES/Intel-Simplified-Software-License.txt +0 -0
- {lme_python-0.2.2 → lme_python-0.2.4}/LICENSES/LGPL-2.1-only.txt +0 -0
- {lme_python-0.2.2 → lme_python-0.2.4}/RELINKING.md +0 -0
- {lme_python-0.2.2 → lme_python-0.2.4}/THIRD_PARTY_NOTICES.md +0 -0
- {lme_python-0.2.2 → lme_python-0.2.4}/benches/bench_load_production.rs +0 -0
- {lme_python-0.2.2 → lme_python-0.2.4}/benches/bench_math.rs +0 -0
- {lme_python-0.2.2 → lme_python-0.2.4}/benchmarks/external-nlmm-inference-python-timings-2026-08-14.json +0 -0
- {lme_python-0.2.2 → lme_python-0.2.4}/benchmarks/fair-rust-julia-reference-2026-07-04.json +0 -0
- {lme_python-0.2.2 → lme_python-0.2.4}/benchmarks/fair-rust-julia-reference-2026-07-06.json +0 -0
- {lme_python-0.2.2 → lme_python-0.2.4}/benchmarks/fair-rust-julia-reference-2026-07-08.json +0 -0
- {lme_python-0.2.2 → lme_python-0.2.4}/benchmarks/fair-rust-julia-reference-2026-07-09-direct-intercept-gram.json +0 -0
- {lme_python-0.2.2 → lme_python-0.2.4}/benchmarks/fair-rust-julia-reference-2026-07-09-full-lmm.json +0 -0
- {lme_python-0.2.2 → lme_python-0.2.4}/benchmarks/fair-rust-julia-reference-2026-07-09-glmm.json +0 -0
- {lme_python-0.2.2 → lme_python-0.2.4}/benchmarks/fair-rust-julia-reference-2026-07-09-large-intercept-setup.json +0 -0
- {lme_python-0.2.2 → lme_python-0.2.4}/benchmarks/fair-rust-julia-reference-2026-07-09-large-slopes-linear-cache.json +0 -0
- {lme_python-0.2.2 → lme_python-0.2.4}/benchmarks/fair-rust-julia-reference-2026-07-09-large-slopes.json +0 -0
- {lme_python-0.2.2 → lme_python-0.2.4}/benchmarks/fair-rust-julia-reference-2026-07-09-sleepstudy-slopes.json +0 -0
- {lme_python-0.2.2 → lme_python-0.2.4}/benchmarks/fair-rust-julia-reference-2026-07-09.json +0 -0
- {lme_python-0.2.2 → lme_python-0.2.4}/benchmarks/fair-rust-julia-reference-2026-07-10-cold-setup-followup.json +0 -0
- {lme_python-0.2.2 → lme_python-0.2.4}/benchmarks/fair-rust-julia-reference-2026-07-16-cold-fit-lt1.json +0 -0
- {lme_python-0.2.2 → lme_python-0.2.4}/benchmarks/fair-rust-julia-reference-2026-07-22-full-tier-a.json +0 -0
- {lme_python-0.2.2 → lme_python-0.2.4}/comparisons/bench_external_timings.R +0 -0
- {lme_python-0.2.2 → lme_python-0.2.4}/comparisons/bench_fair_julia_perf.jl +0 -0
- {lme_python-0.2.2 → lme_python-0.2.4}/comparisons/bench_fair_julia_timing.jl +0 -0
- {lme_python-0.2.2 → lme_python-0.2.4}/comparisons/bench_fair_rust_julia.rs +0 -0
- {lme_python-0.2.2 → lme_python-0.2.4}/comparisons/bench_perf_breakdown.rs +0 -0
- {lme_python-0.2.2 → lme_python-0.2.4}/comparisons/categorical_anova.R +0 -0
- {lme_python-0.2.2 → lme_python-0.2.4}/comparisons/categorical_anova.jl +0 -0
- {lme_python-0.2.2 → lme_python-0.2.4}/comparisons/categorical_anova.py +0 -0
- {lme_python-0.2.2 → lme_python-0.2.4}/comparisons/categorical_anova.rs +0 -0
- {lme_python-0.2.2 → lme_python-0.2.4}/comparisons/comparison_chart.png +0 -0
- {lme_python-0.2.2 → lme_python-0.2.4}/comparisons/glmm_cbpp.R +0 -0
- {lme_python-0.2.2 → lme_python-0.2.4}/comparisons/glmm_cbpp.jl +0 -0
- {lme_python-0.2.2 → lme_python-0.2.4}/comparisons/glmm_cbpp.py +0 -0
- {lme_python-0.2.2 → lme_python-0.2.4}/comparisons/glmm_cbpp.rs +0 -0
- {lme_python-0.2.2 → lme_python-0.2.4}/comparisons/glmm_gaussian.R +0 -0
- {lme_python-0.2.2 → lme_python-0.2.4}/comparisons/glmm_gaussian.jl +0 -0
- {lme_python-0.2.2 → lme_python-0.2.4}/comparisons/glmm_gaussian.py +0 -0
- {lme_python-0.2.2 → lme_python-0.2.4}/comparisons/glmm_gaussian.rs +0 -0
- {lme_python-0.2.2 → lme_python-0.2.4}/comparisons/glmm_grouseticks.R +0 -0
- {lme_python-0.2.2 → lme_python-0.2.4}/comparisons/glmm_grouseticks.jl +0 -0
- {lme_python-0.2.2 → lme_python-0.2.4}/comparisons/glmm_grouseticks.py +0 -0
- {lme_python-0.2.2 → lme_python-0.2.4}/comparisons/glmm_grouseticks.rs +0 -0
- {lme_python-0.2.2 → lme_python-0.2.4}/comparisons/lmer_weighted.R +0 -0
- {lme_python-0.2.2 → lme_python-0.2.4}/comparisons/lmer_weighted.jl +0 -0
- {lme_python-0.2.2 → lme_python-0.2.4}/comparisons/lmer_weighted.py +0 -0
- {lme_python-0.2.2 → lme_python-0.2.4}/comparisons/lmer_weighted.rs +0 -0
- {lme_python-0.2.2 → lme_python-0.2.4}/comparisons/lmm_dyestuff.R +0 -0
- {lme_python-0.2.2 → lme_python-0.2.4}/comparisons/lmm_dyestuff.jl +0 -0
- {lme_python-0.2.2 → lme_python-0.2.4}/comparisons/lmm_dyestuff.py +0 -0
- {lme_python-0.2.2 → lme_python-0.2.4}/comparisons/lmm_dyestuff.rs +0 -0
- {lme_python-0.2.2 → lme_python-0.2.4}/comparisons/lmm_pastes.R +0 -0
- {lme_python-0.2.2 → lme_python-0.2.4}/comparisons/lmm_pastes.jl +0 -0
- {lme_python-0.2.2 → lme_python-0.2.4}/comparisons/lmm_pastes.py +0 -0
- {lme_python-0.2.2 → lme_python-0.2.4}/comparisons/lmm_pastes.rs +0 -0
- {lme_python-0.2.2 → lme_python-0.2.4}/comparisons/lmm_penicillin.R +0 -0
- {lme_python-0.2.2 → lme_python-0.2.4}/comparisons/lmm_penicillin.jl +0 -0
- {lme_python-0.2.2 → lme_python-0.2.4}/comparisons/lmm_penicillin.py +0 -0
- {lme_python-0.2.2 → lme_python-0.2.4}/comparisons/lmm_penicillin.rs +0 -0
- {lme_python-0.2.2 → lme_python-0.2.4}/comparisons/nlmm_sspower.R +0 -0
- {lme_python-0.2.2 → lme_python-0.2.4}/comparisons/parity/glmm_offset.R +0 -0
- {lme_python-0.2.2 → lme_python-0.2.4}/comparisons/parity/glmm_offset.jl +0 -0
- {lme_python-0.2.2 → lme_python-0.2.4}/comparisons/parity/glmm_probit.R +0 -0
- {lme_python-0.2.2 → lme_python-0.2.4}/comparisons/parity/glmm_probit.jl +0 -0
- {lme_python-0.2.2 → lme_python-0.2.4}/comparisons/parity/glmm_weighted.R +0 -0
- {lme_python-0.2.2 → lme_python-0.2.4}/comparisons/parity/glmm_weighted.jl +0 -0
- {lme_python-0.2.2 → lme_python-0.2.4}/comparisons/parity/parity_r_setup.R +0 -0
- {lme_python-0.2.2 → lme_python-0.2.4}/comparisons/parity/sleepstudy_offset.R +0 -0
- {lme_python-0.2.2 → lme_python-0.2.4}/comparisons/parity/sleepstudy_offset.jl +0 -0
- {lme_python-0.2.2 → lme_python-0.2.4}/comparisons/parity_export.rs +0 -0
- {lme_python-0.2.2 → lme_python-0.2.4}/comparisons/pastes_emmeans.R +0 -0
- {lme_python-0.2.2 → lme_python-0.2.4}/comparisons/pastes_glht.R +0 -0
- {lme_python-0.2.2 → lme_python-0.2.4}/comparisons/r_setup.R +0 -0
- {lme_python-0.2.2 → lme_python-0.2.4}/comparisons/sleepstudy.R +0 -0
- {lme_python-0.2.2 → lme_python-0.2.4}/comparisons/sleepstudy.jl +0 -0
- {lme_python-0.2.2 → lme_python-0.2.4}/comparisons/sleepstudy.py +0 -0
- {lme_python-0.2.2 → lme_python-0.2.4}/comparisons/sleepstudy.rs +0 -0
- {lme_python-0.2.2 → lme_python-0.2.4}/comparisons/sleepstudy_confint_profile.R +0 -0
- {lme_python-0.2.2 → lme_python-0.2.4}/comparisons/sleepstudy_ml.R +0 -0
- {lme_python-0.2.2 → lme_python-0.2.4}/comparisons/sleepstudy_ml.jl +0 -0
- {lme_python-0.2.2 → lme_python-0.2.4}/comparisons/sleepstudy_ml.py +0 -0
- {lme_python-0.2.2 → lme_python-0.2.4}/comparisons/sleepstudy_ml.rs +0 -0
- {lme_python-0.2.2 → lme_python-0.2.4}/examples/batch_sspower_cpu.rs +0 -0
- {lme_python-0.2.2 → lme_python-0.2.4}/examples/bench_external_timings.rs +0 -0
- {lme_python-0.2.2 → lme_python-0.2.4}/examples/dump_cascade_fixtures.rs +0 -0
- {lme_python-0.2.2 → lme_python-0.2.4}/examples/explore_formula_ast.rs +0 -0
- {lme_python-0.2.2 → lme_python-0.2.4}/examples/explore_mcp_adjust.rs +0 -0
- {lme_python-0.2.2 → lme_python-0.2.4}/examples/explore_theta_grid.rs +0 -0
- {lme_python-0.2.2 → lme_python-0.2.4}/examples/nlmm_fixture_dump.rs +0 -0
- {lme_python-0.2.2 → lme_python-0.2.4}/legal/dependency-license-exceptions.json +0 -0
- {lme_python-0.2.2 → lme_python-0.2.4}/legal/fixture-provenance.json +0 -0
- {lme_python-0.2.2 → lme_python-0.2.4}/mise.toml +0 -0
- {lme_python-0.2.2 → lme_python-0.2.4}/pyproject.toml +0 -0
- {lme_python-0.2.2 → lme_python-0.2.4}/python/examples/glmer_cbpp.py +0 -0
- {lme_python-0.2.2 → lme_python-0.2.4}/python/examples/glmer_grouseticks.py +0 -0
- {lme_python-0.2.2 → lme_python-0.2.4}/python/examples/lm_basics.py +0 -0
- {lme_python-0.2.2 → lme_python-0.2.4}/python/examples/lmer_sleepstudy.py +0 -0
- {lme_python-0.2.2 → lme_python-0.2.4}/python/examples/model_comparison.py +0 -0
- {lme_python-0.2.2 → lme_python-0.2.4}/python/examples/plotting_demo/.gitignore +0 -0
- {lme_python-0.2.2 → lme_python-0.2.4}/python/examples/plotting_demo/compare_plots.py +0 -0
- {lme_python-0.2.2 → lme_python-0.2.4}/python/examples/plotting_demo/figure_specs.py +0 -0
- {lme_python-0.2.2 → lme_python-0.2.4}/python/examples/plotting_demo/find_rscript.py +0 -0
- {lme_python-0.2.2 → lme_python-0.2.4}/python/examples/plotting_demo/numeric_overlay.py +0 -0
- {lme_python-0.2.2 → lme_python-0.2.4}/python/examples/plotting_demo/paths.py +0 -0
- {lme_python-0.2.2 → lme_python-0.2.4}/python/examples/plotting_demo/plot_demo.py +0 -0
- {lme_python-0.2.2 → lme_python-0.2.4}/python/examples/plotting_demo/plot_r.R +0 -0
- {lme_python-0.2.2 → lme_python-0.2.4}/python/examples/plotting_demo/run_all.py +0 -0
- {lme_python-0.2.2 → lme_python-0.2.4}/python/examples/verification_project/conftest.py +0 -0
- {lme_python-0.2.2 → lme_python-0.2.4}/python/examples/verification_project/parity.py +0 -0
- {lme_python-0.2.2 → lme_python-0.2.4}/python/examples/verification_project/paths.py +0 -0
- {lme_python-0.2.2 → lme_python-0.2.4}/python/examples/verification_project/run.py +0 -0
- {lme_python-0.2.2 → lme_python-0.2.4}/python/examples/verification_project/test_parity.py +0 -0
- {lme_python-0.2.2 → lme_python-0.2.4}/python/tests/test_api_parity.py +0 -0
- {lme_python-0.2.2 → lme_python-0.2.4}/python/tests/test_basic.py +0 -0
- {lme_python-0.2.2 → lme_python-0.2.4}/python/tests/test_cv.py +0 -0
- {lme_python-0.2.2 → lme_python-0.2.4}/python/tests/test_dataframe_inputs.py +0 -0
- {lme_python-0.2.2 → lme_python-0.2.4}/python/tests/test_golden_parity.py +0 -0
- {lme_python-0.2.2 → lme_python-0.2.4}/python/tests/test_nlmer_custom_mean.py +0 -0
- {lme_python-0.2.2 → lme_python-0.2.4}/python/tests/test_simulate_scale.py +0 -0
- {lme_python-0.2.2 → lme_python-0.2.4}/python/tests/test_wheel_notices.py +0 -0
- {lme_python-0.2.2 → lme_python-0.2.4}/scripts/ci/check_legal_compliance.py +0 -0
- {lme_python-0.2.2 → lme_python-0.2.4}/scripts/ci/julia_format.jl +0 -0
- {lme_python-0.2.2 → lme_python-0.2.4}/scripts/ci/package_wheel_notices.py +0 -0
- {lme_python-0.2.2 → lme_python-0.2.4}/scripts/ci/r_format.R +0 -0
- {lme_python-0.2.2 → lme_python-0.2.4}/scripts/ci/run.sh +0 -0
- {lme_python-0.2.2 → lme_python-0.2.4}/scripts/dump_dyestuff.R +0 -0
- {lme_python-0.2.2 → lme_python-0.2.4}/scripts/dump_pastes.R +0 -0
- {lme_python-0.2.2 → lme_python-0.2.4}/scripts/local_ci.ps1 +0 -0
- {lme_python-0.2.2 → lme_python-0.2.4}/scripts/local_ci.sh +0 -0
- {lme_python-0.2.2 → lme_python-0.2.4}/scripts/make_penicillin_csv.py +0 -0
- {lme_python-0.2.2 → lme_python-0.2.4}/scripts/plot_comparisons.py +0 -0
- {lme_python-0.2.2 → lme_python-0.2.4}/scripts/run_cross_language_benchmarks.py +0 -0
- {lme_python-0.2.2 → lme_python-0.2.4}/scripts/run_external_timings.py +0 -0
- {lme_python-0.2.2 → lme_python-0.2.4}/scripts/run_fair_rust_julia_benchmark.py +0 -0
- {lme_python-0.2.2 → lme_python-0.2.4}/scripts/run_perf_breakdown.py +0 -0
- {lme_python-0.2.2 → lme_python-0.2.4}/scripts/sync_github_repo_metadata.py +0 -0
- {lme_python-0.2.2 → lme_python-0.2.4}/scripts/verify_cross_language_parity.py +0 -0
- {lme_python-0.2.2 → lme_python-0.2.4}/src/anova.rs +0 -0
- {lme_python-0.2.2 → lme_python-0.2.4}/src/anova_contrasts.rs +0 -0
- {lme_python-0.2.2 → lme_python-0.2.4}/src/basis.rs +0 -0
- {lme_python-0.2.2 → lme_python-0.2.4}/src/family.rs +0 -0
- {lme_python-0.2.2 → lme_python-0.2.4}/src/nlmm/formula.rs +0 -0
- {lme_python-0.2.2 → lme_python-0.2.4}/src/nlmm/mean.rs +0 -0
- {lme_python-0.2.2 → lme_python-0.2.4}/src/nlmm/mean_fn.rs +0 -0
- {lme_python-0.2.2 → lme_python-0.2.4}/src/nlmm/predict.rs +0 -0
- {lme_python-0.2.2 → lme_python-0.2.4}/src/nlmm/re_cov.rs +0 -0
- {lme_python-0.2.2 → lme_python-0.2.4}/src/nlmm/self_start.rs +0 -0
- {lme_python-0.2.2 → lme_python-0.2.4}/src/nlmm/ssasymp.rs +0 -0
- {lme_python-0.2.2 → lme_python-0.2.4}/src/nlmm/ssasympoff.rs +0 -0
- {lme_python-0.2.2 → lme_python-0.2.4}/src/nlmm/ssasymporig.rs +0 -0
- {lme_python-0.2.2 → lme_python-0.2.4}/src/nlmm/ssbiexp.rs +0 -0
- {lme_python-0.2.2 → lme_python-0.2.4}/src/nlmm/ssfpl.rs +0 -0
- {lme_python-0.2.2 → lme_python-0.2.4}/src/nlmm/ssgompertz.rs +0 -0
- {lme_python-0.2.2 → lme_python-0.2.4}/src/nlmm/sslogis.rs +0 -0
- {lme_python-0.2.2 → lme_python-0.2.4}/src/nlmm/ssmicmen.rs +0 -0
- {lme_python-0.2.2 → lme_python-0.2.4}/src/nlmm/sspower.rs +0 -0
- {lme_python-0.2.2 → lme_python-0.2.4}/src/nlmm/ssweibull.rs +0 -0
- {lme_python-0.2.2 → lme_python-0.2.4}/src/quadrature.rs +0 -0
- {lme_python-0.2.2 → lme_python-0.2.4}/tests/categorical_anova_test.rs +0 -0
- {lme_python-0.2.2 → lme_python-0.2.4}/tests/data/cbpp_binary.csv +0 -0
- {lme_python-0.2.2 → lme_python-0.2.4}/tests/data/cbpp_binary_weighted.csv +0 -0
- {lme_python-0.2.2 → lme_python-0.2.4}/tests/data/dyestuff.csv +0 -0
- {lme_python-0.2.2 → lme_python-0.2.4}/tests/data/dyestuff_intercept_reml.json +0 -0
- {lme_python-0.2.2 → lme_python-0.2.4}/tests/data/glmm_binomial.json +0 -0
- {lme_python-0.2.2 → lme_python-0.2.4}/tests/data/glmm_binomial_agq.json +0 -0
- {lme_python-0.2.2 → lme_python-0.2.4}/tests/data/glmm_binomial_cloglog.json +0 -0
- {lme_python-0.2.2 → lme_python-0.2.4}/tests/data/glmm_binomial_probit.json +0 -0
- {lme_python-0.2.2 → lme_python-0.2.4}/tests/data/glmm_binomial_weighted.json +0 -0
- {lme_python-0.2.2 → lme_python-0.2.4}/tests/data/glmm_gamma_dyestuff.json +0 -0
- {lme_python-0.2.2 → lme_python-0.2.4}/tests/data/glmm_poisson.json +0 -0
- {lme_python-0.2.2 → lme_python-0.2.4}/tests/data/glmm_poisson_offset.json +0 -0
- {lme_python-0.2.2 → lme_python-0.2.4}/tests/data/golden_parity_manifest.json +0 -0
- {lme_python-0.2.2 → lme_python-0.2.4}/tests/data/grouseticks.csv +0 -0
- {lme_python-0.2.2 → lme_python-0.2.4}/tests/data/intercept_only.json +0 -0
- {lme_python-0.2.2 → lme_python-0.2.4}/tests/data/mock_crossed.json +0 -0
- {lme_python-0.2.2 → lme_python-0.2.4}/tests/data/mock_ml.json +0 -0
- {lme_python-0.2.2 → lme_python-0.2.4}/tests/data/orange.csv +0 -0
- {lme_python-0.2.2 → lme_python-0.2.4}/tests/data/orange_nlmer.json +0 -0
- {lme_python-0.2.2 → lme_python-0.2.4}/tests/data/pastes.csv +0 -0
- {lme_python-0.2.2 → lme_python-0.2.4}/tests/data/pastes_cask_reml.json +0 -0
- {lme_python-0.2.2 → lme_python-0.2.4}/tests/data/pastes_emmeans.json +0 -0
- {lme_python-0.2.2 → lme_python-0.2.4}/tests/data/pastes_glht_tukey.json +0 -0
- {lme_python-0.2.2 → lme_python-0.2.4}/tests/data/penicillin.csv +0 -0
- {lme_python-0.2.2 → lme_python-0.2.4}/tests/data/penicillin.json +0 -0
- {lme_python-0.2.2 → lme_python-0.2.4}/tests/data/r_edge_case_matrix.json +0 -0
- {lme_python-0.2.2 → lme_python-0.2.4}/tests/data/random_slopes.json +0 -0
- {lme_python-0.2.2 → lme_python-0.2.4}/tests/data/sleepstudy.csv +0 -0
- {lme_python-0.2.2 → lme_python-0.2.4}/tests/data/sleepstudy_confint_profile.json +0 -0
- {lme_python-0.2.2 → lme_python-0.2.4}/tests/data/sleepstudy_confint_profile_vc.json +0 -0
- {lme_python-0.2.2 → lme_python-0.2.4}/tests/data/sleepstudy_offset_reml.json +0 -0
- {lme_python-0.2.2 → lme_python-0.2.4}/tests/data/ssasymp_synthetic.csv +0 -0
- {lme_python-0.2.2 → lme_python-0.2.4}/tests/data/ssasympoff_nlmer.json +0 -0
- {lme_python-0.2.2 → lme_python-0.2.4}/tests/data/ssasympoff_synthetic.csv +0 -0
- {lme_python-0.2.2 → lme_python-0.2.4}/tests/data/ssasymporig_nlmer.json +0 -0
- {lme_python-0.2.2 → lme_python-0.2.4}/tests/data/ssasymporig_synthetic.csv +0 -0
- {lme_python-0.2.2 → lme_python-0.2.4}/tests/data/ssbiexp_nlmer.json +0 -0
- {lme_python-0.2.2 → lme_python-0.2.4}/tests/data/ssbiexp_synthetic.csv +0 -0
- {lme_python-0.2.2 → lme_python-0.2.4}/tests/data/ssfol_nlmer.json +0 -0
- {lme_python-0.2.2 → lme_python-0.2.4}/tests/data/ssfpl_nlmer.json +0 -0
- {lme_python-0.2.2 → lme_python-0.2.4}/tests/data/ssfpl_synthetic.csv +0 -0
- {lme_python-0.2.2 → lme_python-0.2.4}/tests/data/ssgompertz_nlmer.json +0 -0
- {lme_python-0.2.2 → lme_python-0.2.4}/tests/data/ssgompertz_synthetic.csv +0 -0
- {lme_python-0.2.2 → lme_python-0.2.4}/tests/data/ssmicmen_nlmer.json +0 -0
- {lme_python-0.2.2 → lme_python-0.2.4}/tests/data/ssmicmen_synthetic.csv +0 -0
- {lme_python-0.2.2 → lme_python-0.2.4}/tests/data/sspower_nlmer.json +0 -0
- {lme_python-0.2.2 → lme_python-0.2.4}/tests/data/sspower_synthetic.csv +0 -0
- {lme_python-0.2.2 → lme_python-0.2.4}/tests/data/ssweibull_nlmer.json +0 -0
- {lme_python-0.2.2 → lme_python-0.2.4}/tests/data/ssweibull_synthetic.csv +0 -0
- {lme_python-0.2.2 → lme_python-0.2.4}/tests/gen_nlmm_extras.R +0 -0
- {lme_python-0.2.2 → lme_python-0.2.4}/tests/generate_mock_data.py +0 -0
- {lme_python-0.2.2 → lme_python-0.2.4}/tests/generate_nlmm_fixtures.R +0 -0
- {lme_python-0.2.2 → lme_python-0.2.4}/tests/generate_r_edge_case_matrix.R +0 -0
- {lme_python-0.2.2 → lme_python-0.2.4}/tests/generate_test_data.R +0 -0
- {lme_python-0.2.2 → lme_python-0.2.4}/tests/test_anova_types.rs +0 -0
- {lme_python-0.2.2 → lme_python-0.2.4}/tests/test_bootstrap.rs +0 -0
- {lme_python-0.2.2 → lme_python-0.2.4}/tests/test_conditional_real.rs +0 -0
- {lme_python-0.2.2 → lme_python-0.2.4}/tests/test_confint_profile.rs +0 -0
- {lme_python-0.2.2 → lme_python-0.2.4}/tests/test_confint_simulate.rs +0 -0
- {lme_python-0.2.2 → lme_python-0.2.4}/tests/test_contrast.rs +0 -0
- {lme_python-0.2.2 → lme_python-0.2.4}/tests/test_coverage_edge_cases.rs +0 -0
- {lme_python-0.2.2 → lme_python-0.2.4}/tests/test_crossed_mock.rs +0 -0
- {lme_python-0.2.2 → lme_python-0.2.4}/tests/test_cv.rs +0 -0
- {lme_python-0.2.2 → lme_python-0.2.4}/tests/test_e2e_lmer.rs +0 -0
- {lme_python-0.2.2 → lme_python-0.2.4}/tests/test_edge_cases.rs +0 -0
- {lme_python-0.2.2 → lme_python-0.2.4}/tests/test_emmeans.rs +0 -0
- {lme_python-0.2.2 → lme_python-0.2.4}/tests/test_errors.rs +0 -0
- {lme_python-0.2.2 → lme_python-0.2.4}/tests/test_explorations.rs +0 -0
- {lme_python-0.2.2 → lme_python-0.2.4}/tests/test_external_timings_artifact.rs +0 -0
- {lme_python-0.2.2 → lme_python-0.2.4}/tests/test_formula.rs +0 -0
- {lme_python-0.2.2 → lme_python-0.2.4}/tests/test_gaps.rs +0 -0
- {lme_python-0.2.2 → lme_python-0.2.4}/tests/test_glmm.rs +0 -0
- {lme_python-0.2.2 → lme_python-0.2.4}/tests/test_glmm_links.rs +0 -0
- {lme_python-0.2.2 → lme_python-0.2.4}/tests/test_glmm_offset_grouseticks.rs +0 -0
- {lme_python-0.2.2 → lme_python-0.2.4}/tests/test_glmm_weighted.rs +0 -0
- {lme_python-0.2.2 → lme_python-0.2.4}/tests/test_golden_parity.rs +0 -0
- {lme_python-0.2.2 → lme_python-0.2.4}/tests/test_intercept_only.rs +0 -0
- {lme_python-0.2.2 → lme_python-0.2.4}/tests/test_kenward_roger.rs +0 -0
- {lme_python-0.2.2 → lme_python-0.2.4}/tests/test_kr_modcomp_pastes.rs +0 -0
- {lme_python-0.2.2 → lme_python-0.2.4}/tests/test_mcp.rs +0 -0
- {lme_python-0.2.2 → lme_python-0.2.4}/tests/test_ml_optimization.rs +0 -0
- {lme_python-0.2.2 → lme_python-0.2.4}/tests/test_nlmm_agq.rs +0 -0
- {lme_python-0.2.2 → lme_python-0.2.4}/tests/test_nlmm_bounds.rs +0 -0
- {lme_python-0.2.2 → lme_python-0.2.4}/tests/test_nlmm_custom_mean.rs +0 -0
- {lme_python-0.2.2 → lme_python-0.2.4}/tests/test_nlmm_orange.rs +0 -0
- {lme_python-0.2.2 → lme_python-0.2.4}/tests/test_nlmm_orange_multi_re.rs +0 -0
- {lme_python-0.2.2 → lme_python-0.2.4}/tests/test_nlmm_self_start.rs +0 -0
- {lme_python-0.2.2 → lme_python-0.2.4}/tests/test_nlmm_ss_new_means.rs +0 -0
- {lme_python-0.2.2 → lme_python-0.2.4}/tests/test_nlmm_ssasymp.rs +0 -0
- {lme_python-0.2.2 → lme_python-0.2.4}/tests/test_nlmm_ssasymp_off_orig.rs +0 -0
- {lme_python-0.2.2 → lme_python-0.2.4}/tests/test_nlmm_ssfol.rs +0 -0
- {lme_python-0.2.2 → lme_python-0.2.4}/tests/test_nlmm_ssmicmen.rs +0 -0
- {lme_python-0.2.2 → lme_python-0.2.4}/tests/test_nlmm_sspower.rs +0 -0
- {lme_python-0.2.2 → lme_python-0.2.4}/tests/test_no_intercept.rs +0 -0
- {lme_python-0.2.2 → lme_python-0.2.4}/tests/test_numerical_parity.rs +0 -0
- {lme_python-0.2.2 → lme_python-0.2.4}/tests/test_production_load.rs +0 -0
- {lme_python-0.2.2 → lme_python-0.2.4}/tests/test_r_edge_case_matrix.rs +0 -0
- {lme_python-0.2.2 → lme_python-0.2.4}/tests/test_random_slopes.rs +0 -0
- {lme_python-0.2.2 → lme_python-0.2.4}/tests/test_robust.rs +0 -0
- {lme_python-0.2.2 → lme_python-0.2.4}/tests/test_sandwich_math.R +0 -0
- {lme_python-0.2.2 → lme_python-0.2.4}/tests/test_satterthwaite.rs +0 -0
- {lme_python-0.2.2 → lme_python-0.2.4}/tests/test_statistical_identities.rs +0 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
github: x4g4p3x
|
|
@@ -28,7 +28,7 @@ jobs:
|
|
|
28
28
|
toolchain: stable
|
|
29
29
|
|
|
30
30
|
- name: Install cargo-audit
|
|
31
|
-
uses: taiki-e/install-action@
|
|
31
|
+
uses: taiki-e/install-action@84f5ac3124727fb3d284d4d22ee9ab3654fd09a6 # v2
|
|
32
32
|
with:
|
|
33
33
|
tool: cargo-audit@0.22.1
|
|
34
34
|
|
|
@@ -48,7 +48,7 @@ jobs:
|
|
|
48
48
|
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
49
49
|
|
|
50
50
|
- name: Set up uv
|
|
51
|
-
uses: astral-sh/setup-uv@
|
|
51
|
+
uses: astral-sh/setup-uv@20cfd1bf945f4377ade1205e4dbc17946fc9a30d # v10.0.1
|
|
52
52
|
with:
|
|
53
53
|
python-version: "3.11"
|
|
54
54
|
enable-cache: true
|
|
@@ -18,6 +18,7 @@ on:
|
|
|
18
18
|
permissions:
|
|
19
19
|
contents: write
|
|
20
20
|
id-token: write
|
|
21
|
+
pages: write
|
|
21
22
|
|
|
22
23
|
env:
|
|
23
24
|
CARGO_TERM_COLOR: always
|
|
@@ -200,3 +201,78 @@ jobs:
|
|
|
200
201
|
echo "Cross-language benchmark script failed with exit code ${{ steps.cross_language_run.outputs.status }}." >&2
|
|
201
202
|
exit 1
|
|
202
203
|
|
|
204
|
+
pages:
|
|
205
|
+
name: Publish Benchmark Dashboard
|
|
206
|
+
runs-on: ubuntu-latest
|
|
207
|
+
needs:
|
|
208
|
+
- criterion
|
|
209
|
+
- cross-language
|
|
210
|
+
if: >
|
|
211
|
+
always() &&
|
|
212
|
+
needs.criterion.result == 'success' &&
|
|
213
|
+
needs.cross-language.result == 'success' &&
|
|
214
|
+
(github.ref == 'refs/heads/master' || startsWith(github.ref, 'refs/tags/'))
|
|
215
|
+
permissions:
|
|
216
|
+
contents: read
|
|
217
|
+
pages: write
|
|
218
|
+
id-token: write
|
|
219
|
+
environment:
|
|
220
|
+
name: github-pages
|
|
221
|
+
url: ${{ steps.deploy.outputs.page_url }}
|
|
222
|
+
concurrency:
|
|
223
|
+
group: pages
|
|
224
|
+
cancel-in-progress: true
|
|
225
|
+
steps:
|
|
226
|
+
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
227
|
+
|
|
228
|
+
- uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0
|
|
229
|
+
with:
|
|
230
|
+
python-version: "3.11"
|
|
231
|
+
|
|
232
|
+
- name: Download cross-language artifact
|
|
233
|
+
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
|
|
234
|
+
with:
|
|
235
|
+
name: cross-language-${{ github.sha }}
|
|
236
|
+
path: site-input
|
|
237
|
+
|
|
238
|
+
- name: Resolve release URL
|
|
239
|
+
id: release_url
|
|
240
|
+
run: |
|
|
241
|
+
if [[ "${GITHUB_REF}" == refs/tags/* ]]; then
|
|
242
|
+
echo "value=${GITHUB_SERVER_URL}/${GITHUB_REPOSITORY}/releases/tag/${GITHUB_REF_NAME}" >> "$GITHUB_OUTPUT"
|
|
243
|
+
else
|
|
244
|
+
echo "value=" >> "$GITHUB_OUTPUT"
|
|
245
|
+
fi
|
|
246
|
+
|
|
247
|
+
- name: Build benchmark dashboard
|
|
248
|
+
run: |
|
|
249
|
+
set -euo pipefail
|
|
250
|
+
mkdir -p site
|
|
251
|
+
cp -R docs/. site/
|
|
252
|
+
extra=()
|
|
253
|
+
fair_json="$(find site-input -name 'fair-rust-julia-*.json' -print -quit || true)"
|
|
254
|
+
cross_json="$(find site-input -name 'cross-language-*.json' -print -quit || true)"
|
|
255
|
+
if [ -n "${fair_json}" ]; then
|
|
256
|
+
extra+=(--ci-fair-json "${fair_json}" --fair-asset-name "fair-rust-julia-${GITHUB_SHA}.json")
|
|
257
|
+
fi
|
|
258
|
+
if [ -n "${cross_json}" ]; then
|
|
259
|
+
extra+=(--cross-language-json "${cross_json}" --cross-language-asset-name "cross-language-${GITHUB_SHA}.json")
|
|
260
|
+
fi
|
|
261
|
+
python3 scripts/build_benchmark_site.py \
|
|
262
|
+
--output-dir site/benchmarks/data \
|
|
263
|
+
--run-url "${GITHUB_SERVER_URL}/${GITHUB_REPOSITORY}/actions/runs/${GITHUB_RUN_ID}" \
|
|
264
|
+
--release-url "${{ steps.release_url.outputs.value }}" \
|
|
265
|
+
--criterion-asset-name "criterion-${GITHUB_SHA}.tar.gz" \
|
|
266
|
+
--ref-name "${GITHUB_REF_NAME}" \
|
|
267
|
+
"${extra[@]+"${extra[@]}"}"
|
|
268
|
+
|
|
269
|
+
- uses: actions/configure-pages@45bfe0192ca1faeb007ade9deae92b16b8254a0d # v6.0.0
|
|
270
|
+
|
|
271
|
+
- uses: actions/upload-pages-artifact@fc324d3547104276b827a68afc52ff2a11cc49c9 # v5.0.0
|
|
272
|
+
with:
|
|
273
|
+
path: site
|
|
274
|
+
|
|
275
|
+
- name: Deploy to GitHub Pages
|
|
276
|
+
id: deploy
|
|
277
|
+
uses: actions/deploy-pages@368f82528645a54fb793d4d04e342629a3f51346 # v5.0.1
|
|
278
|
+
|
|
@@ -54,7 +54,7 @@ jobs:
|
|
|
54
54
|
if: matrix.os == 'macos-latest'
|
|
55
55
|
run: echo "OPENBLAS_TARGET=ARMV8" >> "$GITHUB_ENV"
|
|
56
56
|
- name: Cache Rust dependencies
|
|
57
|
-
uses: Swatinem/rust-cache@
|
|
57
|
+
uses: Swatinem/rust-cache@f0d9c3887740aee45f6153b24b3a6b815192ec16 # v2
|
|
58
58
|
with:
|
|
59
59
|
shared-key: ci-v2-${{ runner.os }}-rust-test
|
|
60
60
|
cache-workspace-crates: ${{ runner.os != 'Linux' }}
|
|
@@ -76,7 +76,7 @@ jobs:
|
|
|
76
76
|
- name: Install OpenBLAS
|
|
77
77
|
run: sudo apt-get update && sudo apt-get install -y libopenblas-dev
|
|
78
78
|
- name: Cache production-load Rust dependencies
|
|
79
|
-
uses: Swatinem/rust-cache@
|
|
79
|
+
uses: Swatinem/rust-cache@f0d9c3887740aee45f6153b24b3a6b815192ec16 # v2
|
|
80
80
|
with:
|
|
81
81
|
shared-key: ci-v2-${{ runner.os }}-rust-release
|
|
82
82
|
cache-workspace-crates: true
|
|
@@ -105,7 +105,7 @@ jobs:
|
|
|
105
105
|
if: matrix.os == 'macos-latest'
|
|
106
106
|
run: echo "OPENBLAS_TARGET=ARMV8" >> "$GITHUB_ENV"
|
|
107
107
|
- name: Cache Python Rust dependencies
|
|
108
|
-
uses: Swatinem/rust-cache@
|
|
108
|
+
uses: Swatinem/rust-cache@f0d9c3887740aee45f6153b24b3a6b815192ec16 # v2
|
|
109
109
|
with:
|
|
110
110
|
shared-key: ci-${{ runner.os }}-python
|
|
111
111
|
workspaces: python -> target
|
|
@@ -36,6 +36,8 @@ jobs:
|
|
|
36
36
|
run: python3 scripts/ci/lme_ci.py legal
|
|
37
37
|
- name: Validate Markdown links
|
|
38
38
|
run: python3 scripts/ci/lme_ci.py docs-links
|
|
39
|
+
- name: Validate benchmark dashboard data
|
|
40
|
+
run: python3 scripts/ci/lme_ci.py benchmark-site --check
|
|
39
41
|
- name: Validate completion score claims
|
|
40
42
|
run: python3 scripts/ci/lme_ci.py completion-check
|
|
41
43
|
|
|
@@ -56,7 +58,7 @@ jobs:
|
|
|
56
58
|
- name: Install OpenBLAS
|
|
57
59
|
run: sudo apt-get update && sudo apt-get install -y libopenblas-dev
|
|
58
60
|
- name: Cache Rust dependencies
|
|
59
|
-
uses: Swatinem/rust-cache@
|
|
61
|
+
uses: Swatinem/rust-cache@f0d9c3887740aee45f6153b24b3a6b815192ec16 # v2
|
|
60
62
|
with:
|
|
61
63
|
shared-key: ci-v2-${{ runner.os }}-rust-test
|
|
62
64
|
save-if: ${{ github.event_name == 'pull_request' || github.ref == 'refs/heads/master' }}
|
|
@@ -113,7 +115,7 @@ jobs:
|
|
|
113
115
|
toolchain: stable
|
|
114
116
|
|
|
115
117
|
- name: Cache Rust dependencies
|
|
116
|
-
uses: Swatinem/rust-cache@
|
|
118
|
+
uses: Swatinem/rust-cache@f0d9c3887740aee45f6153b24b3a6b815192ec16 # v2
|
|
117
119
|
with:
|
|
118
120
|
shared-key: ci-v2-${{ runner.os }}-rust-test
|
|
119
121
|
cache-workspace-crates: true
|
|
@@ -141,7 +143,7 @@ jobs:
|
|
|
141
143
|
run: sudo apt-get update && sudo apt-get install -y libopenblas-dev
|
|
142
144
|
|
|
143
145
|
- name: Restore Rust dependencies
|
|
144
|
-
uses: Swatinem/rust-cache@
|
|
146
|
+
uses: Swatinem/rust-cache@f0d9c3887740aee45f6153b24b3a6b815192ec16 # v2
|
|
145
147
|
with:
|
|
146
148
|
shared-key: ci-v2-${{ runner.os }}-rust-release
|
|
147
149
|
cache-workspace-crates: true
|
|
@@ -169,13 +171,13 @@ jobs:
|
|
|
169
171
|
- name: Install OpenBLAS
|
|
170
172
|
run: sudo apt-get update && sudo apt-get install -y libopenblas-dev
|
|
171
173
|
- name: Cache Python Rust dependencies
|
|
172
|
-
uses: Swatinem/rust-cache@
|
|
174
|
+
uses: Swatinem/rust-cache@f0d9c3887740aee45f6153b24b3a6b815192ec16 # v2
|
|
173
175
|
with:
|
|
174
176
|
shared-key: ci-${{ runner.os }}-python
|
|
175
177
|
workspaces: python -> target
|
|
176
178
|
save-if: ${{ matrix.python-version == '3.11' && (github.event_name == 'pull_request' || github.ref == 'refs/heads/master') }}
|
|
177
179
|
- name: Set up uv
|
|
178
|
-
uses: astral-sh/setup-uv@
|
|
180
|
+
uses: astral-sh/setup-uv@20cfd1bf945f4377ade1205e4dbc17946fc9a30d # v10.0.1
|
|
179
181
|
with:
|
|
180
182
|
python-version: ${{ matrix.python-version }}
|
|
181
183
|
enable-cache: true
|
|
@@ -205,13 +207,13 @@ jobs:
|
|
|
205
207
|
if: matrix.os == 'macos-latest'
|
|
206
208
|
run: echo "OPENBLAS_TARGET=ARMV8" >> "$GITHUB_ENV"
|
|
207
209
|
- name: Cache Python Rust dependencies
|
|
208
|
-
uses: Swatinem/rust-cache@
|
|
210
|
+
uses: Swatinem/rust-cache@f0d9c3887740aee45f6153b24b3a6b815192ec16 # v2
|
|
209
211
|
with:
|
|
210
212
|
shared-key: ci-${{ runner.os }}-python
|
|
211
213
|
workspaces: python -> target
|
|
212
214
|
save-if: ${{ github.event_name == 'pull_request' || github.ref == 'refs/heads/master' }}
|
|
213
215
|
- name: Set up uv
|
|
214
|
-
uses: astral-sh/setup-uv@
|
|
216
|
+
uses: astral-sh/setup-uv@20cfd1bf945f4377ade1205e4dbc17946fc9a30d # v10.0.1
|
|
215
217
|
with:
|
|
216
218
|
python-version: "3.11"
|
|
217
219
|
enable-cache: true
|
|
@@ -31,7 +31,7 @@ jobs:
|
|
|
31
31
|
- name: Install cargo-fuzz
|
|
32
32
|
run: cargo install cargo-fuzz@0.13.2 --locked
|
|
33
33
|
|
|
34
|
-
- uses: Swatinem/rust-cache@
|
|
34
|
+
- uses: Swatinem/rust-cache@f0d9c3887740aee45f6153b24b3a6b815192ec16 # v2
|
|
35
35
|
with:
|
|
36
36
|
workspaces: fuzz
|
|
37
37
|
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
name: GitHub Pages
|
|
2
|
+
|
|
3
|
+
# Publishes the static dashboard from checked-in docs/ plus regenerated JSON.
|
|
4
|
+
# Tag/manual benchmark runs can overlay CI artifacts via benchmarks.yml.
|
|
5
|
+
|
|
6
|
+
on:
|
|
7
|
+
push:
|
|
8
|
+
branches:
|
|
9
|
+
- master
|
|
10
|
+
paths:
|
|
11
|
+
- "docs/**"
|
|
12
|
+
- "benchmarks/*.json"
|
|
13
|
+
- "scripts/build_benchmark_site.py"
|
|
14
|
+
- "scripts/ci/lme_ci.py"
|
|
15
|
+
- ".github/workflows/pages.yml"
|
|
16
|
+
workflow_dispatch:
|
|
17
|
+
|
|
18
|
+
permissions:
|
|
19
|
+
contents: read
|
|
20
|
+
pages: write
|
|
21
|
+
id-token: write
|
|
22
|
+
|
|
23
|
+
concurrency:
|
|
24
|
+
group: pages
|
|
25
|
+
cancel-in-progress: true
|
|
26
|
+
|
|
27
|
+
jobs:
|
|
28
|
+
build:
|
|
29
|
+
name: Build dashboard
|
|
30
|
+
runs-on: ubuntu-latest
|
|
31
|
+
steps:
|
|
32
|
+
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
33
|
+
|
|
34
|
+
- uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0
|
|
35
|
+
with:
|
|
36
|
+
python-version: "3.11"
|
|
37
|
+
|
|
38
|
+
- name: Assemble site
|
|
39
|
+
run: python3 scripts/ci/lme_ci.py benchmark-site --site-dir site
|
|
40
|
+
|
|
41
|
+
- uses: actions/configure-pages@45bfe0192ca1faeb007ade9deae92b16b8254a0d # v6.0.0
|
|
42
|
+
|
|
43
|
+
- uses: actions/upload-pages-artifact@fc324d3547104276b827a68afc52ff2a11cc49c9 # v5.0.0
|
|
44
|
+
with:
|
|
45
|
+
path: site
|
|
46
|
+
|
|
47
|
+
deploy:
|
|
48
|
+
name: Deploy
|
|
49
|
+
needs: build
|
|
50
|
+
runs-on: ubuntu-latest
|
|
51
|
+
environment:
|
|
52
|
+
name: github-pages
|
|
53
|
+
url: ${{ steps.deploy.outputs.page_url }}
|
|
54
|
+
steps:
|
|
55
|
+
- id: deploy
|
|
56
|
+
uses: actions/deploy-pages@368f82528645a54fb793d4d04e342629a3f51346 # v5.0.1
|
|
@@ -256,7 +256,7 @@ jobs:
|
|
|
256
256
|
uses: pypa/gh-action-pypi-publish@dc37677b2e1c63e2034f94d8a5b11f265b73ba33 # release/v1
|
|
257
257
|
|
|
258
258
|
- name: Upload to GitHub Release
|
|
259
|
-
uses: softprops/action-gh-release@
|
|
259
|
+
uses: softprops/action-gh-release@efb35369e0ad2afab669f228072c1b0d510eae64 # v3.0.3
|
|
260
260
|
with:
|
|
261
261
|
files: dist/*
|
|
262
262
|
tag_name: ${{ inputs.release_tag }}
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
# Agent guide
|
|
2
|
+
|
|
3
|
+
This is a Rust statistical library (`lme-rs`) with PyO3/maturin Python bindings
|
|
4
|
+
(`lme_python`). There is no application server to start. Run commands from the
|
|
5
|
+
repository root unless stated otherwise.
|
|
6
|
+
|
|
7
|
+
## Start here
|
|
8
|
+
|
|
9
|
+
1. Inspect `git status --short --branch` and the relevant diff. Preserve unrelated
|
|
10
|
+
changes; do not reset, stash, switch branches, or update dependencies as routine setup.
|
|
11
|
+
2. Use `rg` and the map below to find the implementation and existing tests. Read
|
|
12
|
+
relevant guides rather than scanning the whole repository before a focused fix.
|
|
13
|
+
3. Choose required checks before editing. Reproduce bugs with focused tests, fix
|
|
14
|
+
the cause, and verify both the regression and affected behavior.
|
|
15
|
+
4. Update [CHANGELOG.md](CHANGELOG.md) under `Unreleased` for user-visible fixes,
|
|
16
|
+
features, and compatibility changes. Instruction-only edits need no entry.
|
|
17
|
+
5. Review the final diff. Report changes, validation, and failures/skips/limitations;
|
|
18
|
+
do not claim unrun checks.
|
|
19
|
+
|
|
20
|
+
## Code map
|
|
21
|
+
|
|
22
|
+
| Area | Start with |
|
|
23
|
+
|---|---|
|
|
24
|
+
| Public API, contracts, reusable fits | `src/lib.rs`, `src/model.rs`, `src/prepared.rs` |
|
|
25
|
+
| Formulas and design matrices | `src/formula.rs`, `src/model_matrix.rs`, `src/basis.rs` |
|
|
26
|
+
| LMM / GLMM / nonlinear fitting | `src/math.rs`, `src/optimizer.rs`, `src/intercept_blocked.rs` / `src/glmm_math.rs`, `src/family.rs` / `src/nlmm/` |
|
|
27
|
+
| Inference and post-fit behavior | `src/contrast.rs`, `src/ddf.rs`, `src/satterthwaite.rs`, `src/kenward_roger.rs`, `src/kr_modcomp.rs`; named modules such as `predict.rs`, `simulate.rs`, `emmeans.rs`, `mcp.rs`, `robust.rs` |
|
|
28
|
+
| Python API and tests | `python/src/lib.rs`, `python/tests/` |
|
|
29
|
+
| Regression tests and reference evidence | `tests/`, `tests/data/`, `comparisons/` |
|
|
30
|
+
| Checks, aliases, hooks, tool versions | [scripts/ci/lme_ci.py](scripts/ci/lme_ci.py), [Taskfile.yml](Taskfile.yml), [lefthook.yml](lefthook.yml), [mise.toml](mise.toml) |
|
|
31
|
+
|
|
32
|
+
## Required validation
|
|
33
|
+
|
|
34
|
+
Use the smallest tier covering the change. Requirements from multiple rows combine;
|
|
35
|
+
a successful broader check can satisfy its component checks.
|
|
36
|
+
|
|
37
|
+
| Change | Minimum checks and escalation |
|
|
38
|
+
|---|---|
|
|
39
|
+
| Rust code | `task lint`, `task test:fast`, and affected integration tests; use `task rust` for cross-module or public-API changes |
|
|
40
|
+
| Python bindings | `task lint:python`, `task python` |
|
|
41
|
+
| CI, manifests, release tooling | `task preflight`; use `task ci` before a release or broad refactor |
|
|
42
|
+
| R / Julia comparison scripts | `task lint:comparisons`; use `task lint:comparisons:required` when formatters are installed |
|
|
43
|
+
| Documentation (including this file) or portable examples | `task docs:check`; add `task consumer:smoke` when install or example behavior changes |
|
|
44
|
+
| LMM throughput paths (`src/math.rs`, `src/optimizer.rs`, related caches/solvers) | Read [OPTIMIZATION.md](OPTIMIZATION.md) and run applicable fair-harness cases in addition to Rust checks |
|
|
45
|
+
| `README.md`, `REPO_COMPLETION_BY_AREA.md`, `completion_manifest.json`, `scripts/ci/check_completion_score.py` | `task completion:check` |
|
|
46
|
+
|
|
47
|
+
### Avoid redundant work
|
|
48
|
+
|
|
49
|
+
- Start with `cargo test --locked --test <test_target> <test_filter>` or
|
|
50
|
+
`cargo test --locked --lib <test_filter>`. Selecting zero tests proves nothing.
|
|
51
|
+
- `task rust` includes Rust lint, all-target compilation, unit/integration tests,
|
|
52
|
+
doctests, and documentation generation. Add `task lint:python` for the Ruff part
|
|
53
|
+
of `task lint`; do not separately repeat `task test:fast`.
|
|
54
|
+
- `task test` runs the full Rust suite. On Windows/macOS, `task test:consolidated`
|
|
55
|
+
runs unit and integration tests with one integration executable, checks examples,
|
|
56
|
+
and runs doctests. It can replace `task test` when linking is costly. An equivalent
|
|
57
|
+
Rust validation slice is `task lint:rust`, `task check`, `task test:consolidated`,
|
|
58
|
+
and `python scripts/ci/lme_ci.py doc`.
|
|
59
|
+
- `task ci` includes Rust, bindings, portable examples, lint, compilation, legal,
|
|
60
|
+
documentation, and completion checks. It does not replace audits/metadata in
|
|
61
|
+
`task preflight`, R/Julia checks, or performance harnesses. `task ci:fast` skips
|
|
62
|
+
the isolated-wheel pass; report that limitation.
|
|
63
|
+
- Reuse passing results for unchanged files/dependencies in the same task. Rerun
|
|
64
|
+
affected checks after edits; broaden when scope or evidence requires it.
|
|
65
|
+
Keep hooks enabled even when they repeat earlier checks.
|
|
66
|
+
- Serialize Cargo commands sharing a target directory. Capture verbose logs and
|
|
67
|
+
inspect exit status and summaries. A timeout or compilation in progress is not a failed test.
|
|
68
|
+
|
|
69
|
+
## Correctness and evidence
|
|
70
|
+
|
|
71
|
+
- Add regression coverage for bug fixes. Prefer statistical identities, explicit
|
|
72
|
+
expected behavior, and independent fixtures over duplicating the implementation.
|
|
73
|
+
- Register new integration test files in [tests/ci_consolidated.rs](tests/ci_consolidated.rs).
|
|
74
|
+
- For R/Julia parity, match rows, formula, family/link, weights, offsets, and ML/REML.
|
|
75
|
+
Explain tolerances; do not loosen them just to make a failure pass.
|
|
76
|
+
- Tie benchmark claims to the revision, environment, and measured cases. Follow
|
|
77
|
+
[BENCHMARKS.md](BENCHMARKS.md) and [OPTIMIZATION.md](OPTIMIZATION.md); a focused
|
|
78
|
+
speedup does not establish general parity or completion.
|
|
79
|
+
|
|
80
|
+
### Completion scores are generated claims
|
|
81
|
+
|
|
82
|
+
[completion_manifest.json](completion_manifest.json) governs the README headline
|
|
83
|
+
and all percentages in [REPO_COMPLETION_BY_AREA.md](REPO_COMPLETION_BY_AREA.md).
|
|
84
|
+
It declares weighted binary commitments, locked `scope` strings, evidence paths,
|
|
85
|
+
and a `gap` for every incomplete criterion.
|
|
86
|
+
|
|
87
|
+
- Complete an item only when its locked scope is met and evidence is current.
|
|
88
|
+
Partial, stale, or substituted evidence earns zero; an API or focused benchmark is insufficient.
|
|
89
|
+
- Do not narrow/replace `scope` to earn credit or edit generated percentages by hand.
|
|
90
|
+
Update the manifest and supporting evidence together.
|
|
91
|
+
- `task completion:check` validates schema version 2, names/scopes/gaps, evidence
|
|
92
|
+
paths, arithmetic, report rows, and the README headline. `task ci` includes it.
|
|
93
|
+
|
|
94
|
+
## Setup and recovery
|
|
95
|
+
|
|
96
|
+
- [mise.toml](mise.toml) configures Rust stable, Python 3.11, uv, Task, and Lefthook.
|
|
97
|
+
Use `task setup` for tools and hooks; run `mise install` first if Task is missing.
|
|
98
|
+
With tools already installed, use `task hooks:install`. Pre-push audits also
|
|
99
|
+
require `cargo-audit` (`cargo install cargo-audit`).
|
|
100
|
+
- For missing PATH entries, use `mise exec -- task <name>`. Locate installed tools
|
|
101
|
+
before reinstalling. Verify subprocess discovery in the actual environment with
|
|
102
|
+
`python -c "import shutil; print(shutil.which('uv'))"` when necessary.
|
|
103
|
+
- Without Task, use `python scripts/ci/lme_ci.py <subcommand>` (`python3` where
|
|
104
|
+
appropriate). Mappings are in [Taskfile.yml](Taskfile.yml): `test:fast` → `test-fast`,
|
|
105
|
+
`rust` → `rust-all`, `lint:python` → `ruff-lint`, `docs:check` → `docs-check`.
|
|
106
|
+
Use `--help` for all commands. Implement new checks in this runner, not duplicate shell logic.
|
|
107
|
+
- For Git dubious ownership, use `git -c safe.directory=C:/path/to/lme-rs <command>`
|
|
108
|
+
with this checkout's absolute forward-slash path; do not trust all directories globally.
|
|
109
|
+
- x86_64 builds link static Intel MKL via `ndarray-linalg`; first builds can be slow.
|
|
110
|
+
Run numerical examples with `--release`, e.g. `cargo run --release --locked --example sleepstudy`.
|
|
111
|
+
Leave the CI runner's own build profiles unchanged.
|
|
112
|
+
- Windows linker errors `LNK1318`/`LNK1106` can indicate disk exhaustion. Check space
|
|
113
|
+
and active builds first. Before cleaning, verify the target belongs to this checkout
|
|
114
|
+
and no build uses it; avoid broad cache deletion.
|
|
115
|
+
- `uv sync` can uninstall the editable Python extension. Restore it from `python/`
|
|
116
|
+
with `uv run --no-sync maturin develop --release`, or rerun `task python`.
|
|
117
|
+
Run Python examples there with `uv run --no-sync python examples/<name>.py`.
|
|
118
|
+
|
|
119
|
+
## Git, hooks, and release boundaries
|
|
120
|
+
|
|
121
|
+
- Follow the user's commit/push scope; commit authorization alone does not authorize
|
|
122
|
+
pushing. When already authorized, complete validation and delivery without asking again.
|
|
123
|
+
- For requested updates, fetch before comparing branches; fast-forward only when
|
|
124
|
+
ancestry and local changes permit it. After pushing, verify HEAD, the tracking ref,
|
|
125
|
+
and live remote branch SHA agree, and report remaining local changes.
|
|
126
|
+
- Lefthook checks matching staged files: Rust format/Clippy, Python Ruff, comparison
|
|
127
|
+
formatting, manifests, benchmarks/dashboard, and metadata. Hooks may auto-stage
|
|
128
|
+
formatting; inspect the result. They do not run full Rust/bindings suites or `pip-audit`.
|
|
129
|
+
- Pre-push runs `task preflight`: lint, all-target compilation, Cargo audits,
|
|
130
|
+
legal/provenance, and metadata validation. Use `--no-verify` only when explicitly
|
|
131
|
+
necessary; report the bypass and omitted checks.
|
|
132
|
+
- Hosted validation runs on PRs, `v*` tags, and manual dispatch, not ordinary branch
|
|
133
|
+
pushes. Cache-prime is not validation. Hosted coverage adds the OS/Python matrix,
|
|
134
|
+
production-load gates, and `pip-audit`; PRs skip the four heavy ignored cases.
|
|
135
|
+
- Inspect the exact failing CI job/log before changing code. Do not merge with a
|
|
136
|
+
failing security audit. For metadata authentication, use `REPO_ADMIN_TOKEN` with
|
|
137
|
+
`task repo-metadata`; a hosted `401` requires checking/rotating the Actions secret.
|
|
138
|
+
- Preserve full-SHA action pins and readable version comments. After BLAS target-table
|
|
139
|
+
or release-workflow changes, run `task ci` or manually dispatch CI before tagging;
|
|
140
|
+
Windows/Linux cannot validate macOS Apple Silicon BLAS.
|
|
141
|
+
- Tag CI gates crates.io publishing and dispatches PyPI only after validation succeeds.
|
|
142
|
+
Keep PyPI top-level for Trusted Publishing attestations; publishing workflows must
|
|
143
|
+
not independently listen to tags. Read [RELEASING.md](RELEASING.md) before releases.
|
|
144
|
+
- R/Julia benchmark workflow coverage belongs in tag/manual runs. `task benchmarks:preflight`
|
|
145
|
+
includes Rust smoke and R smoke when R/lme4 is installed. Optional tool skips are not passes.
|
|
146
|
+
|
|
147
|
+
See [CONTRIBUTING.md](CONTRIBUTING.md) for extended guidance and
|
|
148
|
+
[Taskfile.yml](Taskfile.yml) for less common commands.
|
|
@@ -1,8 +1,38 @@
|
|
|
1
|
-
#
|
|
1
|
+
# Benchmark guide and measurement history
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
[Documentation](docs/README.md) · [Coverage map](BENCHMARK_COVERAGE.md) · [Optimization notes](OPTIMIZATION.md) · [Dashboard](https://x4g4p3x.github.io/lme-rs/benchmarks/)
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
Choose a harness by the question you want to answer. Numerical parity and
|
|
6
|
+
throughput are separate forms of evidence.
|
|
7
|
+
|
|
8
|
+
## Choose a benchmark
|
|
9
|
+
|
|
10
|
+
| Question | Command | What is timed |
|
|
11
|
+
|:---------|:--------|:--------------|
|
|
12
|
+
| Did a Rust operation regress? | `cargo bench --locked --bench bench_math` | Criterion operations, fit paths, and inference |
|
|
13
|
+
| How does matched fitting compare with Julia? | `task benchmarks:fair-rust-julia` | Fit-only medians with shared inputs and warmups |
|
|
14
|
+
| Where is fitting time spent? | `task benchmarks:perf-breakdown` | Rust phases and Julia optimizer evaluations |
|
|
15
|
+
| What do R inference/NLMM and Python overhead cost? | `task benchmarks:external-timings` | Operations supported by the external harness |
|
|
16
|
+
| Do cross-language example scripts run? | `python scripts/run_cross_language_benchmarks.py` | Whole scripts, including runtime startup |
|
|
17
|
+
| Does the dashboard match its source JSON? | `task docs:check` | Data drift validation, not a new measurement |
|
|
18
|
+
|
|
19
|
+
Run from the repository root. External harnesses require their reference
|
|
20
|
+
runtimes and packages; a skipped implementation is not a measured comparison.
|
|
21
|
+
See [the coverage map](BENCHMARK_COVERAGE.md#running-benchmarks) for setup.
|
|
22
|
+
|
|
23
|
+
## Reading order
|
|
24
|
+
|
|
25
|
+
- [Suite coverage](#current-benchmark-coverage) and [remaining gaps](#what-it-does-not-cover-yet)
|
|
26
|
+
- [Methodology](#cross-language-benchmark-methodology)
|
|
27
|
+
- [Commands](#how-to-run-the-benchmarks)
|
|
28
|
+
- [Fair reference results](#fair-rust-vs-julia-reference-results)
|
|
29
|
+
- [Published artifacts](#latest-published-results)
|
|
30
|
+
- [Interpretation](#how-to-interpret-results)
|
|
31
|
+
|
|
32
|
+
The detailed experiments below are **dated measurement history**. A wording
|
|
33
|
+
update does not rerun them. The July 22 reference contains 10 LMM and 2 GLMM
|
|
34
|
+
cases; later GLMM fitting changes mean its GLMM rows cannot establish current
|
|
35
|
+
performance. Hardware, revision, BLAS, and timing boundaries matter.
|
|
6
36
|
|
|
7
37
|
## Native formula parser optimization (2026-08-10)
|
|
8
38
|
|
|
@@ -76,19 +106,24 @@ What the repo still does not provide is a fully normalized cross-ecosystem harne
|
|
|
76
106
|
It does not yet isolate or compare:
|
|
77
107
|
|
|
78
108
|
- prediction throughput on large crossed and nested structures
|
|
79
|
-
- weighted GLMM
|
|
109
|
+
- weighted GLMM throughput across representative model sizes
|
|
80
110
|
- GLMM inference and post-fit helper costs beyond the currently benchmarked paths
|
|
81
111
|
- confidence interval and simulation throughput across multiple model sizes
|
|
82
112
|
|
|
83
113
|
### Missing benchmark dimensions
|
|
84
114
|
|
|
85
|
-
|
|
115
|
+
The Rust suite already includes parameterized observation/group-count and
|
|
116
|
+
nested/crossed complexity sweeps. It does not provide a complete factorial
|
|
117
|
+
comparison across every combination of:
|
|
118
|
+
|
|
119
|
+
- response family and link
|
|
120
|
+
- random-effect dimension and correlation structure
|
|
121
|
+
- dense-like versus sparse-like layouts
|
|
122
|
+
- prediction, simulation, and inference workloads
|
|
123
|
+
- reference language and optimizer configuration
|
|
86
124
|
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
- random intercept vs random slope structure
|
|
90
|
-
- family and link combinations
|
|
91
|
-
- dense-like vs sparse-like random-effect structure
|
|
125
|
+
Use a named case that represents your workload rather than inferring coverage
|
|
126
|
+
from the existence of one large synthetic benchmark.
|
|
92
127
|
|
|
93
128
|
## Cross-language benchmark methodology
|
|
94
129
|
|
|
@@ -230,7 +265,7 @@ Work on [`src/math.rs`](src/math.rs) and [`src/optimizer.rs`](src/optimizer.rs):
|
|
|
230
265
|
|
|
231
266
|
### 2026-07-08 blocked augmented Cholesky (MixedModels-style)
|
|
232
267
|
|
|
233
|
-
Implemented [`src/intercept_blocked.rs`](src/intercept_blocked.rs): precomputed per-RE Gram blocks, RE ordering by level count, and per-θ **blocked Cholesky** in the layout of MixedModels.jl [`updateL!`](https://github.com/JuliaStats/MixedModels.jl/blob/main/src/linearmixedmodel.jl) — profile deviance from the factored `Xy` block **without** q-dimensional LDL solves or explicit β on the hot path. Full write-up: **[OPTIMIZATION.md § Blocked augmented Cholesky](OPTIMIZATION.md#blocked-augmented-cholesky
|
|
268
|
+
Implemented [`src/intercept_blocked.rs`](src/intercept_blocked.rs): precomputed per-RE Gram blocks, RE ordering by level count, and per-θ **blocked Cholesky** in the layout of MixedModels.jl [`updateL!`](https://github.com/JuliaStats/MixedModels.jl/blob/main/src/linearmixedmodel.jl) — profile deviance from the factored `Xy` block **without** q-dimensional LDL solves or explicit β on the hot path. Full write-up: **[OPTIMIZATION.md § Blocked augmented Cholesky](OPTIMIZATION.md#blocked-augmented-cholesky)**.
|
|
234
269
|
|
|
235
270
|
**Recorded:** 2026-07-08, same Windows AMD64 workstation; `rustc 1.96.0`; 2 warmups + 10 measured fits (`scripts/run_fair_rust_julia_benchmark.py --implementations rust`).
|
|
236
271
|
|
|
@@ -246,7 +281,7 @@ Implemented [`src/intercept_blocked.rs`](src/intercept_blocked.rs): precomputed
|
|
|
246
281
|
|
|
247
282
|
### 2026-07-08 blocked Cholesky hot-path pass
|
|
248
283
|
|
|
249
|
-
Removed per-θ **clone/alloc** overhead in [`src/intercept_blocked.rs`](src/intercept_blocked.rs) (in-place Schur, fused `assign_scaled`, reused workspaces) and tightened the ML 2D log-grid to **5×5 + 4×4** (~42 evals). Nested sparse crosses remain on reused LDL (`fits_blocked_gate`). Details: **[OPTIMIZATION.md § Closing the crossed_20k gap](OPTIMIZATION.md#
|
|
284
|
+
Removed per-θ **clone/alloc** overhead in [`src/intercept_blocked.rs`](src/intercept_blocked.rs) (in-place Schur, fused `assign_scaled`, reused workspaces) and tightened the ML 2D log-grid to **5×5 + 4×4** (~42 evals). Nested sparse crosses remain on reused LDL (`fits_blocked_gate`). Details: **[OPTIMIZATION.md § Closing the crossed_20k gap](OPTIMIZATION.md#progress-timeline)**.
|
|
250
285
|
|
|
251
286
|
**Recorded:** 2026-07-08, same Windows AMD64 workstation; `rustc 1.96.0`; 2 warmups + 10 measured fits (`--implementations rust`).
|
|
252
287
|
|
|
@@ -262,7 +297,7 @@ Removed per-θ **clone/alloc** overhead in [`src/intercept_blocked.rs`](src/inte
|
|
|
262
297
|
|
|
263
298
|
### 2026-07-08 GEMM, batched trisolve, and prepared fit
|
|
264
299
|
|
|
265
|
-
Further blocked-kernel tuning in [`src/intercept_blocked.rs`](src/intercept_blocked.rs) plus **`prepare_lmer` / `fit_prepared`** in [`src/lib.rs`](src/lib.rs). Full write-up: **[OPTIMIZATION.md § Blocked kernel tuning](OPTIMIZATION.md#blocked-kernel-tuning
|
|
300
|
+
Further blocked-kernel tuning in [`src/intercept_blocked.rs`](src/intercept_blocked.rs) plus **`prepare_lmer` / `fit_prepared`** in [`src/lib.rs`](src/lib.rs). Full write-up: **[OPTIMIZATION.md § Blocked kernel tuning](OPTIMIZATION.md#blocked-kernel-tuning)**.
|
|
266
301
|
|
|
267
302
|
**Recorded:** 2026-07-08, same Windows AMD64 workstation; `rustc 1.96.0`; `bench_perf_breakdown` with 1 warmup + measured `fit_prepared`.
|
|
268
303
|
|
|
@@ -433,9 +468,12 @@ The repository also includes a dedicated workflow in [.github/workflows/benchmar
|
|
|
433
468
|
- runs the cross-language example-script benchmark
|
|
434
469
|
- uploads the resulting artifacts in CI
|
|
435
470
|
- attaches them to GitHub Releases on tag pushes
|
|
471
|
+
- publishes the fair-harness dashboard to GitHub Pages at [`https://x4g4p3x.github.io/lme-rs/benchmarks/`](https://x4g4p3x.github.io/lme-rs/benchmarks/)
|
|
436
472
|
|
|
437
473
|
## Latest published results
|
|
438
474
|
|
|
475
|
+
The public dashboard at [`https://x4g4p3x.github.io/lme-rs/benchmarks/`](https://x4g4p3x.github.io/lme-rs/benchmarks/) charts the checked-in fair Rust vs MixedModels.jl reference plus the Julia-free external timings. Tag/manual [benchmark workflow](.github/workflows/benchmarks.yml) runs can overlay GitHub-hosted runner JSON. Rebuild the committed payload with `task benchmarks:site` after changing a reference file.
|
|
476
|
+
|
|
439
477
|
Release-attached Criterion and cross-language JSON artifacts are uploaded by [`.github/workflows/benchmarks.yml`](.github/workflows/benchmarks.yml) on `v*` tags (and manual dispatch). Prefer the [latest GitHub Release](https://github.com/x4g4p3x/lme-rs/releases/latest) for downloadable CI artifacts, and [`CHANGELOG.md`](CHANGELOG.md) for which crate version each tag ships.
|
|
440
478
|
|
|
441
479
|
**Engineering source of truth for fair Rust vs Julia fit timing** is the checked-in reference JSON under [`benchmarks/`](benchmarks/), especially the full strict-target [2026-07-22 tier-A artifact](benchmarks/fair-rust-julia-reference-2026-07-22-full-tier-a.json). Older tags (for example [v0.1.3](https://github.com/x4g4p3x/lme-rs/releases/tag/v0.1.3)) still carry historical CI tarballs useful for release-to-release comparison, but they are **not** the current performance baseline.
|
|
@@ -453,15 +491,24 @@ If you want to cite benchmark results in release notes or external docs, prefer
|
|
|
453
491
|
|
|
454
492
|
## How to interpret results
|
|
455
493
|
|
|
456
|
-
|
|
494
|
+
Compare medians from the same machine, model, and measurement boundary.
|
|
457
495
|
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
496
|
+
| Metric | Includes | Appropriate use |
|
|
497
|
+
|:-------|:---------|:----------------|
|
|
498
|
+
| `cold_fit` | One fit including its setup | One-shot API latency |
|
|
499
|
+
| `prepare_lmer` | Reusable design construction | Setup cost |
|
|
500
|
+
| `fit_prepared` | Fitting a cached design | Repeated fixed-design work |
|
|
501
|
+
| Whole-script elapsed time | Startup, I/O, setup, fitting, and printed output | End-to-end script cost |
|
|
502
|
+
| Criterion operation | The operation selected by the benchmark | Within-Rust regression tracking |
|
|
461
503
|
|
|
462
|
-
|
|
504
|
+
A Rust/Julia ratio below 1 means Rust was faster for that measured row.
|
|
505
|
+
Do not compare a hot prepared fit to a competitor's full process startup.
|
|
463
506
|
|
|
464
|
-
The
|
|
507
|
+
The historical sections document how earlier crossed and nested bottlenecks
|
|
508
|
+
were reduced. They are not predictions for every model shape. The
|
|
509
|
+
[July 22 artifact](benchmarks/fair-rust-julia-reference-2026-07-22-full-tier-a.json)
|
|
510
|
+
and [coverage map](BENCHMARK_COVERAGE.md) are the concise entry points to that
|
|
511
|
+
reference set. Re-run after relevant code changes before making a new claim.
|
|
465
512
|
|
|
466
513
|
## Recommended next extensions
|
|
467
514
|
|
|
@@ -473,15 +520,12 @@ If performance is going to remain a central public claim, the benchmark suite sh
|
|
|
473
520
|
4. More explicit GLMM post-fit benchmarks beyond fitting, prediction, and Wald intervals.
|
|
474
521
|
5. Benchmarks that isolate optimizer iteration cost separately from formula parsing and matrix construction.
|
|
475
522
|
|
|
476
|
-
##
|
|
477
|
-
|
|
478
|
-
The current benchmarking is meaningful, but not comprehensive.
|
|
523
|
+
## Maintaining performance claims
|
|
479
524
|
|
|
480
|
-
|
|
525
|
+
Use Criterion as a regression guard and the fair harness for external timing.
|
|
526
|
+
Keep raw artifacts, case names, code revision, environment, and methodology
|
|
527
|
+
with each claim. Refresh only the evidence affected by a change.
|
|
481
528
|
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
- no, Julia bindings to `lme-rs` are not justified by speed — see [fair Rust vs Julia results](BENCHMARKS.md#fair-rust-vs-julia-reference-results)
|
|
486
|
-
- yes, run benchmarks for performance-sensitive changes before release
|
|
487
|
-
- yes, extend the benchmark surface (GLMM fit-only, prediction sweeps) as optimization work proceeds
|
|
529
|
+
Completion thresholds are governed by [the locked manifest](completion_manifest.json)
|
|
530
|
+
and [coverage policy](BENCHMARK_COVERAGE.md). A faster microbenchmark or revised
|
|
531
|
+
description alone does not satisfy a broader completion criterion.
|