lme-python 0.2.1__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.1 → lme_python-0.2.3}/.github/workflows/audit.yml +2 -2
- {lme_python-0.2.1 → lme_python-0.2.3}/.github/workflows/benchmarks.yml +76 -0
- {lme_python-0.2.1 → lme_python-0.2.3}/.github/workflows/cache-prime.yml +9 -3
- {lme_python-0.2.1 → lme_python-0.2.3}/.github/workflows/ci.yml +30 -15
- {lme_python-0.2.1 → 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.1 → lme_python-0.2.3}/.github/workflows/python-release.yml +89 -9
- {lme_python-0.2.1 → lme_python-0.2.3}/AGENTS.md +19 -6
- {lme_python-0.2.1 → lme_python-0.2.3}/BENCHMARKS.md +74 -30
- {lme_python-0.2.1 → lme_python-0.2.3}/BENCHMARK_COVERAGE.md +35 -11
- {lme_python-0.2.1 → lme_python-0.2.3}/CHANGELOG.md +78 -1
- {lme_python-0.2.1 → lme_python-0.2.3}/CI_PERFORMANCE.md +7 -1
- lme_python-0.2.3/CONTRIBUTING.md +226 -0
- {lme_python-0.2.1 → lme_python-0.2.3}/Cargo.lock +1 -1
- {lme_python-0.2.1 → lme_python-0.2.3}/Cargo.toml +1 -1
- {lme_python-0.2.1 → lme_python-0.2.3}/GUIDE.md +138 -51
- {lme_python-0.2.1 → lme_python-0.2.3}/OPTIMIZATION.md +90 -6
- 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.1 → lme_python-0.2.3}/Taskfile.yml +30 -0
- lme_python-0.2.3/USABILITY.md +110 -0
- {lme_python-0.2.1 → lme_python-0.2.3}/benches/bench_math.rs +21 -0
- lme_python-0.2.3/benchmarks/external-nlmm-inference-python-timings-2026-08-14.json +198 -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.1 → lme_python-0.2.3}/comparisons/COMPARISONS.md +34 -8
- lme_python-0.2.3/comparisons/bench_external_timings.R +138 -0
- lme_python-0.2.3/comparisons/pastes_emmeans.R +48 -0
- lme_python-0.2.3/comparisons/pastes_glht.R +36 -0
- lme_python-0.2.3/comparisons/sleepstudy_confint_profile.R +16 -0
- 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.1 → lme_python-0.2.3}/docs/benchmarks/styles.css +62 -3
- {lme_python-0.2.1 → lme_python-0.2.3}/docs/index.html +1 -1
- lme_python-0.2.3/examples/bench_external_timings.rs +262 -0
- lme_python-0.2.3/examples/explore_formula_ast.rs +137 -0
- lme_python-0.2.3/examples/explore_mcp_adjust.rs +78 -0
- lme_python-0.2.3/examples/explore_theta_grid.rs +76 -0
- {lme_python-0.2.1 → 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.1 → lme_python-0.2.3}/pyproject.toml +8 -0
- {lme_python-0.2.1 → lme_python-0.2.3}/python/Cargo.lock +2 -2
- {lme_python-0.2.1 → lme_python-0.2.3}/python/Cargo.toml +2 -1
- {lme_python-0.2.1 → lme_python-0.2.3}/python/PYTHON_GUIDE.md +195 -114
- 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.1 → lme_python-0.2.3}/python/examples/verification_project/parity.py +5 -3
- {lme_python-0.2.1 → lme_python-0.2.3}/python/examples/verification_project/run.py +1 -1
- {lme_python-0.2.1 → lme_python-0.2.3}/python/lme_python.pyi +114 -12
- 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.1 → lme_python-0.2.3}/python/src/lib.rs +579 -758
- {lme_python-0.2.1 → lme_python-0.2.3}/python/tests/test_api_parity.py +59 -9
- lme_python-0.2.3/python/tests/test_model_contracts.py +133 -0
- {lme_python-0.2.1 → 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.1 → lme_python-0.2.3}/scripts/ci/check_completion_score.py +36 -3
- {lme_python-0.2.1 → lme_python-0.2.3}/scripts/ci/lme_ci.py +283 -3
- lme_python-0.2.3/scripts/explorations/README.md +24 -0
- lme_python-0.2.3/scripts/run_external_timings.py +236 -0
- lme_python-0.2.3/src/basis.rs +529 -0
- {lme_python-0.2.1 → lme_python-0.2.3}/src/bootstrap.rs +249 -119
- {lme_python-0.2.1 → lme_python-0.2.3}/src/contrast.rs +52 -34
- {lme_python-0.2.1 → lme_python-0.2.3}/src/cv.rs +31 -85
- lme_python-0.2.3/src/display.rs +283 -0
- lme_python-0.2.3/src/emmeans.rs +459 -0
- lme_python-0.2.3/src/execution.rs +48 -0
- {lme_python-0.2.1 → lme_python-0.2.3}/src/family.rs +65 -0
- lme_python-0.2.3/src/formula.rs +1361 -0
- {lme_python-0.2.1 → lme_python-0.2.3}/src/glmm_math.rs +226 -82
- {lme_python-0.2.1 → 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.1 → lme_python-0.2.3}/src/kr_modcomp.rs +24 -45
- {lme_python-0.2.1 → lme_python-0.2.3}/src/kr_vcov_adj.rs +7 -12
- {lme_python-0.2.1 → lme_python-0.2.3}/src/lib.rs +254 -576
- {lme_python-0.2.1 → lme_python-0.2.3}/src/math.rs +99 -84
- lme_python-0.2.3/src/mcp.rs +350 -0
- lme_python-0.2.3/src/model.rs +240 -0
- {lme_python-0.2.1 → lme_python-0.2.3}/src/model_matrix.rs +586 -228
- lme_python-0.2.3/src/nlmm/block_solve.rs +132 -0
- {lme_python-0.2.1 → lme_python-0.2.3}/src/nlmm/fit.rs +386 -146
- {lme_python-0.2.1 → 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.1 → lme_python-0.2.3}/src/optimizer.rs +252 -91
- lme_python-0.2.3/src/predict.rs +179 -0
- lme_python-0.2.3/src/prepared.rs +76 -0
- lme_python-0.2.3/src/profile_ci.rs +1113 -0
- {lme_python-0.2.1 → lme_python-0.2.3}/src/robust.rs +18 -2
- {lme_python-0.2.1 → lme_python-0.2.3}/src/satterthwaite.rs +3 -9
- {lme_python-0.2.1 → lme_python-0.2.3}/src/simulate.rs +18 -17
- lme_python-0.2.3/src/studentized_range.rs +224 -0
- {lme_python-0.2.1 → lme_python-0.2.3}/tests/ci_consolidated.rs +19 -0
- {lme_python-0.2.1 → lme_python-0.2.3}/tests/data/glmm_gamma_dyestuff.json +4 -1
- {lme_python-0.2.1 → lme_python-0.2.3}/tests/data/golden_parity_manifest.json +8 -1
- lme_python-0.2.3/tests/data/pastes_emmeans.json +15 -0
- lme_python-0.2.3/tests/data/pastes_glht_tukey.json +18 -0
- lme_python-0.2.3/tests/data/r_edge_case_matrix.json +432 -0
- lme_python-0.2.3/tests/data/sleepstudy_confint_profile_vc.json +12 -0
- {lme_python-0.2.1 → lme_python-0.2.3}/tests/generate_nlmm_fixtures.R +17 -6
- lme_python-0.2.3/tests/generate_r_edge_case_matrix.R +211 -0
- {lme_python-0.2.1 → lme_python-0.2.3}/tests/test_anova.rs +2 -0
- {lme_python-0.2.1 → lme_python-0.2.3}/tests/test_bootstrap.rs +15 -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.1 → lme_python-0.2.3}/tests/test_confint_profile.rs +80 -1
- {lme_python-0.2.1 → lme_python-0.2.3}/tests/test_coverage_gaps.rs +3 -1
- lme_python-0.2.3/tests/test_emmeans.rs +166 -0
- lme_python-0.2.3/tests/test_explorations.rs +159 -0
- lme_python-0.2.3/tests/test_external_timings_artifact.rs +72 -0
- {lme_python-0.2.1 → lme_python-0.2.3}/tests/test_failure_modes.rs +14 -14
- lme_python-0.2.3/tests/test_formula.rs +94 -0
- {lme_python-0.2.1 → lme_python-0.2.3}/tests/test_formula_stress.rs +171 -11
- {lme_python-0.2.1 → lme_python-0.2.3}/tests/test_glmm.rs +86 -1
- {lme_python-0.2.1 → lme_python-0.2.3}/tests/test_glmm_offset_grouseticks.rs +11 -1
- lme_python-0.2.3/tests/test_mcp.rs +182 -0
- lme_python-0.2.3/tests/test_model_contracts.rs +333 -0
- lme_python-0.2.3/tests/test_nlmm_agq.rs +75 -0
- {lme_python-0.2.1 → lme_python-0.2.3}/tests/test_predict.rs +4 -3
- lme_python-0.2.3/tests/test_r_edge_case_matrix.rs +247 -0
- lme_python-0.2.1/CONTRIBUTING.md +0 -217
- lme_python-0.2.1/PKG-INFO +0 -15
- lme_python-0.2.1/README.md +0 -113
- lme_python-0.2.1/RELEASING.md +0 -260
- lme_python-0.2.1/REPO_COMPLETION_BY_AREA.md +0 -110
- lme_python-0.2.1/USABILITY.md +0 -185
- lme_python-0.2.1/completion_manifest.json +0 -20
- lme_python-0.2.1/docs/CALO_CALIBRATION.md +0 -124
- lme_python-0.2.1/docs/benchmarks/app.js +0 -207
- lme_python-0.2.1/docs/benchmarks/index.html +0 -92
- lme_python-0.2.1/python/examples/plotting_demo/README.md +0 -129
- lme_python-0.2.1/python/examples/verification_project/README.md +0 -42
- lme_python-0.2.1/scripts/build_benchmark_site.py +0 -210
- lme_python-0.2.1/scripts/ci/README.md +0 -27
- lme_python-0.2.1/src/formula.rs +0 -653
- lme_python-0.2.1/src/kenward_roger.rs +0 -357
- lme_python-0.2.1/src/profile_ci.rs +0 -473
- lme_python-0.2.1/tests/test_formula.rs +0 -19
- lme_python-0.2.1/tests/test_nlmm_agq.rs +0 -37
- {lme_python-0.2.1 → lme_python-0.2.3}/.JuliaFormatter.toml +0 -0
- {lme_python-0.2.1 → lme_python-0.2.3}/.github/dependabot.yml +0 -0
- {lme_python-0.2.1 → lme_python-0.2.3}/.github/workflows/crate-publish-dry-run.yml +0 -0
- {lme_python-0.2.1 → lme_python-0.2.3}/.github/workflows/repo-metadata.yml +0 -0
- {lme_python-0.2.1 → lme_python-0.2.3}/.gitignore +0 -0
- {lme_python-0.2.1 → lme_python-0.2.3}/LICENSE +0 -0
- {lme_python-0.2.1 → lme_python-0.2.3}/LICENSES/Apache-2.0.txt +0 -0
- {lme_python-0.2.1 → lme_python-0.2.3}/LICENSES/BSD-3-Clause-OpenBLAS.txt +0 -0
- {lme_python-0.2.1 → lme_python-0.2.3}/LICENSES/GPL-2.0-or-later.txt +0 -0
- {lme_python-0.2.1 → lme_python-0.2.3}/LICENSES/Intel-Simplified-Software-License.txt +0 -0
- {lme_python-0.2.1 → lme_python-0.2.3}/LICENSES/LGPL-2.1-only.txt +0 -0
- {lme_python-0.2.1 → lme_python-0.2.3}/RELINKING.md +0 -0
- {lme_python-0.2.1 → lme_python-0.2.3}/THIRD_PARTY_NOTICES.md +0 -0
- {lme_python-0.2.1 → lme_python-0.2.3}/benches/bench_load_production.rs +0 -0
- {lme_python-0.2.1 → lme_python-0.2.3}/benchmarks/fair-rust-julia-reference-2026-07-04.json +0 -0
- {lme_python-0.2.1 → lme_python-0.2.3}/benchmarks/fair-rust-julia-reference-2026-07-06.json +0 -0
- {lme_python-0.2.1 → lme_python-0.2.3}/benchmarks/fair-rust-julia-reference-2026-07-08.json +0 -0
- {lme_python-0.2.1 → lme_python-0.2.3}/benchmarks/fair-rust-julia-reference-2026-07-09-direct-intercept-gram.json +0 -0
- {lme_python-0.2.1 → lme_python-0.2.3}/benchmarks/fair-rust-julia-reference-2026-07-09-full-lmm.json +0 -0
- {lme_python-0.2.1 → lme_python-0.2.3}/benchmarks/fair-rust-julia-reference-2026-07-09-glmm.json +0 -0
- {lme_python-0.2.1 → lme_python-0.2.3}/benchmarks/fair-rust-julia-reference-2026-07-09-large-intercept-setup.json +0 -0
- {lme_python-0.2.1 → lme_python-0.2.3}/benchmarks/fair-rust-julia-reference-2026-07-09-large-slopes-linear-cache.json +0 -0
- {lme_python-0.2.1 → lme_python-0.2.3}/benchmarks/fair-rust-julia-reference-2026-07-09-large-slopes.json +0 -0
- {lme_python-0.2.1 → lme_python-0.2.3}/benchmarks/fair-rust-julia-reference-2026-07-09-sleepstudy-slopes.json +0 -0
- {lme_python-0.2.1 → lme_python-0.2.3}/benchmarks/fair-rust-julia-reference-2026-07-09.json +0 -0
- {lme_python-0.2.1 → lme_python-0.2.3}/benchmarks/fair-rust-julia-reference-2026-07-10-cold-setup-followup.json +0 -0
- {lme_python-0.2.1 → lme_python-0.2.3}/benchmarks/fair-rust-julia-reference-2026-07-16-cold-fit-lt1.json +0 -0
- {lme_python-0.2.1 → lme_python-0.2.3}/benchmarks/fair-rust-julia-reference-2026-07-22-full-tier-a.json +0 -0
- {lme_python-0.2.1 → lme_python-0.2.3}/comparisons/bench_fair_julia_perf.jl +0 -0
- {lme_python-0.2.1 → lme_python-0.2.3}/comparisons/bench_fair_julia_timing.jl +0 -0
- {lme_python-0.2.1 → lme_python-0.2.3}/comparisons/bench_fair_rust_julia.rs +0 -0
- {lme_python-0.2.1 → lme_python-0.2.3}/comparisons/bench_perf_breakdown.rs +0 -0
- {lme_python-0.2.1 → lme_python-0.2.3}/comparisons/categorical_anova.R +0 -0
- {lme_python-0.2.1 → lme_python-0.2.3}/comparisons/categorical_anova.jl +0 -0
- {lme_python-0.2.1 → lme_python-0.2.3}/comparisons/categorical_anova.py +0 -0
- {lme_python-0.2.1 → lme_python-0.2.3}/comparisons/categorical_anova.rs +0 -0
- {lme_python-0.2.1 → lme_python-0.2.3}/comparisons/comparison_chart.png +0 -0
- {lme_python-0.2.1 → lme_python-0.2.3}/comparisons/glmm_cbpp.R +0 -0
- {lme_python-0.2.1 → lme_python-0.2.3}/comparisons/glmm_cbpp.jl +0 -0
- {lme_python-0.2.1 → lme_python-0.2.3}/comparisons/glmm_cbpp.py +0 -0
- {lme_python-0.2.1 → lme_python-0.2.3}/comparisons/glmm_cbpp.rs +0 -0
- {lme_python-0.2.1 → lme_python-0.2.3}/comparisons/glmm_gaussian.R +0 -0
- {lme_python-0.2.1 → lme_python-0.2.3}/comparisons/glmm_gaussian.jl +0 -0
- {lme_python-0.2.1 → lme_python-0.2.3}/comparisons/glmm_gaussian.py +0 -0
- {lme_python-0.2.1 → lme_python-0.2.3}/comparisons/glmm_gaussian.rs +0 -0
- {lme_python-0.2.1 → lme_python-0.2.3}/comparisons/glmm_grouseticks.R +0 -0
- {lme_python-0.2.1 → lme_python-0.2.3}/comparisons/glmm_grouseticks.jl +0 -0
- {lme_python-0.2.1 → lme_python-0.2.3}/comparisons/glmm_grouseticks.py +0 -0
- {lme_python-0.2.1 → lme_python-0.2.3}/comparisons/glmm_grouseticks.rs +0 -0
- {lme_python-0.2.1 → lme_python-0.2.3}/comparisons/lmer_weighted.R +0 -0
- {lme_python-0.2.1 → lme_python-0.2.3}/comparisons/lmer_weighted.jl +0 -0
- {lme_python-0.2.1 → lme_python-0.2.3}/comparisons/lmer_weighted.py +0 -0
- {lme_python-0.2.1 → lme_python-0.2.3}/comparisons/lmer_weighted.rs +0 -0
- {lme_python-0.2.1 → lme_python-0.2.3}/comparisons/lmm_dyestuff.R +0 -0
- {lme_python-0.2.1 → lme_python-0.2.3}/comparisons/lmm_dyestuff.jl +0 -0
- {lme_python-0.2.1 → lme_python-0.2.3}/comparisons/lmm_dyestuff.py +0 -0
- {lme_python-0.2.1 → lme_python-0.2.3}/comparisons/lmm_dyestuff.rs +0 -0
- {lme_python-0.2.1 → lme_python-0.2.3}/comparisons/lmm_pastes.R +0 -0
- {lme_python-0.2.1 → lme_python-0.2.3}/comparisons/lmm_pastes.jl +0 -0
- {lme_python-0.2.1 → lme_python-0.2.3}/comparisons/lmm_pastes.py +0 -0
- {lme_python-0.2.1 → lme_python-0.2.3}/comparisons/lmm_pastes.rs +0 -0
- {lme_python-0.2.1 → lme_python-0.2.3}/comparisons/lmm_penicillin.R +0 -0
- {lme_python-0.2.1 → lme_python-0.2.3}/comparisons/lmm_penicillin.jl +0 -0
- {lme_python-0.2.1 → lme_python-0.2.3}/comparisons/lmm_penicillin.py +0 -0
- {lme_python-0.2.1 → lme_python-0.2.3}/comparisons/lmm_penicillin.rs +0 -0
- {lme_python-0.2.1 → lme_python-0.2.3}/comparisons/nlmm_sspower.R +0 -0
- {lme_python-0.2.1 → lme_python-0.2.3}/comparisons/parity/glmm_offset.R +0 -0
- {lme_python-0.2.1 → lme_python-0.2.3}/comparisons/parity/glmm_offset.jl +0 -0
- {lme_python-0.2.1 → lme_python-0.2.3}/comparisons/parity/glmm_probit.R +0 -0
- {lme_python-0.2.1 → lme_python-0.2.3}/comparisons/parity/glmm_probit.jl +0 -0
- {lme_python-0.2.1 → lme_python-0.2.3}/comparisons/parity/glmm_weighted.R +0 -0
- {lme_python-0.2.1 → lme_python-0.2.3}/comparisons/parity/glmm_weighted.jl +0 -0
- {lme_python-0.2.1 → lme_python-0.2.3}/comparisons/parity/parity_r_setup.R +0 -0
- {lme_python-0.2.1 → lme_python-0.2.3}/comparisons/parity/sleepstudy_offset.R +0 -0
- {lme_python-0.2.1 → lme_python-0.2.3}/comparisons/parity/sleepstudy_offset.jl +0 -0
- {lme_python-0.2.1 → lme_python-0.2.3}/comparisons/parity_export.rs +0 -0
- {lme_python-0.2.1 → lme_python-0.2.3}/comparisons/r_setup.R +0 -0
- {lme_python-0.2.1 → lme_python-0.2.3}/comparisons/sleepstudy.R +0 -0
- {lme_python-0.2.1 → lme_python-0.2.3}/comparisons/sleepstudy.jl +0 -0
- {lme_python-0.2.1 → lme_python-0.2.3}/comparisons/sleepstudy.py +0 -0
- {lme_python-0.2.1 → lme_python-0.2.3}/comparisons/sleepstudy.rs +0 -0
- {lme_python-0.2.1 → lme_python-0.2.3}/comparisons/sleepstudy_ml.R +0 -0
- {lme_python-0.2.1 → lme_python-0.2.3}/comparisons/sleepstudy_ml.jl +0 -0
- {lme_python-0.2.1 → lme_python-0.2.3}/comparisons/sleepstudy_ml.py +0 -0
- {lme_python-0.2.1 → lme_python-0.2.3}/comparisons/sleepstudy_ml.rs +0 -0
- {lme_python-0.2.1 → lme_python-0.2.3}/examples/batch_sspower_cpu.rs +0 -0
- {lme_python-0.2.1 → lme_python-0.2.3}/examples/dump_cascade_fixtures.rs +0 -0
- {lme_python-0.2.1 → lme_python-0.2.3}/examples/nlmm_fixture_dump.rs +0 -0
- {lme_python-0.2.1 → lme_python-0.2.3}/legal/dependency-license-exceptions.json +0 -0
- {lme_python-0.2.1 → lme_python-0.2.3}/legal/fixture-provenance.json +0 -0
- {lme_python-0.2.1 → lme_python-0.2.3}/mise.toml +0 -0
- {lme_python-0.2.1 → lme_python-0.2.3}/python/examples/glmer_cbpp.py +0 -0
- {lme_python-0.2.1 → lme_python-0.2.3}/python/examples/glmer_grouseticks.py +0 -0
- {lme_python-0.2.1 → lme_python-0.2.3}/python/examples/lm_basics.py +0 -0
- {lme_python-0.2.1 → lme_python-0.2.3}/python/examples/lmer_sleepstudy.py +0 -0
- {lme_python-0.2.1 → lme_python-0.2.3}/python/examples/model_comparison.py +0 -0
- {lme_python-0.2.1 → lme_python-0.2.3}/python/examples/plotting_demo/.gitignore +0 -0
- {lme_python-0.2.1 → lme_python-0.2.3}/python/examples/plotting_demo/compare_plots.py +0 -0
- {lme_python-0.2.1 → lme_python-0.2.3}/python/examples/plotting_demo/figure_specs.py +0 -0
- {lme_python-0.2.1 → lme_python-0.2.3}/python/examples/plotting_demo/find_rscript.py +0 -0
- {lme_python-0.2.1 → lme_python-0.2.3}/python/examples/plotting_demo/numeric_overlay.py +0 -0
- {lme_python-0.2.1 → lme_python-0.2.3}/python/examples/plotting_demo/paths.py +0 -0
- {lme_python-0.2.1 → lme_python-0.2.3}/python/examples/plotting_demo/plot_demo.py +0 -0
- {lme_python-0.2.1 → lme_python-0.2.3}/python/examples/plotting_demo/plot_r.R +0 -0
- {lme_python-0.2.1 → lme_python-0.2.3}/python/examples/plotting_demo/run_all.py +0 -0
- {lme_python-0.2.1 → lme_python-0.2.3}/python/examples/verification_project/conftest.py +0 -0
- {lme_python-0.2.1 → lme_python-0.2.3}/python/examples/verification_project/paths.py +0 -0
- {lme_python-0.2.1 → lme_python-0.2.3}/python/examples/verification_project/test_parity.py +0 -0
- {lme_python-0.2.1 → lme_python-0.2.3}/python/tests/test_basic.py +0 -0
- {lme_python-0.2.1 → lme_python-0.2.3}/python/tests/test_cv.py +0 -0
- {lme_python-0.2.1 → lme_python-0.2.3}/python/tests/test_dataframe_inputs.py +0 -0
- {lme_python-0.2.1 → lme_python-0.2.3}/python/tests/test_golden_parity.py +0 -0
- {lme_python-0.2.1 → lme_python-0.2.3}/python/tests/test_nlmer_custom_mean.py +0 -0
- {lme_python-0.2.1 → lme_python-0.2.3}/python/tests/test_simulate_scale.py +0 -0
- {lme_python-0.2.1 → lme_python-0.2.3}/python/tests/test_wheel_notices.py +0 -0
- {lme_python-0.2.1 → lme_python-0.2.3}/scripts/ci/check_legal_compliance.py +0 -0
- {lme_python-0.2.1 → lme_python-0.2.3}/scripts/ci/julia_format.jl +0 -0
- {lme_python-0.2.1 → lme_python-0.2.3}/scripts/ci/package_wheel_notices.py +0 -0
- {lme_python-0.2.1 → lme_python-0.2.3}/scripts/ci/r_format.R +0 -0
- {lme_python-0.2.1 → lme_python-0.2.3}/scripts/ci/run.sh +0 -0
- {lme_python-0.2.1 → lme_python-0.2.3}/scripts/dump_dyestuff.R +0 -0
- {lme_python-0.2.1 → lme_python-0.2.3}/scripts/dump_pastes.R +0 -0
- {lme_python-0.2.1 → lme_python-0.2.3}/scripts/local_ci.ps1 +0 -0
- {lme_python-0.2.1 → lme_python-0.2.3}/scripts/local_ci.sh +0 -0
- {lme_python-0.2.1 → lme_python-0.2.3}/scripts/make_penicillin_csv.py +0 -0
- {lme_python-0.2.1 → lme_python-0.2.3}/scripts/plot_comparisons.py +0 -0
- {lme_python-0.2.1 → lme_python-0.2.3}/scripts/run_cross_language_benchmarks.py +0 -0
- {lme_python-0.2.1 → lme_python-0.2.3}/scripts/run_fair_rust_julia_benchmark.py +0 -0
- {lme_python-0.2.1 → lme_python-0.2.3}/scripts/run_perf_breakdown.py +0 -0
- {lme_python-0.2.1 → lme_python-0.2.3}/scripts/sync_github_repo_metadata.py +0 -0
- {lme_python-0.2.1 → lme_python-0.2.3}/scripts/verify_cross_language_parity.py +0 -0
- {lme_python-0.2.1 → lme_python-0.2.3}/src/anova.rs +0 -0
- {lme_python-0.2.1 → lme_python-0.2.3}/src/anova_contrasts.rs +0 -0
- {lme_python-0.2.1 → lme_python-0.2.3}/src/ddf.rs +0 -0
- {lme_python-0.2.1 → lme_python-0.2.3}/src/nlmm/formula.rs +0 -0
- {lme_python-0.2.1 → lme_python-0.2.3}/src/nlmm/mean.rs +0 -0
- {lme_python-0.2.1 → lme_python-0.2.3}/src/nlmm/mean_fn.rs +0 -0
- {lme_python-0.2.1 → lme_python-0.2.3}/src/nlmm/predict.rs +0 -0
- {lme_python-0.2.1 → lme_python-0.2.3}/src/nlmm/re_cov.rs +0 -0
- {lme_python-0.2.1 → lme_python-0.2.3}/src/nlmm/self_start.rs +0 -0
- {lme_python-0.2.1 → lme_python-0.2.3}/src/nlmm/ssasymp.rs +0 -0
- {lme_python-0.2.1 → lme_python-0.2.3}/src/nlmm/ssasympoff.rs +0 -0
- {lme_python-0.2.1 → lme_python-0.2.3}/src/nlmm/ssasymporig.rs +0 -0
- {lme_python-0.2.1 → lme_python-0.2.3}/src/nlmm/ssbiexp.rs +0 -0
- {lme_python-0.2.1 → lme_python-0.2.3}/src/nlmm/ssfpl.rs +0 -0
- {lme_python-0.2.1 → lme_python-0.2.3}/src/nlmm/ssgompertz.rs +0 -0
- {lme_python-0.2.1 → lme_python-0.2.3}/src/nlmm/sslogis.rs +0 -0
- {lme_python-0.2.1 → lme_python-0.2.3}/src/nlmm/ssmicmen.rs +0 -0
- {lme_python-0.2.1 → lme_python-0.2.3}/src/nlmm/sspower.rs +0 -0
- {lme_python-0.2.1 → lme_python-0.2.3}/src/nlmm/ssweibull.rs +0 -0
- {lme_python-0.2.1 → lme_python-0.2.3}/src/perf_diag.rs +0 -0
- {lme_python-0.2.1 → lme_python-0.2.3}/src/quadrature.rs +0 -0
- {lme_python-0.2.1 → lme_python-0.2.3}/tests/categorical_anova_test.rs +0 -0
- {lme_python-0.2.1 → lme_python-0.2.3}/tests/data/cbpp_binary.csv +0 -0
- {lme_python-0.2.1 → lme_python-0.2.3}/tests/data/cbpp_binary_weighted.csv +0 -0
- {lme_python-0.2.1 → lme_python-0.2.3}/tests/data/dyestuff.csv +0 -0
- {lme_python-0.2.1 → lme_python-0.2.3}/tests/data/dyestuff_intercept_reml.json +0 -0
- {lme_python-0.2.1 → lme_python-0.2.3}/tests/data/glmm_binomial.json +0 -0
- {lme_python-0.2.1 → lme_python-0.2.3}/tests/data/glmm_binomial_agq.json +0 -0
- {lme_python-0.2.1 → lme_python-0.2.3}/tests/data/glmm_binomial_cloglog.json +0 -0
- {lme_python-0.2.1 → lme_python-0.2.3}/tests/data/glmm_binomial_probit.json +0 -0
- {lme_python-0.2.1 → lme_python-0.2.3}/tests/data/glmm_binomial_weighted.json +0 -0
- {lme_python-0.2.1 → lme_python-0.2.3}/tests/data/glmm_poisson.json +0 -0
- {lme_python-0.2.1 → lme_python-0.2.3}/tests/data/glmm_poisson_offset.json +0 -0
- {lme_python-0.2.1 → lme_python-0.2.3}/tests/data/grouseticks.csv +0 -0
- {lme_python-0.2.1 → lme_python-0.2.3}/tests/data/intercept_only.json +0 -0
- {lme_python-0.2.1 → lme_python-0.2.3}/tests/data/mock_crossed.json +0 -0
- {lme_python-0.2.1 → lme_python-0.2.3}/tests/data/mock_ml.json +0 -0
- {lme_python-0.2.1 → lme_python-0.2.3}/tests/data/orange.csv +0 -0
- {lme_python-0.2.1 → lme_python-0.2.3}/tests/data/orange_nlmer.json +0 -0
- {lme_python-0.2.1 → lme_python-0.2.3}/tests/data/pastes.csv +0 -0
- {lme_python-0.2.1 → lme_python-0.2.3}/tests/data/pastes_cask_reml.json +0 -0
- {lme_python-0.2.1 → lme_python-0.2.3}/tests/data/penicillin.csv +0 -0
- {lme_python-0.2.1 → lme_python-0.2.3}/tests/data/penicillin.json +0 -0
- {lme_python-0.2.1 → lme_python-0.2.3}/tests/data/random_slopes.json +0 -0
- {lme_python-0.2.1 → lme_python-0.2.3}/tests/data/sleepstudy.csv +0 -0
- {lme_python-0.2.1 → lme_python-0.2.3}/tests/data/sleepstudy_confint_profile.json +0 -0
- {lme_python-0.2.1 → lme_python-0.2.3}/tests/data/sleepstudy_offset_reml.json +0 -0
- {lme_python-0.2.1 → lme_python-0.2.3}/tests/data/ssasymp_synthetic.csv +0 -0
- {lme_python-0.2.1 → lme_python-0.2.3}/tests/data/ssasympoff_nlmer.json +0 -0
- {lme_python-0.2.1 → lme_python-0.2.3}/tests/data/ssasympoff_synthetic.csv +0 -0
- {lme_python-0.2.1 → lme_python-0.2.3}/tests/data/ssasymporig_nlmer.json +0 -0
- {lme_python-0.2.1 → lme_python-0.2.3}/tests/data/ssasymporig_synthetic.csv +0 -0
- {lme_python-0.2.1 → lme_python-0.2.3}/tests/data/ssbiexp_nlmer.json +0 -0
- {lme_python-0.2.1 → lme_python-0.2.3}/tests/data/ssbiexp_synthetic.csv +0 -0
- {lme_python-0.2.1 → lme_python-0.2.3}/tests/data/ssfol_nlmer.json +0 -0
- {lme_python-0.2.1 → lme_python-0.2.3}/tests/data/ssfpl_nlmer.json +0 -0
- {lme_python-0.2.1 → lme_python-0.2.3}/tests/data/ssfpl_synthetic.csv +0 -0
- {lme_python-0.2.1 → lme_python-0.2.3}/tests/data/ssgompertz_nlmer.json +0 -0
- {lme_python-0.2.1 → lme_python-0.2.3}/tests/data/ssgompertz_synthetic.csv +0 -0
- {lme_python-0.2.1 → lme_python-0.2.3}/tests/data/ssmicmen_nlmer.json +0 -0
- {lme_python-0.2.1 → lme_python-0.2.3}/tests/data/ssmicmen_synthetic.csv +0 -0
- {lme_python-0.2.1 → lme_python-0.2.3}/tests/data/sspower_nlmer.json +0 -0
- {lme_python-0.2.1 → lme_python-0.2.3}/tests/data/sspower_synthetic.csv +0 -0
- {lme_python-0.2.1 → lme_python-0.2.3}/tests/data/ssweibull_nlmer.json +0 -0
- {lme_python-0.2.1 → lme_python-0.2.3}/tests/data/ssweibull_synthetic.csv +0 -0
- {lme_python-0.2.1 → lme_python-0.2.3}/tests/gen_nlmm_extras.R +0 -0
- {lme_python-0.2.1 → lme_python-0.2.3}/tests/generate_mock_data.py +0 -0
- {lme_python-0.2.1 → lme_python-0.2.3}/tests/generate_test_data.R +0 -0
- {lme_python-0.2.1 → lme_python-0.2.3}/tests/test_anova_types.rs +0 -0
- {lme_python-0.2.1 → lme_python-0.2.3}/tests/test_conditional_real.rs +0 -0
- {lme_python-0.2.1 → lme_python-0.2.3}/tests/test_confint_simulate.rs +0 -0
- {lme_python-0.2.1 → lme_python-0.2.3}/tests/test_contrast.rs +0 -0
- {lme_python-0.2.1 → lme_python-0.2.3}/tests/test_coverage_edge_cases.rs +0 -0
- {lme_python-0.2.1 → lme_python-0.2.3}/tests/test_crossed_mock.rs +0 -0
- {lme_python-0.2.1 → lme_python-0.2.3}/tests/test_cv.rs +0 -0
- {lme_python-0.2.1 → lme_python-0.2.3}/tests/test_e2e_lmer.rs +0 -0
- {lme_python-0.2.1 → lme_python-0.2.3}/tests/test_edge_cases.rs +0 -0
- {lme_python-0.2.1 → lme_python-0.2.3}/tests/test_errors.rs +0 -0
- {lme_python-0.2.1 → lme_python-0.2.3}/tests/test_gaps.rs +0 -0
- {lme_python-0.2.1 → lme_python-0.2.3}/tests/test_glmm_links.rs +0 -0
- {lme_python-0.2.1 → lme_python-0.2.3}/tests/test_glmm_weighted.rs +0 -0
- {lme_python-0.2.1 → lme_python-0.2.3}/tests/test_golden_parity.rs +0 -0
- {lme_python-0.2.1 → lme_python-0.2.3}/tests/test_intercept_only.rs +0 -0
- {lme_python-0.2.1 → lme_python-0.2.3}/tests/test_kenward_roger.rs +0 -0
- {lme_python-0.2.1 → lme_python-0.2.3}/tests/test_kr_modcomp_pastes.rs +0 -0
- {lme_python-0.2.1 → lme_python-0.2.3}/tests/test_ml_optimization.rs +0 -0
- {lme_python-0.2.1 → lme_python-0.2.3}/tests/test_nlmm_bounds.rs +0 -0
- {lme_python-0.2.1 → lme_python-0.2.3}/tests/test_nlmm_custom_mean.rs +0 -0
- {lme_python-0.2.1 → lme_python-0.2.3}/tests/test_nlmm_orange.rs +0 -0
- {lme_python-0.2.1 → lme_python-0.2.3}/tests/test_nlmm_orange_multi_re.rs +0 -0
- {lme_python-0.2.1 → lme_python-0.2.3}/tests/test_nlmm_self_start.rs +0 -0
- {lme_python-0.2.1 → lme_python-0.2.3}/tests/test_nlmm_ss_new_means.rs +0 -0
- {lme_python-0.2.1 → lme_python-0.2.3}/tests/test_nlmm_ssasymp.rs +0 -0
- {lme_python-0.2.1 → lme_python-0.2.3}/tests/test_nlmm_ssasymp_off_orig.rs +0 -0
- {lme_python-0.2.1 → lme_python-0.2.3}/tests/test_nlmm_ssfol.rs +0 -0
- {lme_python-0.2.1 → lme_python-0.2.3}/tests/test_nlmm_ssmicmen.rs +0 -0
- {lme_python-0.2.1 → lme_python-0.2.3}/tests/test_nlmm_sspower.rs +0 -0
- {lme_python-0.2.1 → lme_python-0.2.3}/tests/test_no_intercept.rs +0 -0
- {lme_python-0.2.1 → lme_python-0.2.3}/tests/test_numerical_parity.rs +0 -0
- {lme_python-0.2.1 → lme_python-0.2.3}/tests/test_production_load.rs +0 -0
- {lme_python-0.2.1 → lme_python-0.2.3}/tests/test_random_slopes.rs +0 -0
- {lme_python-0.2.1 → lme_python-0.2.3}/tests/test_robust.rs +0 -0
- {lme_python-0.2.1 → lme_python-0.2.3}/tests/test_sandwich_math.R +0 -0
- {lme_python-0.2.1 → lme_python-0.2.3}/tests/test_satterthwaite.rs +0 -0
- {lme_python-0.2.1 → 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,11 +105,17 @@ 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
|
|
112
112
|
- name: Compile Python binding dependencies
|
|
113
|
+
if: matrix.os != 'macos-latest'
|
|
113
114
|
env:
|
|
114
115
|
PYO3_PYTHON: python
|
|
115
116
|
run: cargo build --release --manifest-path python/Cargo.toml
|
|
117
|
+
- name: Compile Python binding dependencies (macOS)
|
|
118
|
+
if: matrix.os == 'macos-latest'
|
|
119
|
+
uses: PyO3/maturin-action@e83996d129638aa358a18fbd1dfb82f0b0fb5d3b # v1
|
|
120
|
+
with:
|
|
121
|
+
args: --release --out python/dist --manifest-path python/Cargo.toml
|
|
@@ -34,6 +34,10 @@ jobs:
|
|
|
34
34
|
python-version: "3.11"
|
|
35
35
|
- name: Validate legal notices and provenance
|
|
36
36
|
run: python3 scripts/ci/lme_ci.py legal
|
|
37
|
+
- name: Validate Markdown links
|
|
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
|
|
37
41
|
- name: Validate completion score claims
|
|
38
42
|
run: python3 scripts/ci/lme_ci.py completion-check
|
|
39
43
|
|
|
@@ -54,7 +58,7 @@ jobs:
|
|
|
54
58
|
- name: Install OpenBLAS
|
|
55
59
|
run: sudo apt-get update && sudo apt-get install -y libopenblas-dev
|
|
56
60
|
- name: Cache Rust dependencies
|
|
57
|
-
uses: Swatinem/rust-cache@
|
|
61
|
+
uses: Swatinem/rust-cache@f0d9c3887740aee45f6153b24b3a6b815192ec16 # v2
|
|
58
62
|
with:
|
|
59
63
|
shared-key: ci-v2-${{ runner.os }}-rust-test
|
|
60
64
|
save-if: ${{ github.event_name == 'pull_request' || github.ref == 'refs/heads/master' }}
|
|
@@ -111,7 +115,7 @@ jobs:
|
|
|
111
115
|
toolchain: stable
|
|
112
116
|
|
|
113
117
|
- name: Cache Rust dependencies
|
|
114
|
-
uses: Swatinem/rust-cache@
|
|
118
|
+
uses: Swatinem/rust-cache@f0d9c3887740aee45f6153b24b3a6b815192ec16 # v2
|
|
115
119
|
with:
|
|
116
120
|
shared-key: ci-v2-${{ runner.os }}-rust-test
|
|
117
121
|
cache-workspace-crates: true
|
|
@@ -139,7 +143,7 @@ jobs:
|
|
|
139
143
|
run: sudo apt-get update && sudo apt-get install -y libopenblas-dev
|
|
140
144
|
|
|
141
145
|
- name: Restore Rust dependencies
|
|
142
|
-
uses: Swatinem/rust-cache@
|
|
146
|
+
uses: Swatinem/rust-cache@f0d9c3887740aee45f6153b24b3a6b815192ec16 # v2
|
|
143
147
|
with:
|
|
144
148
|
shared-key: ci-v2-${{ runner.os }}-rust-release
|
|
145
149
|
cache-workspace-crates: true
|
|
@@ -167,13 +171,13 @@ jobs:
|
|
|
167
171
|
- name: Install OpenBLAS
|
|
168
172
|
run: sudo apt-get update && sudo apt-get install -y libopenblas-dev
|
|
169
173
|
- name: Cache Python Rust dependencies
|
|
170
|
-
uses: Swatinem/rust-cache@
|
|
174
|
+
uses: Swatinem/rust-cache@f0d9c3887740aee45f6153b24b3a6b815192ec16 # v2
|
|
171
175
|
with:
|
|
172
176
|
shared-key: ci-${{ runner.os }}-python
|
|
173
177
|
workspaces: python -> target
|
|
174
178
|
save-if: ${{ matrix.python-version == '3.11' && (github.event_name == 'pull_request' || github.ref == 'refs/heads/master') }}
|
|
175
179
|
- name: Set up uv
|
|
176
|
-
uses: astral-sh/setup-uv@
|
|
180
|
+
uses: astral-sh/setup-uv@20cfd1bf945f4377ade1205e4dbc17946fc9a30d # v10.0.1
|
|
177
181
|
with:
|
|
178
182
|
python-version: ${{ matrix.python-version }}
|
|
179
183
|
enable-cache: true
|
|
@@ -181,7 +185,7 @@ jobs:
|
|
|
181
185
|
|
|
182
186
|
- name: Python bindings (canonical editable identity + isolated wheel)
|
|
183
187
|
if: matrix.python-version == '3.11'
|
|
184
|
-
run: python scripts/ci/lme_ci.py python --python-version ${{ matrix.python-version }}
|
|
188
|
+
run: python scripts/ci/lme_ci.py python --python-version ${{ matrix.python-version }} --examples
|
|
185
189
|
|
|
186
190
|
- name: Python bindings (isolated wheel compatibility)
|
|
187
191
|
if: matrix.python-version != '3.11'
|
|
@@ -203,19 +207,19 @@ jobs:
|
|
|
203
207
|
if: matrix.os == 'macos-latest'
|
|
204
208
|
run: echo "OPENBLAS_TARGET=ARMV8" >> "$GITHUB_ENV"
|
|
205
209
|
- name: Cache Python Rust dependencies
|
|
206
|
-
uses: Swatinem/rust-cache@
|
|
210
|
+
uses: Swatinem/rust-cache@f0d9c3887740aee45f6153b24b3a6b815192ec16 # v2
|
|
207
211
|
with:
|
|
208
212
|
shared-key: ci-${{ runner.os }}-python
|
|
209
213
|
workspaces: python -> target
|
|
210
214
|
save-if: ${{ github.event_name == 'pull_request' || github.ref == 'refs/heads/master' }}
|
|
211
215
|
- name: Set up uv
|
|
212
|
-
uses: astral-sh/setup-uv@
|
|
216
|
+
uses: astral-sh/setup-uv@20cfd1bf945f4377ade1205e4dbc17946fc9a30d # v10.0.1
|
|
213
217
|
with:
|
|
214
218
|
python-version: "3.11"
|
|
215
219
|
enable-cache: true
|
|
216
220
|
cache-dependency-glob: "python/uv.lock"
|
|
217
221
|
- name: Python bindings (isolated wheel OS compatibility)
|
|
218
|
-
run: python scripts/ci/lme_ci.py python --python-version 3.11 --wheel-only
|
|
222
|
+
run: python scripts/ci/lme_ci.py python --python-version 3.11 --wheel-only --examples
|
|
219
223
|
|
|
220
224
|
publish-crate:
|
|
221
225
|
name: Publish Rust crate after CI
|
|
@@ -236,7 +240,7 @@ jobs:
|
|
|
236
240
|
secrets: inherit
|
|
237
241
|
|
|
238
242
|
publish-python:
|
|
239
|
-
name:
|
|
243
|
+
name: Dispatch Python release after CI
|
|
240
244
|
if: startsWith(github.ref, 'refs/tags/v')
|
|
241
245
|
needs:
|
|
242
246
|
- release-policy
|
|
@@ -247,8 +251,19 @@ jobs:
|
|
|
247
251
|
- python-bindings-versions
|
|
248
252
|
- python-bindings-os
|
|
249
253
|
permissions:
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
254
|
+
actions: write
|
|
255
|
+
contents: read
|
|
256
|
+
runs-on: ubuntu-latest
|
|
257
|
+
steps:
|
|
258
|
+
- name: Dispatch verified Python release
|
|
259
|
+
env:
|
|
260
|
+
GH_TOKEN: ${{ github.token }}
|
|
261
|
+
RELEASE_SHA: ${{ github.sha }}
|
|
262
|
+
RELEASE_TAG: ${{ github.ref_name }}
|
|
263
|
+
run: |
|
|
264
|
+
gh workflow run python-release.yml \
|
|
265
|
+
--repo "${GITHUB_REPOSITORY}" \
|
|
266
|
+
--ref master \
|
|
267
|
+
-f release_tag="${RELEASE_TAG}" \
|
|
268
|
+
-f release_sha="${RELEASE_SHA}" \
|
|
269
|
+
-f publish=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
|
|
@@ -1,28 +1,96 @@
|
|
|
1
1
|
name: Build and Publish Python Wheels
|
|
2
2
|
|
|
3
|
-
# CI
|
|
4
|
-
#
|
|
3
|
+
# CI dispatches this top-level workflow after every release-tag validation job
|
|
4
|
+
# succeeds. PyPI Trusted Publishing does not support publishing from a reusable
|
|
5
|
+
# workflow with attestations, so this workflow must retain its own identity.
|
|
5
6
|
on:
|
|
6
|
-
|
|
7
|
+
workflow_dispatch:
|
|
7
8
|
inputs:
|
|
9
|
+
release_tag:
|
|
10
|
+
description: Validated v* tag to build; blank builds the selected ref
|
|
11
|
+
required: false
|
|
12
|
+
type: string
|
|
13
|
+
default: ""
|
|
14
|
+
release_sha:
|
|
15
|
+
description: Exact validated commit for a publishing run
|
|
16
|
+
required: false
|
|
17
|
+
type: string
|
|
18
|
+
default: ""
|
|
8
19
|
publish:
|
|
9
|
-
description: Publish the
|
|
20
|
+
description: Publish the verified release tag to PyPI
|
|
10
21
|
required: false
|
|
11
22
|
type: boolean
|
|
12
23
|
default: false
|
|
13
|
-
workflow_dispatch:
|
|
14
24
|
|
|
15
25
|
permissions:
|
|
16
26
|
contents: read
|
|
17
27
|
|
|
28
|
+
env:
|
|
29
|
+
RELEASE_REF: ${{ inputs.release_tag || github.ref }}
|
|
30
|
+
|
|
18
31
|
jobs:
|
|
32
|
+
verify-release:
|
|
33
|
+
name: Verify release target
|
|
34
|
+
runs-on: ubuntu-latest
|
|
35
|
+
steps:
|
|
36
|
+
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
37
|
+
with:
|
|
38
|
+
fetch-depth: 0
|
|
39
|
+
ref: ${{ env.RELEASE_REF }}
|
|
40
|
+
|
|
41
|
+
- name: Verify validated tag and package versions
|
|
42
|
+
if: inputs.publish
|
|
43
|
+
env:
|
|
44
|
+
RELEASE_SHA: ${{ inputs.release_sha }}
|
|
45
|
+
RELEASE_TAG: ${{ inputs.release_tag }}
|
|
46
|
+
run: |
|
|
47
|
+
set -euo pipefail
|
|
48
|
+
|
|
49
|
+
if [[ ! "${RELEASE_TAG}" =~ ^v[0-9]+\.[0-9]+\.[0-9]+([.-][0-9A-Za-z.-]+)?$ ]]; then
|
|
50
|
+
echo "Publishing requires an explicit semantic v* release tag." >&2
|
|
51
|
+
exit 1
|
|
52
|
+
fi
|
|
53
|
+
if [[ ! "${RELEASE_SHA}" =~ ^[0-9a-f]{40}$ ]]; then
|
|
54
|
+
echo "Publishing requires the exact 40-character validated commit SHA." >&2
|
|
55
|
+
exit 1
|
|
56
|
+
fi
|
|
57
|
+
|
|
58
|
+
actual_sha="$(git rev-list -n 1 "refs/tags/${RELEASE_TAG}")"
|
|
59
|
+
if [[ "${actual_sha}" != "${RELEASE_SHA}" ]]; then
|
|
60
|
+
echo "Tag ${RELEASE_TAG} resolves to ${actual_sha}, not validated SHA ${RELEASE_SHA}." >&2
|
|
61
|
+
exit 1
|
|
62
|
+
fi
|
|
63
|
+
if [[ "$(git rev-parse HEAD)" != "${RELEASE_SHA}" ]]; then
|
|
64
|
+
echo "Checked-out release does not match validated SHA ${RELEASE_SHA}." >&2
|
|
65
|
+
exit 1
|
|
66
|
+
fi
|
|
67
|
+
|
|
68
|
+
python - "${RELEASE_TAG#v}" <<'PY'
|
|
69
|
+
import pathlib
|
|
70
|
+
import sys
|
|
71
|
+
import tomllib
|
|
72
|
+
|
|
73
|
+
expected = sys.argv[1]
|
|
74
|
+
manifests = (pathlib.Path("Cargo.toml"), pathlib.Path("python/Cargo.toml"))
|
|
75
|
+
for manifest in manifests:
|
|
76
|
+
with manifest.open("rb") as stream:
|
|
77
|
+
actual = tomllib.load(stream)["package"]["version"]
|
|
78
|
+
if actual != expected:
|
|
79
|
+
raise SystemExit(
|
|
80
|
+
f"{manifest}: package version {actual!r} does not match tag {expected!r}"
|
|
81
|
+
)
|
|
82
|
+
PY
|
|
83
|
+
|
|
19
84
|
linux:
|
|
85
|
+
needs: verify-release
|
|
20
86
|
runs-on: ubuntu-latest
|
|
21
87
|
strategy:
|
|
22
88
|
matrix:
|
|
23
89
|
target: [x86_64, aarch64]
|
|
24
90
|
steps:
|
|
25
91
|
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
92
|
+
with:
|
|
93
|
+
ref: ${{ env.RELEASE_REF }}
|
|
26
94
|
- uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0
|
|
27
95
|
with:
|
|
28
96
|
python-version: '3.10'
|
|
@@ -59,12 +127,15 @@ jobs:
|
|
|
59
127
|
path: dist
|
|
60
128
|
|
|
61
129
|
windows:
|
|
130
|
+
needs: verify-release
|
|
62
131
|
runs-on: windows-latest
|
|
63
132
|
strategy:
|
|
64
133
|
matrix:
|
|
65
134
|
target: [x64]
|
|
66
135
|
steps:
|
|
67
136
|
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
137
|
+
with:
|
|
138
|
+
ref: ${{ env.RELEASE_REF }}
|
|
68
139
|
- uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0
|
|
69
140
|
with:
|
|
70
141
|
python-version: '3.10'
|
|
@@ -89,12 +160,15 @@ jobs:
|
|
|
89
160
|
path: dist
|
|
90
161
|
|
|
91
162
|
macos:
|
|
163
|
+
needs: verify-release
|
|
92
164
|
runs-on: macos-latest
|
|
93
165
|
strategy:
|
|
94
166
|
matrix:
|
|
95
167
|
target: [x86_64, aarch64]
|
|
96
168
|
steps:
|
|
97
169
|
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
170
|
+
with:
|
|
171
|
+
ref: ${{ env.RELEASE_REF }}
|
|
98
172
|
- uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0
|
|
99
173
|
with:
|
|
100
174
|
python-version: '3.10'
|
|
@@ -124,9 +198,12 @@ jobs:
|
|
|
124
198
|
path: dist
|
|
125
199
|
|
|
126
200
|
sdist:
|
|
201
|
+
needs: verify-release
|
|
127
202
|
runs-on: ubuntu-latest
|
|
128
203
|
steps:
|
|
129
204
|
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
205
|
+
with:
|
|
206
|
+
ref: ${{ env.RELEASE_REF }}
|
|
130
207
|
- uses: dtolnay/rust-toolchain@4cda84d5c5c54efe2404f9d843567869ab1699d4 # stable
|
|
131
208
|
with:
|
|
132
209
|
toolchain: stable
|
|
@@ -147,14 +224,16 @@ jobs:
|
|
|
147
224
|
name: Publish to PyPI
|
|
148
225
|
needs: [linux, windows, macos, sdist]
|
|
149
226
|
runs-on: ubuntu-latest
|
|
150
|
-
#
|
|
151
|
-
if:
|
|
227
|
+
# Publication requires the explicit opt-in and exact tag/SHA verification above.
|
|
228
|
+
if: inputs.publish
|
|
152
229
|
environment: pypi
|
|
153
230
|
permissions:
|
|
154
231
|
id-token: write # IMPORTANT: this permission is mandatory for trusted publishing
|
|
155
232
|
contents: write # needed to create GitHub Release
|
|
156
233
|
steps:
|
|
157
234
|
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
235
|
+
with:
|
|
236
|
+
ref: ${{ env.RELEASE_REF }}
|
|
158
237
|
|
|
159
238
|
- uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0
|
|
160
239
|
with:
|
|
@@ -174,9 +253,10 @@ jobs:
|
|
|
174
253
|
done
|
|
175
254
|
|
|
176
255
|
- name: Publish to PyPI
|
|
177
|
-
uses: pypa/gh-action-pypi-publish@
|
|
256
|
+
uses: pypa/gh-action-pypi-publish@dc37677b2e1c63e2034f94d8a5b11f265b73ba33 # release/v1
|
|
178
257
|
|
|
179
258
|
- name: Upload to GitHub Release
|
|
180
|
-
uses: softprops/action-gh-release@
|
|
259
|
+
uses: softprops/action-gh-release@efb35369e0ad2afab669f228072c1b0d510eae64 # v3.0.3
|
|
181
260
|
with:
|
|
182
261
|
files: dist/*
|
|
262
|
+
tag_name: ${{ inputs.release_tag }}
|
|
@@ -10,6 +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` (includes dashboard JSON drift); use `task consumer:smoke` when install or example behavior changes |
|
|
13
14
|
| LMM throughput paths (`src/math.rs`, `src/optimizer.rs`) | Read [OPTIMIZATION.md](OPTIMIZATION.md) and run the applicable fair-harness cases |
|
|
14
15
|
| Completion score files: `README.md`, `REPO_COMPLETION_BY_AREA.md`, `completion_manifest.json`, or `scripts/ci/check_completion_score.py` | `task completion:check` |
|
|
15
16
|
|
|
@@ -19,10 +20,10 @@ For a change that crosses several rows, run every applicable check. Full Rust in
|
|
|
19
20
|
|
|
20
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.
|
|
21
22
|
|
|
22
|
-
- [completion_manifest.json](completion_manifest.json) is the source of truth: it declares binary scope commitments, their weights,
|
|
23
|
-
- `task completion:check` validates evidence-path existence, score arithmetic, report rows, and the README headline.
|
|
24
|
-
- A completion item may be marked complete only when its stated evidence is current. Partial or
|
|
25
|
-
- 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.
|
|
26
27
|
|
|
27
28
|
`task ci` runs this check automatically. Run it directly whenever a completion-related file changes.
|
|
28
29
|
|
|
@@ -70,11 +71,11 @@ Use `--no-verify` only when explicitly necessary; report the bypass and the chec
|
|
|
70
71
|
|
|
71
72
|
## CI and release boundaries
|
|
72
73
|
|
|
73
|
-
GitHub Actions validation runs automatically on pull requests and `v*` tags, and can be manually dispatched. Ordinary non-PR branch pushes do not receive the hosted validation matrix automatically. A lightweight cache-prime workflow runs when Rust dependency inputs change on `master` and weekly so new PRs can reuse trusted dependency artifacts. Pull requests run the full matrix except the four ignored heavy production-load cases. The tag CI calls the crates.io and PyPI
|
|
74
|
+
GitHub Actions validation runs automatically on pull requests and `v*` tags, and can be manually dispatched. Ordinary non-PR branch pushes do not receive the hosted validation matrix automatically. A lightweight cache-prime workflow runs when Rust dependency inputs change on `master` and weekly so new PRs can reuse trusted dependency artifacts. Pull requests run the full matrix except the four ignored heavy production-load cases. The tag CI calls the crates.io workflow and dispatches the top-level PyPI workflow only after every validation job succeeds; the publishing workflows do not listen to tags independently. The PyPI workflow must remain top-level because Trusted Publishing attestations do not support a reusable publishing workflow.
|
|
74
75
|
|
|
75
76
|
External GitHub Actions are pinned to full commit SHAs, with the readable release line retained as a comment. Dependabot proposes grouped weekly pin updates; do not replace SHA pins with mutable tags. Dependency audits and libFuzzer smoke tests run weekly in addition to their release/manual entry points.
|
|
76
77
|
|
|
77
|
-
- `task ci` mirrors the core hosted flow: Rust tests, Python bindings, lint, all-targets check, legal checks,
|
|
78
|
+
- `task ci` mirrors the core hosted flow: Rust tests, Python bindings, portable consumer examples, lint, all-targets check, legal checks, documentation/link verification, and the completion-score check.
|
|
78
79
|
- Hosted-only coverage includes the multi-OS matrix, Python 3.10–3.13, production-load gates, and `pip-audit`.
|
|
79
80
|
- After changing BLAS target tables or release workflows, run `task ci` locally or manually dispatch CI before tagging; macOS Apple Silicon BLAS is not exercised on Windows/Linux.
|
|
80
81
|
- Benchmark workflow coverage requiring R or Julia belongs in the tag/manual workflow. `task benchmarks:preflight` runs the Rust smoke plus the R smoke when R/lme4 is available.
|
|
@@ -93,8 +94,20 @@ For repository-metadata token issues, set `REPO_ADMIN_TOKEN` locally and run `ta
|
|
|
93
94
|
| `task ci` / `task ci:fast` | Core CI mirror / reuse the editable Python environment and skip the isolated-wheel pass |
|
|
94
95
|
| `task audit` / `task legal` | Security audit / provenance and license checks |
|
|
95
96
|
| `task completion:check` | Verify the manifest-derived completion score and published markers |
|
|
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 |
|
|
96
99
|
| `task benchmarks:fair-rust-julia` | Fair fit-only Rust vs MixedModels.jl timing when Julia packages are installed |
|
|
97
100
|
| `task benchmarks:perf-breakdown` | Rust phase timings against Julia optimizer evaluation counts |
|
|
101
|
+
| `task benchmarks:external-timings` | Fair-ish `nlmer`, post-fit inference, and Python FFI timings vs R when available |
|
|
102
|
+
| `task explorations` | Standalone native-parser AST, θ-grid, and MCP exploration examples |
|
|
98
103
|
| `task lint:comparisons` | Optional R/Julia comparison formatting check |
|
|
99
104
|
|
|
100
105
|
Run `python scripts/ci/lme_ci.py --help` for the complete command list. See [CONTRIBUTING.md](CONTRIBUTING.md) for contributor workflow and [RELEASING.md](RELEASING.md) for release steps.
|
|
106
|
+
|
|
107
|
+
## Cursor Cloud specific instructions
|
|
108
|
+
|
|
109
|
+
This repo is a pure Rust library (`lme-rs`) plus a PyO3/maturin Python binding (`lme_python`); there are no servers or long-running services. "Running the app" means building the crate and running examples/tests. See the command reference above for the canonical `task` aliases.
|
|
110
|
+
|
|
111
|
+
- Toolchain comes from `mise` (per [mise.toml](mise.toml): Rust stable, Python 3.11, `uv`, `task`, `lefthook`). The startup update script runs `mise install`. Interactive shells auto-activate mise via `~/.bashrc`. In a non-interactive shell where `mise`/`task`/`uv` aren't on `PATH`, run `eval "$($HOME/.local/bin/mise activate bash --shims)"` first (or invoke tools with `$HOME/.local/bin/mise exec -- <cmd>`).
|
|
112
|
+
- On x86_64 the core crate links Intel MKL statically via `ndarray-linalg`, so no `gfortran`/system BLAS is needed; the first `cargo build`/`task test:fast` compiles MKL and takes a few minutes (subsequent builds are cached). Examples must be run with `--release` (e.g. `cargo run --release --example sleepstudy`) — a debug build is very slow.
|
|
113
|
+
- Python bindings gotcha: `uv sync` / `task ci` / `task python` reinstall the venv and **uninstall** the maturin-built `lme_python` before rebuilding it. If you run a bare `uv sync` (or interrupt `task python` before its maturin step), `import lme_python` breaks; restore it with `cd python && uv run --no-sync maturin develop --release` (or re-run `task python`). Run Python examples from `python/` via `uv run --no-sync python examples/<name>.py`.
|