lme-python 0.2.2__tar.gz → 0.2.3__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.3/.github/FUNDING.yml +1 -0
- {lme_python-0.2.2 → lme_python-0.2.3}/.github/workflows/audit.yml +2 -2
- {lme_python-0.2.2 → lme_python-0.2.3}/.github/workflows/benchmarks.yml +76 -0
- {lme_python-0.2.2 → lme_python-0.2.3}/.github/workflows/cache-prime.yml +3 -3
- {lme_python-0.2.2 → lme_python-0.2.3}/.github/workflows/ci.yml +9 -7
- {lme_python-0.2.2 → lme_python-0.2.3}/.github/workflows/fuzz-smoke.yml +1 -1
- lme_python-0.2.3/.github/workflows/pages.yml +56 -0
- {lme_python-0.2.2 → lme_python-0.2.3}/.github/workflows/python-release.yml +1 -1
- {lme_python-0.2.2 → lme_python-0.2.3}/AGENTS.md +6 -5
- {lme_python-0.2.2 → lme_python-0.2.3}/BENCHMARKS.md +73 -29
- {lme_python-0.2.2 → lme_python-0.2.3}/BENCHMARK_COVERAGE.md +17 -9
- {lme_python-0.2.2 → lme_python-0.2.3}/CHANGELOG.md +53 -1
- {lme_python-0.2.2 → lme_python-0.2.3}/CI_PERFORMANCE.md +7 -1
- lme_python-0.2.3/CONTRIBUTING.md +226 -0
- {lme_python-0.2.2 → lme_python-0.2.3}/Cargo.lock +1 -1
- {lme_python-0.2.2 → lme_python-0.2.3}/Cargo.toml +1 -1
- {lme_python-0.2.2 → lme_python-0.2.3}/GUIDE.md +100 -41
- {lme_python-0.2.2 → lme_python-0.2.3}/OPTIMIZATION.md +88 -4
- lme_python-0.2.3/PKG-INFO +127 -0
- lme_python-0.2.3/README.md +220 -0
- lme_python-0.2.3/RELEASING.md +157 -0
- lme_python-0.2.3/REPO_COMPLETION_BY_AREA.md +132 -0
- {lme_python-0.2.2 → lme_python-0.2.3}/Taskfile.yml +10 -0
- lme_python-0.2.3/USABILITY.md +110 -0
- lme_python-0.2.3/benchmarks/fair-rust-julia-reference-2026-09-09-refactor.json +1693 -0
- lme_python-0.2.3/benchmarks/refactor-2026-09-09.json +1854 -0
- {lme_python-0.2.2 → lme_python-0.2.3}/comparisons/COMPARISONS.md +25 -4
- lme_python-0.2.3/completion_manifest.json +159 -0
- lme_python-0.2.3/docs/CALO_CALIBRATION.md +98 -0
- lme_python-0.2.3/docs/EXAMPLES.md +86 -0
- lme_python-0.2.3/docs/README.md +69 -0
- lme_python-0.2.3/docs/TROUBLESHOOTING.md +91 -0
- lme_python-0.2.3/docs/benchmarks/app.js +397 -0
- lme_python-0.2.3/docs/benchmarks/data/latest.json +834 -0
- lme_python-0.2.3/docs/benchmarks/index.html +133 -0
- {lme_python-0.2.2 → lme_python-0.2.3}/docs/benchmarks/styles.css +62 -3
- {lme_python-0.2.2 → lme_python-0.2.3}/docs/index.html +1 -1
- {lme_python-0.2.2 → lme_python-0.2.3}/lefthook.yml +4 -0
- lme_python-0.2.3/lme-rs-icon.png +0 -0
- lme_python-0.2.3/lme-rs.png +0 -0
- {lme_python-0.2.2 → lme_python-0.2.3}/python/Cargo.lock +2 -2
- {lme_python-0.2.2 → lme_python-0.2.3}/python/Cargo.toml +1 -1
- {lme_python-0.2.2 → lme_python-0.2.3}/python/PYTHON_GUIDE.md +163 -112
- lme_python-0.2.3/python/README.md +104 -0
- lme_python-0.2.3/python/examples/plotting_demo/README.md +101 -0
- lme_python-0.2.3/python/examples/verification_project/README.md +51 -0
- {lme_python-0.2.2 → lme_python-0.2.3}/python/lme_python.pyi +48 -10
- lme_python-0.2.3/python/src/controls.rs +61 -0
- lme_python-0.2.3/python/src/fitting.rs +597 -0
- lme_python-0.2.3/python/src/input.rs +107 -0
- {lme_python-0.2.2 → lme_python-0.2.3}/python/src/lib.rs +131 -727
- lme_python-0.2.3/python/tests/test_model_contracts.py +133 -0
- {lme_python-0.2.2 → lme_python-0.2.3}/python/uv.lock +4 -4
- lme_python-0.2.3/scripts/build_benchmark_site.py +508 -0
- lme_python-0.2.3/scripts/ci/README.md +55 -0
- {lme_python-0.2.2 → lme_python-0.2.3}/scripts/ci/check_completion_score.py +36 -3
- {lme_python-0.2.2 → lme_python-0.2.3}/scripts/ci/lme_ci.py +76 -1
- {lme_python-0.2.2 → lme_python-0.2.3}/scripts/explorations/README.md +5 -1
- {lme_python-0.2.2 → lme_python-0.2.3}/src/bootstrap.rs +107 -102
- {lme_python-0.2.2 → lme_python-0.2.3}/src/contrast.rs +38 -24
- {lme_python-0.2.2 → lme_python-0.2.3}/src/cv.rs +31 -85
- lme_python-0.2.3/src/display.rs +283 -0
- {lme_python-0.2.2 → lme_python-0.2.3}/src/emmeans.rs +3 -3
- lme_python-0.2.3/src/execution.rs +48 -0
- {lme_python-0.2.2 → lme_python-0.2.3}/src/formula.rs +2 -1
- {lme_python-0.2.2 → lme_python-0.2.3}/src/glmm_math.rs +149 -74
- {lme_python-0.2.2 → lme_python-0.2.3}/src/intercept_blocked.rs +19 -0
- lme_python-0.2.3/src/kenward_roger.rs +81 -0
- {lme_python-0.2.2 → lme_python-0.2.3}/src/kr_modcomp.rs +24 -45
- {lme_python-0.2.2 → lme_python-0.2.3}/src/kr_vcov_adj.rs +7 -12
- {lme_python-0.2.2 → lme_python-0.2.3}/src/lib.rs +218 -560
- {lme_python-0.2.2 → lme_python-0.2.3}/src/math.rs +99 -84
- {lme_python-0.2.2 → lme_python-0.2.3}/src/mcp.rs +2 -2
- lme_python-0.2.3/src/model.rs +240 -0
- {lme_python-0.2.2 → lme_python-0.2.3}/src/model_matrix.rs +62 -60
- lme_python-0.2.3/src/nlmm/block_solve.rs +132 -0
- {lme_python-0.2.2 → lme_python-0.2.3}/src/nlmm/fit.rs +263 -140
- {lme_python-0.2.2 → lme_python-0.2.3}/src/nlmm/mod.rs +1 -0
- lme_python-0.2.3/src/ols.rs +33 -0
- {lme_python-0.2.2 → lme_python-0.2.3}/src/optimizer.rs +138 -101
- lme_python-0.2.3/src/predict.rs +179 -0
- lme_python-0.2.3/src/prepared.rs +76 -0
- {lme_python-0.2.2 → lme_python-0.2.3}/src/profile_ci.rs +6 -11
- {lme_python-0.2.2 → lme_python-0.2.3}/src/robust.rs +16 -1
- {lme_python-0.2.2 → lme_python-0.2.3}/src/satterthwaite.rs +2 -9
- {lme_python-0.2.2 → lme_python-0.2.3}/src/simulate.rs +18 -17
- {lme_python-0.2.2 → lme_python-0.2.3}/tests/ci_consolidated.rs +9 -0
- {lme_python-0.2.2 → lme_python-0.2.3}/tests/test_anova.rs +1 -0
- lme_python-0.2.3/tests/test_bug_hunt.rs +353 -0
- lme_python-0.2.3/tests/test_bug_hunt_more.rs +212 -0
- lme_python-0.2.3/tests/test_bug_hunt_numerics.rs +287 -0
- {lme_python-0.2.2 → lme_python-0.2.3}/tests/test_coverage_gaps.rs +2 -1
- {lme_python-0.2.2 → lme_python-0.2.3}/tests/test_failure_modes.rs +14 -14
- {lme_python-0.2.2 → lme_python-0.2.3}/tests/test_formula_stress.rs +1 -0
- lme_python-0.2.3/tests/test_model_contracts.rs +333 -0
- {lme_python-0.2.2 → lme_python-0.2.3}/tests/test_predict.rs +4 -3
- 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.3}/.JuliaFormatter.toml +0 -0
- {lme_python-0.2.2 → lme_python-0.2.3}/.github/dependabot.yml +0 -0
- {lme_python-0.2.2 → lme_python-0.2.3}/.github/workflows/crate-publish-dry-run.yml +0 -0
- {lme_python-0.2.2 → lme_python-0.2.3}/.github/workflows/repo-metadata.yml +0 -0
- {lme_python-0.2.2 → lme_python-0.2.3}/.gitignore +0 -0
- {lme_python-0.2.2 → lme_python-0.2.3}/LICENSE +0 -0
- {lme_python-0.2.2 → lme_python-0.2.3}/LICENSES/Apache-2.0.txt +0 -0
- {lme_python-0.2.2 → lme_python-0.2.3}/LICENSES/BSD-3-Clause-OpenBLAS.txt +0 -0
- {lme_python-0.2.2 → lme_python-0.2.3}/LICENSES/GPL-2.0-or-later.txt +0 -0
- {lme_python-0.2.2 → lme_python-0.2.3}/LICENSES/Intel-Simplified-Software-License.txt +0 -0
- {lme_python-0.2.2 → lme_python-0.2.3}/LICENSES/LGPL-2.1-only.txt +0 -0
- {lme_python-0.2.2 → lme_python-0.2.3}/RELINKING.md +0 -0
- {lme_python-0.2.2 → lme_python-0.2.3}/THIRD_PARTY_NOTICES.md +0 -0
- {lme_python-0.2.2 → lme_python-0.2.3}/benches/bench_load_production.rs +0 -0
- {lme_python-0.2.2 → lme_python-0.2.3}/benches/bench_math.rs +0 -0
- {lme_python-0.2.2 → lme_python-0.2.3}/benchmarks/external-nlmm-inference-python-timings-2026-08-14.json +0 -0
- {lme_python-0.2.2 → lme_python-0.2.3}/benchmarks/fair-rust-julia-reference-2026-07-04.json +0 -0
- {lme_python-0.2.2 → lme_python-0.2.3}/benchmarks/fair-rust-julia-reference-2026-07-06.json +0 -0
- {lme_python-0.2.2 → lme_python-0.2.3}/benchmarks/fair-rust-julia-reference-2026-07-08.json +0 -0
- {lme_python-0.2.2 → lme_python-0.2.3}/benchmarks/fair-rust-julia-reference-2026-07-09-direct-intercept-gram.json +0 -0
- {lme_python-0.2.2 → lme_python-0.2.3}/benchmarks/fair-rust-julia-reference-2026-07-09-full-lmm.json +0 -0
- {lme_python-0.2.2 → lme_python-0.2.3}/benchmarks/fair-rust-julia-reference-2026-07-09-glmm.json +0 -0
- {lme_python-0.2.2 → lme_python-0.2.3}/benchmarks/fair-rust-julia-reference-2026-07-09-large-intercept-setup.json +0 -0
- {lme_python-0.2.2 → lme_python-0.2.3}/benchmarks/fair-rust-julia-reference-2026-07-09-large-slopes-linear-cache.json +0 -0
- {lme_python-0.2.2 → lme_python-0.2.3}/benchmarks/fair-rust-julia-reference-2026-07-09-large-slopes.json +0 -0
- {lme_python-0.2.2 → lme_python-0.2.3}/benchmarks/fair-rust-julia-reference-2026-07-09-sleepstudy-slopes.json +0 -0
- {lme_python-0.2.2 → lme_python-0.2.3}/benchmarks/fair-rust-julia-reference-2026-07-09.json +0 -0
- {lme_python-0.2.2 → lme_python-0.2.3}/benchmarks/fair-rust-julia-reference-2026-07-10-cold-setup-followup.json +0 -0
- {lme_python-0.2.2 → lme_python-0.2.3}/benchmarks/fair-rust-julia-reference-2026-07-16-cold-fit-lt1.json +0 -0
- {lme_python-0.2.2 → lme_python-0.2.3}/benchmarks/fair-rust-julia-reference-2026-07-22-full-tier-a.json +0 -0
- {lme_python-0.2.2 → lme_python-0.2.3}/comparisons/bench_external_timings.R +0 -0
- {lme_python-0.2.2 → lme_python-0.2.3}/comparisons/bench_fair_julia_perf.jl +0 -0
- {lme_python-0.2.2 → lme_python-0.2.3}/comparisons/bench_fair_julia_timing.jl +0 -0
- {lme_python-0.2.2 → lme_python-0.2.3}/comparisons/bench_fair_rust_julia.rs +0 -0
- {lme_python-0.2.2 → lme_python-0.2.3}/comparisons/bench_perf_breakdown.rs +0 -0
- {lme_python-0.2.2 → lme_python-0.2.3}/comparisons/categorical_anova.R +0 -0
- {lme_python-0.2.2 → lme_python-0.2.3}/comparisons/categorical_anova.jl +0 -0
- {lme_python-0.2.2 → lme_python-0.2.3}/comparisons/categorical_anova.py +0 -0
- {lme_python-0.2.2 → lme_python-0.2.3}/comparisons/categorical_anova.rs +0 -0
- {lme_python-0.2.2 → lme_python-0.2.3}/comparisons/comparison_chart.png +0 -0
- {lme_python-0.2.2 → lme_python-0.2.3}/comparisons/glmm_cbpp.R +0 -0
- {lme_python-0.2.2 → lme_python-0.2.3}/comparisons/glmm_cbpp.jl +0 -0
- {lme_python-0.2.2 → lme_python-0.2.3}/comparisons/glmm_cbpp.py +0 -0
- {lme_python-0.2.2 → lme_python-0.2.3}/comparisons/glmm_cbpp.rs +0 -0
- {lme_python-0.2.2 → lme_python-0.2.3}/comparisons/glmm_gaussian.R +0 -0
- {lme_python-0.2.2 → lme_python-0.2.3}/comparisons/glmm_gaussian.jl +0 -0
- {lme_python-0.2.2 → lme_python-0.2.3}/comparisons/glmm_gaussian.py +0 -0
- {lme_python-0.2.2 → lme_python-0.2.3}/comparisons/glmm_gaussian.rs +0 -0
- {lme_python-0.2.2 → lme_python-0.2.3}/comparisons/glmm_grouseticks.R +0 -0
- {lme_python-0.2.2 → lme_python-0.2.3}/comparisons/glmm_grouseticks.jl +0 -0
- {lme_python-0.2.2 → lme_python-0.2.3}/comparisons/glmm_grouseticks.py +0 -0
- {lme_python-0.2.2 → lme_python-0.2.3}/comparisons/glmm_grouseticks.rs +0 -0
- {lme_python-0.2.2 → lme_python-0.2.3}/comparisons/lmer_weighted.R +0 -0
- {lme_python-0.2.2 → lme_python-0.2.3}/comparisons/lmer_weighted.jl +0 -0
- {lme_python-0.2.2 → lme_python-0.2.3}/comparisons/lmer_weighted.py +0 -0
- {lme_python-0.2.2 → lme_python-0.2.3}/comparisons/lmer_weighted.rs +0 -0
- {lme_python-0.2.2 → lme_python-0.2.3}/comparisons/lmm_dyestuff.R +0 -0
- {lme_python-0.2.2 → lme_python-0.2.3}/comparisons/lmm_dyestuff.jl +0 -0
- {lme_python-0.2.2 → lme_python-0.2.3}/comparisons/lmm_dyestuff.py +0 -0
- {lme_python-0.2.2 → lme_python-0.2.3}/comparisons/lmm_dyestuff.rs +0 -0
- {lme_python-0.2.2 → lme_python-0.2.3}/comparisons/lmm_pastes.R +0 -0
- {lme_python-0.2.2 → lme_python-0.2.3}/comparisons/lmm_pastes.jl +0 -0
- {lme_python-0.2.2 → lme_python-0.2.3}/comparisons/lmm_pastes.py +0 -0
- {lme_python-0.2.2 → lme_python-0.2.3}/comparisons/lmm_pastes.rs +0 -0
- {lme_python-0.2.2 → lme_python-0.2.3}/comparisons/lmm_penicillin.R +0 -0
- {lme_python-0.2.2 → lme_python-0.2.3}/comparisons/lmm_penicillin.jl +0 -0
- {lme_python-0.2.2 → lme_python-0.2.3}/comparisons/lmm_penicillin.py +0 -0
- {lme_python-0.2.2 → lme_python-0.2.3}/comparisons/lmm_penicillin.rs +0 -0
- {lme_python-0.2.2 → lme_python-0.2.3}/comparisons/nlmm_sspower.R +0 -0
- {lme_python-0.2.2 → lme_python-0.2.3}/comparisons/parity/glmm_offset.R +0 -0
- {lme_python-0.2.2 → lme_python-0.2.3}/comparisons/parity/glmm_offset.jl +0 -0
- {lme_python-0.2.2 → lme_python-0.2.3}/comparisons/parity/glmm_probit.R +0 -0
- {lme_python-0.2.2 → lme_python-0.2.3}/comparisons/parity/glmm_probit.jl +0 -0
- {lme_python-0.2.2 → lme_python-0.2.3}/comparisons/parity/glmm_weighted.R +0 -0
- {lme_python-0.2.2 → lme_python-0.2.3}/comparisons/parity/glmm_weighted.jl +0 -0
- {lme_python-0.2.2 → lme_python-0.2.3}/comparisons/parity/parity_r_setup.R +0 -0
- {lme_python-0.2.2 → lme_python-0.2.3}/comparisons/parity/sleepstudy_offset.R +0 -0
- {lme_python-0.2.2 → lme_python-0.2.3}/comparisons/parity/sleepstudy_offset.jl +0 -0
- {lme_python-0.2.2 → lme_python-0.2.3}/comparisons/parity_export.rs +0 -0
- {lme_python-0.2.2 → lme_python-0.2.3}/comparisons/pastes_emmeans.R +0 -0
- {lme_python-0.2.2 → lme_python-0.2.3}/comparisons/pastes_glht.R +0 -0
- {lme_python-0.2.2 → lme_python-0.2.3}/comparisons/r_setup.R +0 -0
- {lme_python-0.2.2 → lme_python-0.2.3}/comparisons/sleepstudy.R +0 -0
- {lme_python-0.2.2 → lme_python-0.2.3}/comparisons/sleepstudy.jl +0 -0
- {lme_python-0.2.2 → lme_python-0.2.3}/comparisons/sleepstudy.py +0 -0
- {lme_python-0.2.2 → lme_python-0.2.3}/comparisons/sleepstudy.rs +0 -0
- {lme_python-0.2.2 → lme_python-0.2.3}/comparisons/sleepstudy_confint_profile.R +0 -0
- {lme_python-0.2.2 → lme_python-0.2.3}/comparisons/sleepstudy_ml.R +0 -0
- {lme_python-0.2.2 → lme_python-0.2.3}/comparisons/sleepstudy_ml.jl +0 -0
- {lme_python-0.2.2 → lme_python-0.2.3}/comparisons/sleepstudy_ml.py +0 -0
- {lme_python-0.2.2 → lme_python-0.2.3}/comparisons/sleepstudy_ml.rs +0 -0
- {lme_python-0.2.2 → lme_python-0.2.3}/examples/batch_sspower_cpu.rs +0 -0
- {lme_python-0.2.2 → lme_python-0.2.3}/examples/bench_external_timings.rs +0 -0
- {lme_python-0.2.2 → lme_python-0.2.3}/examples/dump_cascade_fixtures.rs +0 -0
- {lme_python-0.2.2 → lme_python-0.2.3}/examples/explore_formula_ast.rs +0 -0
- {lme_python-0.2.2 → lme_python-0.2.3}/examples/explore_mcp_adjust.rs +0 -0
- {lme_python-0.2.2 → lme_python-0.2.3}/examples/explore_theta_grid.rs +0 -0
- {lme_python-0.2.2 → lme_python-0.2.3}/examples/nlmm_fixture_dump.rs +0 -0
- {lme_python-0.2.2 → lme_python-0.2.3}/legal/dependency-license-exceptions.json +0 -0
- {lme_python-0.2.2 → lme_python-0.2.3}/legal/fixture-provenance.json +0 -0
- {lme_python-0.2.2 → lme_python-0.2.3}/mise.toml +0 -0
- {lme_python-0.2.2 → lme_python-0.2.3}/pyproject.toml +0 -0
- {lme_python-0.2.2 → lme_python-0.2.3}/python/examples/glmer_cbpp.py +0 -0
- {lme_python-0.2.2 → lme_python-0.2.3}/python/examples/glmer_grouseticks.py +0 -0
- {lme_python-0.2.2 → lme_python-0.2.3}/python/examples/lm_basics.py +0 -0
- {lme_python-0.2.2 → lme_python-0.2.3}/python/examples/lmer_sleepstudy.py +0 -0
- {lme_python-0.2.2 → lme_python-0.2.3}/python/examples/model_comparison.py +0 -0
- {lme_python-0.2.2 → lme_python-0.2.3}/python/examples/plotting_demo/.gitignore +0 -0
- {lme_python-0.2.2 → lme_python-0.2.3}/python/examples/plotting_demo/compare_plots.py +0 -0
- {lme_python-0.2.2 → lme_python-0.2.3}/python/examples/plotting_demo/figure_specs.py +0 -0
- {lme_python-0.2.2 → lme_python-0.2.3}/python/examples/plotting_demo/find_rscript.py +0 -0
- {lme_python-0.2.2 → lme_python-0.2.3}/python/examples/plotting_demo/numeric_overlay.py +0 -0
- {lme_python-0.2.2 → lme_python-0.2.3}/python/examples/plotting_demo/paths.py +0 -0
- {lme_python-0.2.2 → lme_python-0.2.3}/python/examples/plotting_demo/plot_demo.py +0 -0
- {lme_python-0.2.2 → lme_python-0.2.3}/python/examples/plotting_demo/plot_r.R +0 -0
- {lme_python-0.2.2 → lme_python-0.2.3}/python/examples/plotting_demo/run_all.py +0 -0
- {lme_python-0.2.2 → lme_python-0.2.3}/python/examples/verification_project/conftest.py +0 -0
- {lme_python-0.2.2 → lme_python-0.2.3}/python/examples/verification_project/parity.py +0 -0
- {lme_python-0.2.2 → lme_python-0.2.3}/python/examples/verification_project/paths.py +0 -0
- {lme_python-0.2.2 → lme_python-0.2.3}/python/examples/verification_project/run.py +0 -0
- {lme_python-0.2.2 → lme_python-0.2.3}/python/examples/verification_project/test_parity.py +0 -0
- {lme_python-0.2.2 → lme_python-0.2.3}/python/tests/test_api_parity.py +0 -0
- {lme_python-0.2.2 → lme_python-0.2.3}/python/tests/test_basic.py +0 -0
- {lme_python-0.2.2 → lme_python-0.2.3}/python/tests/test_cv.py +0 -0
- {lme_python-0.2.2 → lme_python-0.2.3}/python/tests/test_dataframe_inputs.py +0 -0
- {lme_python-0.2.2 → lme_python-0.2.3}/python/tests/test_golden_parity.py +0 -0
- {lme_python-0.2.2 → lme_python-0.2.3}/python/tests/test_nlmer_custom_mean.py +0 -0
- {lme_python-0.2.2 → lme_python-0.2.3}/python/tests/test_simulate_scale.py +0 -0
- {lme_python-0.2.2 → lme_python-0.2.3}/python/tests/test_wheel_notices.py +0 -0
- {lme_python-0.2.2 → lme_python-0.2.3}/scripts/ci/check_legal_compliance.py +0 -0
- {lme_python-0.2.2 → lme_python-0.2.3}/scripts/ci/julia_format.jl +0 -0
- {lme_python-0.2.2 → lme_python-0.2.3}/scripts/ci/package_wheel_notices.py +0 -0
- {lme_python-0.2.2 → lme_python-0.2.3}/scripts/ci/r_format.R +0 -0
- {lme_python-0.2.2 → lme_python-0.2.3}/scripts/ci/run.sh +0 -0
- {lme_python-0.2.2 → lme_python-0.2.3}/scripts/dump_dyestuff.R +0 -0
- {lme_python-0.2.2 → lme_python-0.2.3}/scripts/dump_pastes.R +0 -0
- {lme_python-0.2.2 → lme_python-0.2.3}/scripts/local_ci.ps1 +0 -0
- {lme_python-0.2.2 → lme_python-0.2.3}/scripts/local_ci.sh +0 -0
- {lme_python-0.2.2 → lme_python-0.2.3}/scripts/make_penicillin_csv.py +0 -0
- {lme_python-0.2.2 → lme_python-0.2.3}/scripts/plot_comparisons.py +0 -0
- {lme_python-0.2.2 → lme_python-0.2.3}/scripts/run_cross_language_benchmarks.py +0 -0
- {lme_python-0.2.2 → lme_python-0.2.3}/scripts/run_external_timings.py +0 -0
- {lme_python-0.2.2 → lme_python-0.2.3}/scripts/run_fair_rust_julia_benchmark.py +0 -0
- {lme_python-0.2.2 → lme_python-0.2.3}/scripts/run_perf_breakdown.py +0 -0
- {lme_python-0.2.2 → lme_python-0.2.3}/scripts/sync_github_repo_metadata.py +0 -0
- {lme_python-0.2.2 → lme_python-0.2.3}/scripts/verify_cross_language_parity.py +0 -0
- {lme_python-0.2.2 → lme_python-0.2.3}/src/anova.rs +0 -0
- {lme_python-0.2.2 → lme_python-0.2.3}/src/anova_contrasts.rs +0 -0
- {lme_python-0.2.2 → lme_python-0.2.3}/src/basis.rs +0 -0
- {lme_python-0.2.2 → lme_python-0.2.3}/src/ddf.rs +0 -0
- {lme_python-0.2.2 → lme_python-0.2.3}/src/family.rs +0 -0
- {lme_python-0.2.2 → lme_python-0.2.3}/src/nlmm/formula.rs +0 -0
- {lme_python-0.2.2 → lme_python-0.2.3}/src/nlmm/mean.rs +0 -0
- {lme_python-0.2.2 → lme_python-0.2.3}/src/nlmm/mean_fn.rs +0 -0
- {lme_python-0.2.2 → lme_python-0.2.3}/src/nlmm/predict.rs +0 -0
- {lme_python-0.2.2 → lme_python-0.2.3}/src/nlmm/re_cov.rs +0 -0
- {lme_python-0.2.2 → lme_python-0.2.3}/src/nlmm/self_start.rs +0 -0
- {lme_python-0.2.2 → lme_python-0.2.3}/src/nlmm/ssasymp.rs +0 -0
- {lme_python-0.2.2 → lme_python-0.2.3}/src/nlmm/ssasympoff.rs +0 -0
- {lme_python-0.2.2 → lme_python-0.2.3}/src/nlmm/ssasymporig.rs +0 -0
- {lme_python-0.2.2 → lme_python-0.2.3}/src/nlmm/ssbiexp.rs +0 -0
- {lme_python-0.2.2 → lme_python-0.2.3}/src/nlmm/ssfpl.rs +0 -0
- {lme_python-0.2.2 → lme_python-0.2.3}/src/nlmm/ssgompertz.rs +0 -0
- {lme_python-0.2.2 → lme_python-0.2.3}/src/nlmm/sslogis.rs +0 -0
- {lme_python-0.2.2 → lme_python-0.2.3}/src/nlmm/ssmicmen.rs +0 -0
- {lme_python-0.2.2 → lme_python-0.2.3}/src/nlmm/sspower.rs +0 -0
- {lme_python-0.2.2 → lme_python-0.2.3}/src/nlmm/ssweibull.rs +0 -0
- {lme_python-0.2.2 → lme_python-0.2.3}/src/perf_diag.rs +0 -0
- {lme_python-0.2.2 → lme_python-0.2.3}/src/quadrature.rs +0 -0
- {lme_python-0.2.2 → lme_python-0.2.3}/src/studentized_range.rs +0 -0
- {lme_python-0.2.2 → lme_python-0.2.3}/tests/categorical_anova_test.rs +0 -0
- {lme_python-0.2.2 → lme_python-0.2.3}/tests/data/cbpp_binary.csv +0 -0
- {lme_python-0.2.2 → lme_python-0.2.3}/tests/data/cbpp_binary_weighted.csv +0 -0
- {lme_python-0.2.2 → lme_python-0.2.3}/tests/data/dyestuff.csv +0 -0
- {lme_python-0.2.2 → lme_python-0.2.3}/tests/data/dyestuff_intercept_reml.json +0 -0
- {lme_python-0.2.2 → lme_python-0.2.3}/tests/data/glmm_binomial.json +0 -0
- {lme_python-0.2.2 → lme_python-0.2.3}/tests/data/glmm_binomial_agq.json +0 -0
- {lme_python-0.2.2 → lme_python-0.2.3}/tests/data/glmm_binomial_cloglog.json +0 -0
- {lme_python-0.2.2 → lme_python-0.2.3}/tests/data/glmm_binomial_probit.json +0 -0
- {lme_python-0.2.2 → lme_python-0.2.3}/tests/data/glmm_binomial_weighted.json +0 -0
- {lme_python-0.2.2 → lme_python-0.2.3}/tests/data/glmm_gamma_dyestuff.json +0 -0
- {lme_python-0.2.2 → lme_python-0.2.3}/tests/data/glmm_poisson.json +0 -0
- {lme_python-0.2.2 → lme_python-0.2.3}/tests/data/glmm_poisson_offset.json +0 -0
- {lme_python-0.2.2 → lme_python-0.2.3}/tests/data/golden_parity_manifest.json +0 -0
- {lme_python-0.2.2 → lme_python-0.2.3}/tests/data/grouseticks.csv +0 -0
- {lme_python-0.2.2 → lme_python-0.2.3}/tests/data/intercept_only.json +0 -0
- {lme_python-0.2.2 → lme_python-0.2.3}/tests/data/mock_crossed.json +0 -0
- {lme_python-0.2.2 → lme_python-0.2.3}/tests/data/mock_ml.json +0 -0
- {lme_python-0.2.2 → lme_python-0.2.3}/tests/data/orange.csv +0 -0
- {lme_python-0.2.2 → lme_python-0.2.3}/tests/data/orange_nlmer.json +0 -0
- {lme_python-0.2.2 → lme_python-0.2.3}/tests/data/pastes.csv +0 -0
- {lme_python-0.2.2 → lme_python-0.2.3}/tests/data/pastes_cask_reml.json +0 -0
- {lme_python-0.2.2 → lme_python-0.2.3}/tests/data/pastes_emmeans.json +0 -0
- {lme_python-0.2.2 → lme_python-0.2.3}/tests/data/pastes_glht_tukey.json +0 -0
- {lme_python-0.2.2 → lme_python-0.2.3}/tests/data/penicillin.csv +0 -0
- {lme_python-0.2.2 → lme_python-0.2.3}/tests/data/penicillin.json +0 -0
- {lme_python-0.2.2 → lme_python-0.2.3}/tests/data/r_edge_case_matrix.json +0 -0
- {lme_python-0.2.2 → lme_python-0.2.3}/tests/data/random_slopes.json +0 -0
- {lme_python-0.2.2 → lme_python-0.2.3}/tests/data/sleepstudy.csv +0 -0
- {lme_python-0.2.2 → lme_python-0.2.3}/tests/data/sleepstudy_confint_profile.json +0 -0
- {lme_python-0.2.2 → lme_python-0.2.3}/tests/data/sleepstudy_confint_profile_vc.json +0 -0
- {lme_python-0.2.2 → lme_python-0.2.3}/tests/data/sleepstudy_offset_reml.json +0 -0
- {lme_python-0.2.2 → lme_python-0.2.3}/tests/data/ssasymp_synthetic.csv +0 -0
- {lme_python-0.2.2 → lme_python-0.2.3}/tests/data/ssasympoff_nlmer.json +0 -0
- {lme_python-0.2.2 → lme_python-0.2.3}/tests/data/ssasympoff_synthetic.csv +0 -0
- {lme_python-0.2.2 → lme_python-0.2.3}/tests/data/ssasymporig_nlmer.json +0 -0
- {lme_python-0.2.2 → lme_python-0.2.3}/tests/data/ssasymporig_synthetic.csv +0 -0
- {lme_python-0.2.2 → lme_python-0.2.3}/tests/data/ssbiexp_nlmer.json +0 -0
- {lme_python-0.2.2 → lme_python-0.2.3}/tests/data/ssbiexp_synthetic.csv +0 -0
- {lme_python-0.2.2 → lme_python-0.2.3}/tests/data/ssfol_nlmer.json +0 -0
- {lme_python-0.2.2 → lme_python-0.2.3}/tests/data/ssfpl_nlmer.json +0 -0
- {lme_python-0.2.2 → lme_python-0.2.3}/tests/data/ssfpl_synthetic.csv +0 -0
- {lme_python-0.2.2 → lme_python-0.2.3}/tests/data/ssgompertz_nlmer.json +0 -0
- {lme_python-0.2.2 → lme_python-0.2.3}/tests/data/ssgompertz_synthetic.csv +0 -0
- {lme_python-0.2.2 → lme_python-0.2.3}/tests/data/ssmicmen_nlmer.json +0 -0
- {lme_python-0.2.2 → lme_python-0.2.3}/tests/data/ssmicmen_synthetic.csv +0 -0
- {lme_python-0.2.2 → lme_python-0.2.3}/tests/data/sspower_nlmer.json +0 -0
- {lme_python-0.2.2 → lme_python-0.2.3}/tests/data/sspower_synthetic.csv +0 -0
- {lme_python-0.2.2 → lme_python-0.2.3}/tests/data/ssweibull_nlmer.json +0 -0
- {lme_python-0.2.2 → lme_python-0.2.3}/tests/data/ssweibull_synthetic.csv +0 -0
- {lme_python-0.2.2 → lme_python-0.2.3}/tests/gen_nlmm_extras.R +0 -0
- {lme_python-0.2.2 → lme_python-0.2.3}/tests/generate_mock_data.py +0 -0
- {lme_python-0.2.2 → lme_python-0.2.3}/tests/generate_nlmm_fixtures.R +0 -0
- {lme_python-0.2.2 → lme_python-0.2.3}/tests/generate_r_edge_case_matrix.R +0 -0
- {lme_python-0.2.2 → lme_python-0.2.3}/tests/generate_test_data.R +0 -0
- {lme_python-0.2.2 → lme_python-0.2.3}/tests/test_anova_types.rs +0 -0
- {lme_python-0.2.2 → lme_python-0.2.3}/tests/test_bootstrap.rs +0 -0
- {lme_python-0.2.2 → lme_python-0.2.3}/tests/test_conditional_real.rs +0 -0
- {lme_python-0.2.2 → lme_python-0.2.3}/tests/test_confint_profile.rs +0 -0
- {lme_python-0.2.2 → lme_python-0.2.3}/tests/test_confint_simulate.rs +0 -0
- {lme_python-0.2.2 → lme_python-0.2.3}/tests/test_contrast.rs +0 -0
- {lme_python-0.2.2 → lme_python-0.2.3}/tests/test_coverage_edge_cases.rs +0 -0
- {lme_python-0.2.2 → lme_python-0.2.3}/tests/test_crossed_mock.rs +0 -0
- {lme_python-0.2.2 → lme_python-0.2.3}/tests/test_cv.rs +0 -0
- {lme_python-0.2.2 → lme_python-0.2.3}/tests/test_e2e_lmer.rs +0 -0
- {lme_python-0.2.2 → lme_python-0.2.3}/tests/test_edge_cases.rs +0 -0
- {lme_python-0.2.2 → lme_python-0.2.3}/tests/test_emmeans.rs +0 -0
- {lme_python-0.2.2 → lme_python-0.2.3}/tests/test_errors.rs +0 -0
- {lme_python-0.2.2 → lme_python-0.2.3}/tests/test_explorations.rs +0 -0
- {lme_python-0.2.2 → lme_python-0.2.3}/tests/test_external_timings_artifact.rs +0 -0
- {lme_python-0.2.2 → lme_python-0.2.3}/tests/test_formula.rs +0 -0
- {lme_python-0.2.2 → lme_python-0.2.3}/tests/test_gaps.rs +0 -0
- {lme_python-0.2.2 → lme_python-0.2.3}/tests/test_glmm.rs +0 -0
- {lme_python-0.2.2 → lme_python-0.2.3}/tests/test_glmm_links.rs +0 -0
- {lme_python-0.2.2 → lme_python-0.2.3}/tests/test_glmm_offset_grouseticks.rs +0 -0
- {lme_python-0.2.2 → lme_python-0.2.3}/tests/test_glmm_weighted.rs +0 -0
- {lme_python-0.2.2 → lme_python-0.2.3}/tests/test_golden_parity.rs +0 -0
- {lme_python-0.2.2 → lme_python-0.2.3}/tests/test_intercept_only.rs +0 -0
- {lme_python-0.2.2 → lme_python-0.2.3}/tests/test_kenward_roger.rs +0 -0
- {lme_python-0.2.2 → lme_python-0.2.3}/tests/test_kr_modcomp_pastes.rs +0 -0
- {lme_python-0.2.2 → lme_python-0.2.3}/tests/test_mcp.rs +0 -0
- {lme_python-0.2.2 → lme_python-0.2.3}/tests/test_ml_optimization.rs +0 -0
- {lme_python-0.2.2 → lme_python-0.2.3}/tests/test_nlmm_agq.rs +0 -0
- {lme_python-0.2.2 → lme_python-0.2.3}/tests/test_nlmm_bounds.rs +0 -0
- {lme_python-0.2.2 → lme_python-0.2.3}/tests/test_nlmm_custom_mean.rs +0 -0
- {lme_python-0.2.2 → lme_python-0.2.3}/tests/test_nlmm_orange.rs +0 -0
- {lme_python-0.2.2 → lme_python-0.2.3}/tests/test_nlmm_orange_multi_re.rs +0 -0
- {lme_python-0.2.2 → lme_python-0.2.3}/tests/test_nlmm_self_start.rs +0 -0
- {lme_python-0.2.2 → lme_python-0.2.3}/tests/test_nlmm_ss_new_means.rs +0 -0
- {lme_python-0.2.2 → lme_python-0.2.3}/tests/test_nlmm_ssasymp.rs +0 -0
- {lme_python-0.2.2 → lme_python-0.2.3}/tests/test_nlmm_ssasymp_off_orig.rs +0 -0
- {lme_python-0.2.2 → lme_python-0.2.3}/tests/test_nlmm_ssfol.rs +0 -0
- {lme_python-0.2.2 → lme_python-0.2.3}/tests/test_nlmm_ssmicmen.rs +0 -0
- {lme_python-0.2.2 → lme_python-0.2.3}/tests/test_nlmm_sspower.rs +0 -0
- {lme_python-0.2.2 → lme_python-0.2.3}/tests/test_no_intercept.rs +0 -0
- {lme_python-0.2.2 → lme_python-0.2.3}/tests/test_numerical_parity.rs +0 -0
- {lme_python-0.2.2 → lme_python-0.2.3}/tests/test_production_load.rs +0 -0
- {lme_python-0.2.2 → lme_python-0.2.3}/tests/test_r_edge_case_matrix.rs +0 -0
- {lme_python-0.2.2 → lme_python-0.2.3}/tests/test_random_slopes.rs +0 -0
- {lme_python-0.2.2 → lme_python-0.2.3}/tests/test_robust.rs +0 -0
- {lme_python-0.2.2 → lme_python-0.2.3}/tests/test_sandwich_math.R +0 -0
- {lme_python-0.2.2 → lme_python-0.2.3}/tests/test_satterthwaite.rs +0 -0
- {lme_python-0.2.2 → lme_python-0.2.3}/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 }}
|
|
@@ -10,7 +10,7 @@ Use the smallest validation tier that proves the change is sound, then run the e
|
|
|
10
10
|
| Python bindings | `task lint:python`, `task python` |
|
|
11
11
|
| CI, manifests, release tooling | `task preflight`; use `task ci` before a release or broad refactor |
|
|
12
12
|
| R / Julia comparison scripts | `task lint:comparisons`; use `task lint:comparisons:required` when the formatters are installed |
|
|
13
|
-
| Documentation or portable examples | `task docs:check
|
|
13
|
+
| Documentation or portable examples | `task docs:check` (includes dashboard JSON drift); use `task consumer:smoke` when install or example behavior changes |
|
|
14
14
|
| LMM throughput paths (`src/math.rs`, `src/optimizer.rs`) | Read [OPTIMIZATION.md](OPTIMIZATION.md) and run the applicable fair-harness cases |
|
|
15
15
|
| Completion score files: `README.md`, `REPO_COMPLETION_BY_AREA.md`, `completion_manifest.json`, or `scripts/ci/check_completion_score.py` | `task completion:check` |
|
|
16
16
|
|
|
@@ -20,10 +20,10 @@ For a change that crosses several rows, run every applicable check. Full Rust in
|
|
|
20
20
|
|
|
21
21
|
The completion headline in [README.md](README.md) and every percentage in [REPO_COMPLETION_BY_AREA.md](REPO_COMPLETION_BY_AREA.md) are generated claims, not values to edit by hand.
|
|
22
22
|
|
|
23
|
-
- [completion_manifest.json](completion_manifest.json) is the source of truth: it declares binary scope commitments, their weights,
|
|
24
|
-
- `task completion:check` validates evidence-path existence, score arithmetic, report rows, and the README headline.
|
|
25
|
-
- A completion item may be marked complete only when its stated evidence is current. Partial or
|
|
26
|
-
- Do not raise a score merely because an API exists, a focused benchmark passes, or the stated scope has been narrowed. Update the manifest and supporting evidence in the same change.
|
|
23
|
+
- [completion_manifest.json](completion_manifest.json) is the source of truth: it declares binary scope commitments, their weights, locked `scope` strings, evidence paths, and a `gap` for every incomplete criterion.
|
|
24
|
+
- `task completion:check` validates schema version 2 (names, scopes, gaps), evidence-path existence, score arithmetic, report rows, and the README headline.
|
|
25
|
+
- A completion item may be marked complete only when its **locked scope** is met and its stated evidence is current. Partial, stale, or substituted evidence earns zero.
|
|
26
|
+
- Do not raise a score merely because an API exists, a focused benchmark passes, or the stated scope has been narrowed or replaced. Do not edit `scope` to make an existing artifact pass. Update the manifest and supporting evidence in the same change.
|
|
27
27
|
|
|
28
28
|
`task ci` runs this check automatically. Run it directly whenever a completion-related file changes.
|
|
29
29
|
|
|
@@ -95,6 +95,7 @@ For repository-metadata token issues, set `REPO_ADMIN_TOKEN` locally and run `ta
|
|
|
95
95
|
| `task audit` / `task legal` | Security audit / provenance and license checks |
|
|
96
96
|
| `task completion:check` | Verify the manifest-derived completion score and published markers |
|
|
97
97
|
| `task docs:check` / `task consumer:smoke` | Validate docs/links/API examples / run clean-install Rust and Python workflows |
|
|
98
|
+
| `task benchmarks:site` | Regenerate `docs/benchmarks/data/latest.json` from checked-in reference JSON |
|
|
98
99
|
| `task benchmarks:fair-rust-julia` | Fair fit-only Rust vs MixedModels.jl timing when Julia packages are installed |
|
|
99
100
|
| `task benchmarks:perf-breakdown` | Rust phase timings against Julia optimizer evaluation counts |
|
|
100
101
|
| `task benchmarks:external-timings` | Fair-ish `nlmer`, post-fit inference, and Python FFI timings vs R when available |
|
|
@@ -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.
|
|
@@ -1,8 +1,14 @@
|
|
|
1
1
|
# Benchmark coverage map
|
|
2
2
|
|
|
3
|
+
[Documentation](docs/README.md) · [Benchmark guide](BENCHMARKS.md) · [Optimization notes](OPTIMIZATION.md)
|
|
4
|
+
|
|
3
5
|
This file maps **which parts of `lme-rs` have external performance references** (not just Rust-only Criterion benches). Use it to ground [REPO_COMPLETION_BY_AREA.md](REPO_COMPLETION_BY_AREA.md) axis (3) and [USABILITY.md](USABILITY.md) performance posture.
|
|
4
6
|
|
|
5
|
-
**
|
|
7
|
+
**Evidence assessment:** 2026-08-15. The catalog below reports dated artifacts,
|
|
8
|
+
not measurements rerun during documentation maintenance.
|
|
9
|
+
|
|
10
|
+
**Jump to:** [Harness tiers](#harness-tiers) · [Case catalog](#tier-a-case-catalog) ·
|
|
11
|
+
[Commands](#running-benchmarks) · [Claim policy](#what-each-completion-row-may-claim)
|
|
6
12
|
|
|
7
13
|
---
|
|
8
14
|
|
|
@@ -23,7 +29,7 @@ This file maps **which parts of `lme-rs` have external performance references**
|
|
|
23
29
|
|
|
24
30
|
Default target: **Rust median < 1.0× Julia median** on `cold_fit` for tier-A LMM cases on the reference workstation (strictly faster than MixedModels.jl).
|
|
25
31
|
|
|
26
|
-
Prior milestones: **≤ 2×** (through 2026-07-08) while crossed/nested were multi× slower; **≤ 1.5×** (2026-07-09–15); selected crossed/nested strict passes on 2026-07-16. The [2026-07-22 full tier-A reference](benchmarks/fair-rust-julia-reference-2026-07-22-full-tier-a.json) records all 12 cases at the
|
|
32
|
+
Prior milestones: **≤ 2×** (through 2026-07-08) while crossed/nested were multi× slower; **≤ 1.5×** (2026-07-09–15); selected crossed/nested strict passes on 2026-07-16. The [2026-07-22 full tier-A reference](benchmarks/fair-rust-julia-reference-2026-07-22-full-tier-a.json) records all 12 cases at the **1.0×** gate on that revision. LMM rows remain the current LMM evidence (`math.rs` / `optimizer.rs` unchanged); the two GLMM rows predate Gamma PIRLS phi profiling and multivariate AGQ-in-θ.
|
|
27
33
|
|
|
28
34
|
```powershell
|
|
29
35
|
python scripts/run_fair_rust_julia_benchmark.py --implementations rust,julia --with-phases --repeats 10
|
|
@@ -47,18 +53,18 @@ Hot-path target (batch / CV): **`fit_prepared` ≤ ~1× Julia `fit`** when `--wi
|
|
|
47
53
|
| `large_random_slopes_100k` | LMM | Synthetic (100k obs; 2k groups) | MixedModels.jl | **0.898×** | **0.646×** | Showcase: correlated intercept/slope, 3 θ; linear cache setup |
|
|
48
54
|
| `crossed_20k` | LMM | Synthetic | MixedModels.jl | **0.879×** | **0.677×** | Direct two-factor Gram + allocation-free blocked gate |
|
|
49
55
|
| `nested_10k` | LMM | Synthetic | MixedModels.jl | **0.961×** | **0.492×** | Direct slash design + membership Gram |
|
|
50
|
-
| `cbpp_binomial_ml` | GLMM | Real binomial | MixedModels.jl GLMM | **0.749×** | N/A | Laplace;
|
|
51
|
-
| `grouseticks_poisson_ml` | GLMM | Real Poisson | MixedModels.jl GLMM | **0.033×** | N/A | Laplace |
|
|
56
|
+
| `cbpp_binomial_ml` | GLMM | Real binomial | MixedModels.jl GLMM | **0.749×** | N/A | Historical Laplace timing; rerun after GLMM changes |
|
|
57
|
+
| `grouseticks_poisson_ml` | GLMM | Real Poisson | MixedModels.jl GLMM | **0.033×** | N/A | Historical Laplace timing; rerun after GLMM changes |
|
|
52
58
|
|
|
53
59
|
Cases not in tier A (no fair MixedModels.jl fit timing yet):
|
|
54
60
|
|
|
55
61
|
| Area | Rust bench | Comparable | Status |
|
|
56
62
|
|:-----|:-----------|:-----------|:-------|
|
|
57
|
-
| `nlmer` / Orange | Golden parity + [`scripts/run_external_timings.py`](scripts/run_external_timings.py) | `lme4::nlmer` | **External R timing** (not Julia) |
|
|
58
|
-
| GLMM AGQ (`n_agq > 1`) | Criterion |
|
|
63
|
+
| `nlmer` / Orange | Golden parity + [`scripts/run_external_timings.py`](scripts/run_external_timings.py) | `lme4::nlmer` | **External R timing** (not Julia; inspect the dated artifact) |
|
|
64
|
+
| GLMM AGQ (`n_agq > 1`) | Criterion | Match integration and optimizer settings | **No** matched external timing in this tier |
|
|
59
65
|
| Post-fit inference (KR, ANOVA, predict) | Criterion + external harness | `lmerTest` when installed | **External R timing** for KR / Satterthwaite ANOVA |
|
|
60
66
|
| LMM estimated marginal means / pairs | Criterion (`inference/emmeans_*`) | R `emmeans` correctness fixture | **Rust microbenchmark**; no cross-language speed claim |
|
|
61
|
-
| Python `lme_python` FFI | External harness | Rust `lmer` | **External Python timing** |
|
|
67
|
+
| Python `lme_python` FFI | External harness | Rust `lmer` | **External Python timing** (inspect the dated artifact) |
|
|
62
68
|
| `lm` / `lm_df` | Minimal | R `lm` | **No** (usually negligible) |
|
|
63
69
|
|
|
64
70
|
The 2026-08-14 Windows Criterion run measured `inference/emmeans_reference_grid` at **42.5–43.1 µs** and `inference/emmeans_pairs_tukey` at **52.9–56.8 µs** on the pastes fixture. These are post-fit operations and do not warrant a specialized cache at the current scale.
|
|
@@ -71,7 +77,7 @@ The 2026-08-14 Windows Criterion run measured `inference/emmeans_reference_grid`
|
|
|
71
77
|
|:------------|:----------------------------|
|
|
72
78
|
| **1 LMM** | Tier-A LMM cases meet `cold_fit` target (or documented exception) |
|
|
73
79
|
| **2 GLMM** | Tier-A GLMM cases measured; do not infer from LMM row 13 alone |
|
|
74
|
-
| **13 Throughput** |
|
|
80
|
+
| **13 Throughput** | Named LMM cases at target from a **current** artifact; full-suite-including-GLMM needs a rerun after GLMM fit-math changes |
|
|
75
81
|
| **4 Inference** | Correctness / API only unless tier added |
|
|
76
82
|
|
|
77
83
|
---
|
|
@@ -122,4 +128,6 @@ A dated reference JSON lives under [`benchmarks/`](benchmarks/). Use `--rust-onl
|
|
|
122
128
|
1. After optimization work on a workflow, add or refresh its tier-A case.
|
|
123
129
|
2. Record medians in [BENCHMARKS.md](BENCHMARKS.md) and/or commit a dated reference JSON under [`benchmarks/`](benchmarks/).
|
|
124
130
|
3. Update **Measured** / **Re-run** cells in the case catalog above.
|
|
125
|
-
4.
|
|
131
|
+
4. Update [completion_manifest.json](completion_manifest.json) and its supporting
|
|
132
|
+
evidence only when the existing locked scope is met. Keep generated report
|
|
133
|
+
markers aligned and run `task completion:check`; do not edit percentages by hand.
|
|
@@ -5,7 +5,59 @@ All notable changes to this project will be documented in this file.
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
|
-
## [
|
|
8
|
+
## [0.2.3] - 2026-09-09
|
|
9
|
+
|
|
10
|
+
### Fixed
|
|
11
|
+
|
|
12
|
+
- Preserve offsets and observation weights throughout Satterthwaite and Kenward-Roger inference.
|
|
13
|
+
- Use one Kenward-Roger covariance adjustment for marginal and joint tests, confidence
|
|
14
|
+
intervals, estimated marginal means, and multiple comparisons; retain precision
|
|
15
|
+
for very small p-values and reject nonfinite contrast inputs.
|
|
16
|
+
- Respect precision weights in observation-level and cluster-robust standard errors.
|
|
17
|
+
- Keep nested grouping labels distinct when components contain underscores or backslashes.
|
|
18
|
+
- Honor requested grouped cross-validation fold counts, accept supported numeric
|
|
19
|
+
response types, and reject missing split labels and invalid responses.
|
|
20
|
+
- Preserve predictors and responses named `intercept` in formula models.
|
|
21
|
+
- Reject nonfinite confidence levels and mismatched or missing robust-inference data.
|
|
22
|
+
- Leave uncertainty unavailable when an OLS fit has no residual degrees of freedom.
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
- Preserve formula offsets in population/conditional predictions and OLS fitting.
|
|
26
|
+
- Preserve precision weights in Gaussian simulation and bootstrap refits; weighted
|
|
27
|
+
residual resampling uses standardized residuals.
|
|
28
|
+
- Refine two-parameter LMM grid minima before reporting optimizer convergence.
|
|
29
|
+
- Honor nonlinear iteration budgets and expose failed numerical stages. Nonlinear
|
|
30
|
+
ML fitting now refines covariance and population parameters jointly and includes
|
|
31
|
+
the full Gaussian likelihood constant; reported likelihood/AIC/BIC may change.
|
|
32
|
+
- Compute OLS coefficients and covariance from one QR decomposition with rank checks.
|
|
33
|
+
|
|
34
|
+
### Added
|
|
35
|
+
|
|
36
|
+
- Rust `FitControl`, `FitDiagnostics`, `ModelSpec`, and `ExecutionContext`; Python
|
|
37
|
+
`FitControl`, `fit.diagnostics`, and `prepared.fit(y=..., control=...)`.
|
|
38
|
+
- Independent response workspaces with shared immutable LMM/GLMM designs, retained
|
|
39
|
+
GLMM sparse factorization structure, and group-block nonlinear normal equations.
|
|
40
|
+
- Formula-based Python IPC column projection and interpreter release during native
|
|
41
|
+
fitting, prediction, bootstrap, and profile intervals.
|
|
42
|
+
|
|
43
|
+
### Compatibility
|
|
44
|
+
|
|
45
|
+
- Existing fitting functions retain their defaults. Rust consumers constructing
|
|
46
|
+
`LmeFit` literals must add `diagnostics: None`; numerical design fields exposed
|
|
47
|
+
through `LmmData`/`GlmmData` are now immutable shared data.
|
|
48
|
+
- A nonconverged fit remains inspectable, but Wald intervals reject it. Set
|
|
49
|
+
`require_convergence` to reject unsuccessful LMM/GLMM fits immediately.
|
|
50
|
+
- Resampling no longer changes process-wide BLAS/OpenMP environment variables.
|
|
51
|
+
`n_jobs=None` uses the current Rayon context; callers own backend thread settings.
|
|
52
|
+
|
|
53
|
+
### Changed
|
|
54
|
+
|
|
55
|
+
- Reworked documentation navigation, Rust/Python onboarding, example discovery,
|
|
56
|
+
troubleshooting, workflow scope, and the contributor/release runbooks. Corrected
|
|
57
|
+
prepared-fit, bootstrap, calibration-bound, and benchmark-evidence descriptions.
|
|
58
|
+
- Reevaluated the repository completion score. The 2026-08-14 **100% (236/236)** headline overstated remaining stretch-item depth, omitted NLMM from the denominator, and could be satisfied by file existence alone. Locked criterion `scope` strings, reopened partial/stale/substituted items, added NLMM as row 14, and published **91% (235/258)**. See [REPO_COMPLETION_BY_AREA.md](REPO_COMPLETION_BY_AREA.md).
|
|
59
|
+
- Reorganized the GitHub README around the existing banner: table of contents, capability and documentation tables, dual Rust/Python install and quick start, an `lme4` mapping, and structured limitation notes.
|
|
60
|
+
- Rebuilt the GitHub Pages [benchmark dashboard](https://x4g4p3x.github.io/lme-rs/benchmarks/) around the fair MixedModels.jl harness and checked-in external timings, and restored Pages deployment.
|
|
9
61
|
|
|
10
62
|
## [0.2.2] - 2026-08-14
|
|
11
63
|
|
|
@@ -1,4 +1,10 @@
|
|
|
1
|
-
# CI performance
|
|
1
|
+
# CI performance history
|
|
2
|
+
|
|
3
|
+
[Documentation](docs/README.md) · [Current CI behavior](CONTRIBUTING.md#github-actions) · [Runner reference](scripts/ci/README.md)
|
|
4
|
+
|
|
5
|
+
These are historical measurements from the linked runs, not current duration
|
|
6
|
+
estimates. Use the workflow files and shared runner for the current validation
|
|
7
|
+
contract. Retain both cold and warm runs when adding a new comparison.
|
|
2
8
|
|
|
3
9
|
This document records hosted-CI timing evidence and the optimizations that are
|
|
4
10
|
safe to depend on. Times are GitHub Actions job timestamps, not local estimates.
|