lme-python 0.1.3__tar.gz → 0.1.7__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.1.7/.github/workflows/audit.yml +73 -0
- {lme_python-0.1.3 → lme_python-0.1.7}/.github/workflows/benchmarks.yml +2 -0
- lme_python-0.1.7/.github/workflows/ci.yml +225 -0
- lme_python-0.1.7/.github/workflows/crate-publish-dry-run.yml +28 -0
- lme_python-0.1.7/.github/workflows/fuzz-smoke.yml +34 -0
- {lme_python-0.1.3 → lme_python-0.1.7}/.github/workflows/python-release.yml +12 -12
- {lme_python-0.1.3 → lme_python-0.1.7}/.github/workflows/repo-metadata.yml +1 -1
- {lme_python-0.1.3 → lme_python-0.1.7}/.gitignore +5 -0
- {lme_python-0.1.3 → lme_python-0.1.7}/BENCHMARKS.md +29 -1
- lme_python-0.1.7/CHANGELOG.md +103 -0
- lme_python-0.1.7/CONTRIBUTING.md +122 -0
- {lme_python-0.1.3 → lme_python-0.1.7}/Cargo.lock +11 -11
- {lme_python-0.1.3 → lme_python-0.1.7}/Cargo.toml +50 -1
- {lme_python-0.1.3 → lme_python-0.1.7}/GUIDE.md +16 -13
- {lme_python-0.1.3 → lme_python-0.1.7}/PKG-INFO +5 -1
- {lme_python-0.1.3 → lme_python-0.1.7}/README.md +22 -11
- {lme_python-0.1.3 → lme_python-0.1.7}/RELEASING.md +30 -7
- lme_python-0.1.7/REPO_COMPLETION_BY_AREA.md +74 -0
- lme_python-0.1.7/benches/bench_load_production.rs +188 -0
- {lme_python-0.1.3 → lme_python-0.1.7}/benches/bench_math.rs +41 -0
- {lme_python-0.1.3/examples → lme_python-0.1.7/comparisons}/COMPARISONS.md +309 -78
- lme_python-0.1.7/comparisons/categorical_anova.R +17 -0
- lme_python-0.1.7/comparisons/categorical_anova.jl +13 -0
- lme_python-0.1.7/comparisons/categorical_anova.py +16 -0
- lme_python-0.1.7/comparisons/categorical_anova.rs +24 -0
- {lme_python-0.1.3/examples → lme_python-0.1.7/comparisons}/glmm_cbpp.R +15 -5
- {lme_python-0.1.3/examples → lme_python-0.1.7/comparisons}/glmm_cbpp.jl +3 -0
- lme_python-0.1.7/comparisons/glmm_cbpp.py +66 -0
- {lme_python-0.1.3/examples → lme_python-0.1.7/comparisons}/glmm_cbpp.rs +8 -4
- lme_python-0.1.7/comparisons/glmm_gaussian.R +29 -0
- lme_python-0.1.7/comparisons/glmm_gaussian.jl +29 -0
- lme_python-0.1.7/comparisons/glmm_gaussian.py +54 -0
- lme_python-0.1.7/comparisons/glmm_gaussian.rs +46 -0
- {lme_python-0.1.3/examples → lme_python-0.1.7/comparisons}/glmm_grouseticks.rs +1 -1
- lme_python-0.1.7/comparisons/lmer_weighted.R +28 -0
- lme_python-0.1.7/comparisons/lmer_weighted.jl +37 -0
- lme_python-0.1.7/comparisons/lmer_weighted.py +63 -0
- lme_python-0.1.7/comparisons/lmer_weighted.rs +51 -0
- lme_python-0.1.7/comparisons/lmm_dyestuff.py +33 -0
- lme_python-0.1.7/comparisons/lmm_pastes.py +47 -0
- lme_python-0.1.7/comparisons/lmm_penicillin.py +43 -0
- lme_python-0.1.7/docs/benchmarks/app.js +207 -0
- lme_python-0.1.7/docs/benchmarks/index.html +92 -0
- lme_python-0.1.7/docs/benchmarks/styles.css +305 -0
- lme_python-0.1.7/docs/index.html +63 -0
- {lme_python-0.1.3 → lme_python-0.1.7}/pyproject.toml +7 -0
- {lme_python-0.1.3 → lme_python-0.1.7}/python/Cargo.lock +22 -21
- {lme_python-0.1.3 → lme_python-0.1.7}/python/Cargo.toml +3 -2
- {lme_python-0.1.3 → lme_python-0.1.7}/python/PYTHON_GUIDE.md +63 -2
- lme_python-0.1.7/python/examples/glmer_cbpp.py +92 -0
- lme_python-0.1.7/python/examples/glmer_grouseticks.py +99 -0
- lme_python-0.1.7/python/examples/lm_basics.py +84 -0
- lme_python-0.1.7/python/examples/lmer_sleepstudy.py +96 -0
- lme_python-0.1.7/python/examples/model_comparison.py +117 -0
- lme_python-0.1.7/python/examples/plotting_demo/.gitignore +6 -0
- lme_python-0.1.7/python/examples/plotting_demo/README.md +129 -0
- lme_python-0.1.7/python/examples/plotting_demo/compare_plots.py +310 -0
- lme_python-0.1.7/python/examples/plotting_demo/figure_specs.py +45 -0
- lme_python-0.1.7/python/examples/plotting_demo/find_rscript.py +92 -0
- lme_python-0.1.7/python/examples/plotting_demo/numeric_overlay.py +143 -0
- lme_python-0.1.7/python/examples/plotting_demo/paths.py +14 -0
- lme_python-0.1.7/python/examples/plotting_demo/plot_demo.py +185 -0
- lme_python-0.1.7/python/examples/plotting_demo/plot_r.R +177 -0
- lme_python-0.1.7/python/examples/plotting_demo/run_all.py +58 -0
- lme_python-0.1.7/python/examples/verification_project/README.md +42 -0
- lme_python-0.1.7/python/examples/verification_project/conftest.py +8 -0
- lme_python-0.1.7/python/examples/verification_project/parity.py +197 -0
- lme_python-0.1.7/python/examples/verification_project/paths.py +14 -0
- lme_python-0.1.7/python/examples/verification_project/run.py +39 -0
- lme_python-0.1.7/python/examples/verification_project/test_parity.py +41 -0
- lme_python-0.1.7/python/requirements-ci.txt +87 -0
- lme_python-0.1.7/python/src/lib.rs +675 -0
- lme_python-0.1.7/python/tests/test_basic.py +406 -0
- lme_python-0.1.7/scripts/build_benchmark_site.py +210 -0
- lme_python-0.1.7/scripts/local_ci.ps1 +85 -0
- lme_python-0.1.7/scripts/local_ci.sh +86 -0
- {lme_python-0.1.3 → lme_python-0.1.7}/scripts/plot_comparisons.py +2 -2
- {lme_python-0.1.3 → lme_python-0.1.7}/scripts/run_cross_language_benchmarks.py +31 -13
- lme_python-0.1.7/src/anova.rs +398 -0
- lme_python-0.1.7/src/anova_contrasts.rs +208 -0
- lme_python-0.1.7/src/ddf.rs +196 -0
- {lme_python-0.1.3 → lme_python-0.1.7}/src/family.rs +2 -2
- {lme_python-0.1.3 → lme_python-0.1.7}/src/formula.rs +21 -0
- lme_python-0.1.7/src/glmm_math.rs +1217 -0
- {lme_python-0.1.3 → lme_python-0.1.7}/src/lib.rs +384 -33
- {lme_python-0.1.3 → lme_python-0.1.7}/src/model_matrix.rs +255 -14
- {lme_python-0.1.3 → lme_python-0.1.7}/src/optimizer.rs +88 -64
- {lme_python-0.1.3 → lme_python-0.1.7}/src/robust.rs +8 -2
- {lme_python-0.1.3 → lme_python-0.1.7}/src/satterthwaite.rs +32 -22
- lme_python-0.1.7/tests/categorical_anova_test.rs +42 -0
- lme_python-0.1.7/tests/data/golden_parity_manifest.json +440 -0
- {lme_python-0.1.3 → lme_python-0.1.7}/tests/data/intercept_only.json +2 -0
- {lme_python-0.1.3 → lme_python-0.1.7}/tests/data/mock_ml.json +2 -0
- lme_python-0.1.7/tests/data/pastes_cask_reml.json +13 -0
- lme_python-0.1.7/tests/data/penicillin.csv +145 -0
- {lme_python-0.1.3 → lme_python-0.1.7}/tests/data/penicillin.json +2 -0
- {lme_python-0.1.3 → lme_python-0.1.7}/tests/data/random_slopes.json +2 -0
- lme_python-0.1.7/tests/generate_test_data.R +506 -0
- {lme_python-0.1.3 → lme_python-0.1.7}/tests/test_anova.rs +6 -6
- lme_python-0.1.7/tests/test_anova_types.rs +56 -0
- {lme_python-0.1.3 → lme_python-0.1.7}/tests/test_confint_simulate.rs +62 -1
- {lme_python-0.1.3 → lme_python-0.1.7}/tests/test_coverage_edge_cases.rs +2 -1
- {lme_python-0.1.3 → lme_python-0.1.7}/tests/test_coverage_gaps.rs +3 -0
- lme_python-0.1.7/tests/test_failure_modes.rs +222 -0
- lme_python-0.1.7/tests/test_formula_stress.rs +316 -0
- {lme_python-0.1.3 → lme_python-0.1.7}/tests/test_gaps.rs +10 -3
- {lme_python-0.1.3 → lme_python-0.1.7}/tests/test_glmm.rs +140 -0
- lme_python-0.1.7/tests/test_golden_parity.rs +543 -0
- lme_python-0.1.7/tests/test_production_load.rs +360 -0
- lme_python-0.1.7/tests/test_statistical_identities.rs +294 -0
- lme_python-0.1.3/.github/workflows/ci.yml +0 -66
- lme_python-0.1.3/CHANGELOG.md +0 -60
- lme_python-0.1.3/CONTRIBUTING.md +0 -91
- lme_python-0.1.3/examples/glmm_cbpp.py +0 -45
- lme_python-0.1.3/examples/lmm_dyestuff.py +0 -21
- lme_python-0.1.3/examples/lmm_pastes.py +0 -35
- lme_python-0.1.3/examples/lmm_penicillin.py +0 -35
- lme_python-0.1.3/python/src/lib.rs +0 -201
- lme_python-0.1.3/python/tests/test_basic.py +0 -164
- lme_python-0.1.3/src/anova.rs +0 -164
- lme_python-0.1.3/src/glmm_math.rs +0 -558
- lme_python-0.1.3/tests/data/penicillin.csv +0 -145
- lme_python-0.1.3/tests/generate_test_data.R +0 -231
- {lme_python-0.1.3 → lme_python-0.1.7}/LICENSE +0 -0
- {lme_python-0.1.3/examples → lme_python-0.1.7/comparisons}/comparison_chart.png +0 -0
- {lme_python-0.1.3/examples → lme_python-0.1.7/comparisons}/glmm_grouseticks.R +0 -0
- {lme_python-0.1.3/examples → lme_python-0.1.7/comparisons}/glmm_grouseticks.jl +0 -0
- {lme_python-0.1.3/examples → lme_python-0.1.7/comparisons}/glmm_grouseticks.py +0 -0
- {lme_python-0.1.3/examples → lme_python-0.1.7/comparisons}/lmm_dyestuff.R +0 -0
- {lme_python-0.1.3/examples → lme_python-0.1.7/comparisons}/lmm_dyestuff.jl +0 -0
- {lme_python-0.1.3/examples → lme_python-0.1.7/comparisons}/lmm_dyestuff.rs +0 -0
- {lme_python-0.1.3/examples → lme_python-0.1.7/comparisons}/lmm_pastes.R +0 -0
- {lme_python-0.1.3/examples → lme_python-0.1.7/comparisons}/lmm_pastes.jl +0 -0
- {lme_python-0.1.3/examples → lme_python-0.1.7/comparisons}/lmm_pastes.rs +0 -0
- {lme_python-0.1.3/examples → lme_python-0.1.7/comparisons}/lmm_penicillin.R +0 -0
- {lme_python-0.1.3/examples → lme_python-0.1.7/comparisons}/lmm_penicillin.jl +0 -0
- {lme_python-0.1.3/examples → lme_python-0.1.7/comparisons}/lmm_penicillin.rs +0 -0
- {lme_python-0.1.3/examples → lme_python-0.1.7/comparisons}/sleepstudy.R +0 -0
- {lme_python-0.1.3/examples → lme_python-0.1.7/comparisons}/sleepstudy.jl +0 -0
- {lme_python-0.1.3/examples → lme_python-0.1.7/comparisons}/sleepstudy.py +0 -0
- {lme_python-0.1.3/examples → lme_python-0.1.7/comparisons}/sleepstudy.rs +0 -0
- {lme_python-0.1.3/examples → lme_python-0.1.7/comparisons}/sleepstudy_ml.R +0 -0
- {lme_python-0.1.3/examples → lme_python-0.1.7/comparisons}/sleepstudy_ml.jl +0 -0
- {lme_python-0.1.3/examples → lme_python-0.1.7/comparisons}/sleepstudy_ml.py +0 -0
- {lme_python-0.1.3/examples → lme_python-0.1.7/comparisons}/sleepstudy_ml.rs +0 -0
- {lme_python-0.1.3 → lme_python-0.1.7}/scripts/ast_explorations/test_fiasto.rs +0 -0
- {lme_python-0.1.3 → lme_python-0.1.7}/scripts/ast_explorations/test_fiasto_offset.rs +0 -0
- {lme_python-0.1.3 → lme_python-0.1.7}/scripts/dump_dyestuff.R +0 -0
- {lme_python-0.1.3 → lme_python-0.1.7}/scripts/dump_pastes.R +0 -0
- {lme_python-0.1.3 → lme_python-0.1.7}/scripts/make_penicillin_csv.py +0 -0
- {lme_python-0.1.3 → lme_python-0.1.7}/scripts/sync_github_repo_metadata.py +0 -0
- {lme_python-0.1.3 → lme_python-0.1.7}/src/kenward_roger.rs +0 -0
- {lme_python-0.1.3 → lme_python-0.1.7}/src/math.rs +0 -0
- {lme_python-0.1.3 → lme_python-0.1.7}/tests/data/cbpp_binary.csv +0 -0
- {lme_python-0.1.3 → lme_python-0.1.7}/tests/data/dyestuff.csv +0 -0
- {lme_python-0.1.3 → lme_python-0.1.7}/tests/data/glmm_binomial.json +0 -0
- {lme_python-0.1.3 → lme_python-0.1.7}/tests/data/glmm_poisson.json +0 -0
- {lme_python-0.1.3 → lme_python-0.1.7}/tests/data/grouseticks.csv +0 -0
- {lme_python-0.1.3 → lme_python-0.1.7}/tests/data/mock_crossed.json +0 -0
- {lme_python-0.1.3 → lme_python-0.1.7}/tests/data/pastes.csv +0 -0
- {lme_python-0.1.3 → lme_python-0.1.7}/tests/data/sleepstudy.csv +0 -0
- {lme_python-0.1.3 → lme_python-0.1.7}/tests/generate_mock_data.py +0 -0
- {lme_python-0.1.3 → lme_python-0.1.7}/tests/test_conditional_real.rs +0 -0
- {lme_python-0.1.3 → lme_python-0.1.7}/tests/test_crossed_mock.rs +0 -0
- {lme_python-0.1.3 → lme_python-0.1.7}/tests/test_e2e_lmer.rs +0 -0
- {lme_python-0.1.3 → lme_python-0.1.7}/tests/test_edge_cases.rs +0 -0
- {lme_python-0.1.3 → lme_python-0.1.7}/tests/test_errors.rs +0 -0
- {lme_python-0.1.3 → lme_python-0.1.7}/tests/test_formula.rs +0 -0
- {lme_python-0.1.3 → lme_python-0.1.7}/tests/test_intercept_only.rs +0 -0
- {lme_python-0.1.3 → lme_python-0.1.7}/tests/test_kenward_roger.rs +0 -0
- {lme_python-0.1.3 → lme_python-0.1.7}/tests/test_ml_optimization.rs +0 -0
- {lme_python-0.1.3 → lme_python-0.1.7}/tests/test_no_intercept.rs +0 -0
- {lme_python-0.1.3 → lme_python-0.1.7}/tests/test_numerical_parity.rs +0 -0
- {lme_python-0.1.3 → lme_python-0.1.7}/tests/test_predict.rs +0 -0
- {lme_python-0.1.3 → lme_python-0.1.7}/tests/test_random_slopes.rs +0 -0
- {lme_python-0.1.3 → lme_python-0.1.7}/tests/test_robust.rs +0 -0
- {lme_python-0.1.3 → lme_python-0.1.7}/tests/test_sandwich_math.R +0 -0
- {lme_python-0.1.3 → lme_python-0.1.7}/tests/test_satterthwaite.rs +0 -0
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
name: Security audit
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
schedule:
|
|
5
|
+
# Weekly: Mondays 12:00 UTC
|
|
6
|
+
- cron: "0 12 * * 1"
|
|
7
|
+
workflow_dispatch:
|
|
8
|
+
push:
|
|
9
|
+
branches: [master]
|
|
10
|
+
paths:
|
|
11
|
+
- "**/Cargo.toml"
|
|
12
|
+
- "**/Cargo.lock"
|
|
13
|
+
- "python/pyproject.toml"
|
|
14
|
+
- "python/requirements-ci.txt"
|
|
15
|
+
pull_request:
|
|
16
|
+
branches: [master]
|
|
17
|
+
paths:
|
|
18
|
+
- "**/Cargo.toml"
|
|
19
|
+
- "**/Cargo.lock"
|
|
20
|
+
- "python/pyproject.toml"
|
|
21
|
+
- "python/requirements-ci.txt"
|
|
22
|
+
|
|
23
|
+
permissions:
|
|
24
|
+
contents: read
|
|
25
|
+
|
|
26
|
+
concurrency:
|
|
27
|
+
group: audit-${{ github.workflow }}-${{ github.ref }}
|
|
28
|
+
cancel-in-progress: true
|
|
29
|
+
|
|
30
|
+
jobs:
|
|
31
|
+
audit:
|
|
32
|
+
name: cargo audit
|
|
33
|
+
runs-on: ubuntu-latest
|
|
34
|
+
steps:
|
|
35
|
+
- uses: actions/checkout@v6
|
|
36
|
+
|
|
37
|
+
- uses: dtolnay/rust-toolchain@stable
|
|
38
|
+
|
|
39
|
+
- name: Install cargo-audit
|
|
40
|
+
uses: taiki-e/install-action@v2
|
|
41
|
+
with:
|
|
42
|
+
tool: cargo-audit@0.22.1
|
|
43
|
+
|
|
44
|
+
- name: Run cargo audit (root)
|
|
45
|
+
run: cargo audit
|
|
46
|
+
|
|
47
|
+
- name: Run cargo audit (python/)
|
|
48
|
+
working-directory: python
|
|
49
|
+
run: cargo audit
|
|
50
|
+
|
|
51
|
+
pip-audit:
|
|
52
|
+
name: pip-audit (python lockfile)
|
|
53
|
+
runs-on: ubuntu-latest
|
|
54
|
+
steps:
|
|
55
|
+
- uses: actions/checkout@v6
|
|
56
|
+
|
|
57
|
+
- name: Set up Python
|
|
58
|
+
uses: actions/setup-python@v6
|
|
59
|
+
with:
|
|
60
|
+
python-version: "3.11"
|
|
61
|
+
cache: pip
|
|
62
|
+
cache-dependency-path: python/requirements-ci.txt
|
|
63
|
+
|
|
64
|
+
- name: Install locked CI dependencies
|
|
65
|
+
working-directory: python
|
|
66
|
+
run: |
|
|
67
|
+
set -euo pipefail
|
|
68
|
+
python -m pip install -U pip
|
|
69
|
+
python -m pip install -r requirements-ci.txt
|
|
70
|
+
|
|
71
|
+
- name: pip-audit
|
|
72
|
+
working-directory: python
|
|
73
|
+
run: python -m pip_audit
|
|
@@ -17,6 +17,7 @@ on:
|
|
|
17
17
|
|
|
18
18
|
permissions:
|
|
19
19
|
contents: write
|
|
20
|
+
id-token: write
|
|
20
21
|
|
|
21
22
|
env:
|
|
22
23
|
CARGO_TERM_COLOR: always
|
|
@@ -169,3 +170,4 @@ jobs:
|
|
|
169
170
|
run: |
|
|
170
171
|
echo "Cross-language benchmark script failed with exit code ${{ steps.cross_language_run.outputs.status }}." >&2
|
|
171
172
|
exit 1
|
|
173
|
+
|
|
@@ -0,0 +1,225 @@
|
|
|
1
|
+
name: CI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [master]
|
|
6
|
+
paths-ignore:
|
|
7
|
+
- "**/*.md"
|
|
8
|
+
- "LICENSE"
|
|
9
|
+
pull_request:
|
|
10
|
+
branches: [master]
|
|
11
|
+
paths-ignore:
|
|
12
|
+
- "**/*.md"
|
|
13
|
+
- "LICENSE"
|
|
14
|
+
|
|
15
|
+
permissions:
|
|
16
|
+
contents: read
|
|
17
|
+
|
|
18
|
+
concurrency:
|
|
19
|
+
group: ci-${{ github.workflow }}-${{ github.ref }}
|
|
20
|
+
cancel-in-progress: true
|
|
21
|
+
|
|
22
|
+
env:
|
|
23
|
+
CARGO_TERM_COLOR: always
|
|
24
|
+
|
|
25
|
+
jobs:
|
|
26
|
+
test:
|
|
27
|
+
name: Test (${{ matrix.os }})
|
|
28
|
+
runs-on: ${{ matrix.os }}
|
|
29
|
+
strategy:
|
|
30
|
+
fail-fast: false
|
|
31
|
+
matrix:
|
|
32
|
+
os: [ubuntu-latest, windows-latest, macos-latest]
|
|
33
|
+
|
|
34
|
+
steps:
|
|
35
|
+
- uses: actions/checkout@v6
|
|
36
|
+
|
|
37
|
+
- name: Install Rust toolchain
|
|
38
|
+
uses: dtolnay/rust-toolchain@stable
|
|
39
|
+
|
|
40
|
+
- name: Install OpenBLAS (macOS)
|
|
41
|
+
if: matrix.os == 'macos-latest'
|
|
42
|
+
run: brew install openblas
|
|
43
|
+
|
|
44
|
+
- name: Install OpenBLAS (Ubuntu)
|
|
45
|
+
if: matrix.os == 'ubuntu-latest'
|
|
46
|
+
run: sudo apt-get update && sudo apt-get install -y libopenblas-dev
|
|
47
|
+
|
|
48
|
+
- name: Cache cargo registry & build
|
|
49
|
+
uses: actions/cache@v5
|
|
50
|
+
with:
|
|
51
|
+
path: |
|
|
52
|
+
~/.cargo/registry
|
|
53
|
+
~/.cargo/git
|
|
54
|
+
target
|
|
55
|
+
key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }}
|
|
56
|
+
restore-keys: ${{ runner.os }}-cargo-
|
|
57
|
+
|
|
58
|
+
- name: Build
|
|
59
|
+
run: cargo build --verbose --locked
|
|
60
|
+
|
|
61
|
+
- name: Run tests
|
|
62
|
+
run: cargo test --verbose --locked
|
|
63
|
+
|
|
64
|
+
- name: Set up Python
|
|
65
|
+
uses: actions/setup-python@v6
|
|
66
|
+
with:
|
|
67
|
+
python-version: "3.11"
|
|
68
|
+
cache: pip
|
|
69
|
+
cache-dependency-path: python/requirements-ci.txt
|
|
70
|
+
|
|
71
|
+
- name: Python bindings (maturin develop, pytest, wheel install, pytest)
|
|
72
|
+
working-directory: python
|
|
73
|
+
shell: bash
|
|
74
|
+
run: |
|
|
75
|
+
set -euo pipefail
|
|
76
|
+
python -m venv .venv
|
|
77
|
+
if [ -f .venv/Scripts/python.exe ]; then
|
|
78
|
+
VPY=.venv/Scripts/python.exe
|
|
79
|
+
else
|
|
80
|
+
VPY=.venv/bin/python
|
|
81
|
+
fi
|
|
82
|
+
"$VPY" -m pip install -U pip
|
|
83
|
+
"$VPY" -m pip install -r requirements-ci.txt
|
|
84
|
+
"$VPY" -m maturin develop --release
|
|
85
|
+
"$VPY" -m pytest tests/ -v
|
|
86
|
+
"$VPY" -m maturin build --release -o dist
|
|
87
|
+
shopt -s nullglob
|
|
88
|
+
wheels=(dist/lme_python-*.whl)
|
|
89
|
+
if [ ${#wheels[@]} -eq 0 ]; then
|
|
90
|
+
echo "No wheel found under python/dist"
|
|
91
|
+
ls -la dist 2>/dev/null || true
|
|
92
|
+
exit 1
|
|
93
|
+
fi
|
|
94
|
+
"$VPY" -m pip install --force-reinstall "${wheels[0]}"
|
|
95
|
+
"$VPY" -m pytest tests/ -v
|
|
96
|
+
|
|
97
|
+
rust-all-targets:
|
|
98
|
+
name: Rust check (all targets)
|
|
99
|
+
runs-on: ubuntu-latest
|
|
100
|
+
steps:
|
|
101
|
+
- uses: actions/checkout@v6
|
|
102
|
+
- uses: dtolnay/rust-toolchain@stable
|
|
103
|
+
- name: Install OpenBLAS
|
|
104
|
+
run: sudo apt-get update && sudo apt-get install -y libopenblas-dev
|
|
105
|
+
- name: Cache cargo registry & build
|
|
106
|
+
uses: actions/cache@v5
|
|
107
|
+
with:
|
|
108
|
+
path: |
|
|
109
|
+
~/.cargo/registry
|
|
110
|
+
~/.cargo/git
|
|
111
|
+
target
|
|
112
|
+
key: ubuntu-cargo-${{ hashFiles('**/Cargo.lock') }}
|
|
113
|
+
restore-keys: ubuntu-cargo-
|
|
114
|
+
- name: cargo check --workspace --all-targets
|
|
115
|
+
run: cargo check --workspace --all-targets --locked -v
|
|
116
|
+
|
|
117
|
+
production-load:
|
|
118
|
+
name: Production load & perf gates (ubuntu, release)
|
|
119
|
+
runs-on: ubuntu-latest
|
|
120
|
+
steps:
|
|
121
|
+
- uses: actions/checkout@v6
|
|
122
|
+
|
|
123
|
+
- name: Install Rust toolchain
|
|
124
|
+
uses: dtolnay/rust-toolchain@stable
|
|
125
|
+
|
|
126
|
+
- name: Install OpenBLAS (Ubuntu)
|
|
127
|
+
run: sudo apt-get update && sudo apt-get install -y libopenblas-dev
|
|
128
|
+
|
|
129
|
+
- name: Cache cargo registry & build
|
|
130
|
+
uses: actions/cache@v5
|
|
131
|
+
with:
|
|
132
|
+
path: |
|
|
133
|
+
~/.cargo/registry
|
|
134
|
+
~/.cargo/git
|
|
135
|
+
target
|
|
136
|
+
key: ubuntu-prodload-${{ hashFiles('**/Cargo.lock') }}
|
|
137
|
+
restore-keys: ubuntu-prodload-
|
|
138
|
+
|
|
139
|
+
- name: Production load tests (smoke + release wall-clock gates)
|
|
140
|
+
run: cargo test --release --locked --verbose --test test_production_load
|
|
141
|
+
|
|
142
|
+
- name: Heavy production load tests (ignored)
|
|
143
|
+
run: cargo test --release --locked --verbose --test test_production_load -- --ignored --test-threads=1
|
|
144
|
+
|
|
145
|
+
rust-doctests:
|
|
146
|
+
name: Rust doctests
|
|
147
|
+
runs-on: ubuntu-latest
|
|
148
|
+
steps:
|
|
149
|
+
- uses: actions/checkout@v6
|
|
150
|
+
- uses: dtolnay/rust-toolchain@stable
|
|
151
|
+
- name: Install OpenBLAS
|
|
152
|
+
run: sudo apt-get update && sudo apt-get install -y libopenblas-dev
|
|
153
|
+
- name: Cache cargo registry & build
|
|
154
|
+
uses: actions/cache@v5
|
|
155
|
+
with:
|
|
156
|
+
path: |
|
|
157
|
+
~/.cargo/registry
|
|
158
|
+
~/.cargo/git
|
|
159
|
+
target
|
|
160
|
+
key: ubuntu-cargo-${{ hashFiles('**/Cargo.lock') }}
|
|
161
|
+
restore-keys: ubuntu-cargo-
|
|
162
|
+
- name: cargo test --doc
|
|
163
|
+
run: cargo test --doc --locked --verbose
|
|
164
|
+
|
|
165
|
+
python-bindings-versions:
|
|
166
|
+
name: Python ${{ matrix.python-version }} (ubuntu)
|
|
167
|
+
runs-on: ubuntu-latest
|
|
168
|
+
strategy:
|
|
169
|
+
fail-fast: false
|
|
170
|
+
matrix:
|
|
171
|
+
python-version: ["3.10", "3.12", "3.13"]
|
|
172
|
+
steps:
|
|
173
|
+
- uses: actions/checkout@v6
|
|
174
|
+
- uses: dtolnay/rust-toolchain@stable
|
|
175
|
+
- name: Install OpenBLAS
|
|
176
|
+
run: sudo apt-get update && sudo apt-get install -y libopenblas-dev
|
|
177
|
+
- name: Cache cargo registry & build
|
|
178
|
+
uses: actions/cache@v5
|
|
179
|
+
with:
|
|
180
|
+
path: |
|
|
181
|
+
~/.cargo/registry
|
|
182
|
+
~/.cargo/git
|
|
183
|
+
target
|
|
184
|
+
key: ubuntu-cargo-${{ hashFiles('**/Cargo.lock') }}
|
|
185
|
+
restore-keys: ubuntu-cargo-
|
|
186
|
+
- name: Set up Python
|
|
187
|
+
uses: actions/setup-python@v6
|
|
188
|
+
with:
|
|
189
|
+
python-version: ${{ matrix.python-version }}
|
|
190
|
+
cache: pip
|
|
191
|
+
cache-dependency-path: python/requirements-ci.txt
|
|
192
|
+
- name: Python bindings (maturin develop, pytest, wheel install, pytest)
|
|
193
|
+
working-directory: python
|
|
194
|
+
shell: bash
|
|
195
|
+
run: |
|
|
196
|
+
set -euo pipefail
|
|
197
|
+
python -m venv .venv
|
|
198
|
+
if [ -f .venv/Scripts/python.exe ]; then
|
|
199
|
+
VPY=.venv/Scripts/python.exe
|
|
200
|
+
else
|
|
201
|
+
VPY=.venv/bin/python
|
|
202
|
+
fi
|
|
203
|
+
"$VPY" -m pip install -U pip
|
|
204
|
+
"$VPY" -m pip install -r requirements-ci.txt
|
|
205
|
+
"$VPY" -m maturin develop --release
|
|
206
|
+
"$VPY" -m pytest tests/ -v
|
|
207
|
+
"$VPY" -m maturin build --release -o dist
|
|
208
|
+
shopt -s nullglob
|
|
209
|
+
wheels=(dist/lme_python-*.whl)
|
|
210
|
+
if [ ${#wheels[@]} -eq 0 ]; then
|
|
211
|
+
echo "No wheel found under python/dist"
|
|
212
|
+
ls -la dist 2>/dev/null || true
|
|
213
|
+
exit 1
|
|
214
|
+
fi
|
|
215
|
+
"$VPY" -m pip install --force-reinstall "${wheels[0]}"
|
|
216
|
+
"$VPY" -m pytest tests/ -v
|
|
217
|
+
|
|
218
|
+
docs:
|
|
219
|
+
name: Build docs
|
|
220
|
+
runs-on: ubuntu-latest
|
|
221
|
+
steps:
|
|
222
|
+
- uses: actions/checkout@v6
|
|
223
|
+
- uses: dtolnay/rust-toolchain@stable
|
|
224
|
+
- name: Build documentation
|
|
225
|
+
run: cargo doc --no-deps --verbose --locked
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
name: Crate publish (dry-run)
|
|
2
|
+
|
|
3
|
+
# Verifies `cargo publish` packaging (metadata, README, excluded files) without uploading.
|
|
4
|
+
|
|
5
|
+
on:
|
|
6
|
+
push:
|
|
7
|
+
tags:
|
|
8
|
+
- "v*"
|
|
9
|
+
workflow_dispatch:
|
|
10
|
+
|
|
11
|
+
permissions:
|
|
12
|
+
contents: read
|
|
13
|
+
|
|
14
|
+
concurrency:
|
|
15
|
+
group: publish-dry-run-${{ github.workflow }}-${{ github.ref }}
|
|
16
|
+
cancel-in-progress: true
|
|
17
|
+
|
|
18
|
+
jobs:
|
|
19
|
+
dry-run:
|
|
20
|
+
name: cargo publish --dry-run
|
|
21
|
+
runs-on: ubuntu-latest
|
|
22
|
+
steps:
|
|
23
|
+
- uses: actions/checkout@v6
|
|
24
|
+
|
|
25
|
+
- uses: dtolnay/rust-toolchain@stable
|
|
26
|
+
|
|
27
|
+
- name: Dry-run publish (root crate)
|
|
28
|
+
run: cargo publish --dry-run --locked
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
# Manual libFuzzer smoke (long compile + short run). Trigger from the Actions tab.
|
|
2
|
+
name: Fuzz (manual)
|
|
3
|
+
|
|
4
|
+
on:
|
|
5
|
+
workflow_dispatch:
|
|
6
|
+
|
|
7
|
+
jobs:
|
|
8
|
+
libfuzzer-smoke:
|
|
9
|
+
runs-on: ubuntu-latest
|
|
10
|
+
timeout-minutes: 120
|
|
11
|
+
defaults:
|
|
12
|
+
run:
|
|
13
|
+
working-directory: fuzz
|
|
14
|
+
|
|
15
|
+
steps:
|
|
16
|
+
- uses: actions/checkout@v4
|
|
17
|
+
|
|
18
|
+
- uses: dtolnay/rust-toolchain@nightly
|
|
19
|
+
|
|
20
|
+
- name: Install cargo-fuzz
|
|
21
|
+
run: cargo install cargo-fuzz --locked
|
|
22
|
+
|
|
23
|
+
- uses: Swatinem/rust-cache@v2
|
|
24
|
+
with:
|
|
25
|
+
workspaces: fuzz
|
|
26
|
+
|
|
27
|
+
- name: Build fuzz targets
|
|
28
|
+
run: cargo fuzz build formula_parse && cargo fuzz build formula_pipeline
|
|
29
|
+
|
|
30
|
+
- name: Run formula_parse
|
|
31
|
+
run: cargo fuzz run formula_parse corpus/formula_parse -- -runs=15000 -max_len=16384
|
|
32
|
+
|
|
33
|
+
- name: Run formula_pipeline
|
|
34
|
+
run: cargo fuzz run formula_pipeline corpus/formula_parse -- -runs=15000 -max_len=16384
|
|
@@ -23,8 +23,8 @@ jobs:
|
|
|
23
23
|
matrix:
|
|
24
24
|
target: [x86_64, aarch64]
|
|
25
25
|
steps:
|
|
26
|
-
- uses: actions/checkout@
|
|
27
|
-
- uses: actions/setup-python@
|
|
26
|
+
- uses: actions/checkout@v6
|
|
27
|
+
- uses: actions/setup-python@v6
|
|
28
28
|
with:
|
|
29
29
|
python-version: '3.10'
|
|
30
30
|
- name: Build wheels
|
|
@@ -44,7 +44,7 @@ jobs:
|
|
|
44
44
|
CFLAGS: "-std=gnu99"
|
|
45
45
|
CFLAGS_aarch64_unknown_linux_gnu: "-std=gnu99"
|
|
46
46
|
- name: Upload wheels
|
|
47
|
-
uses: actions/upload-artifact@
|
|
47
|
+
uses: actions/upload-artifact@v7
|
|
48
48
|
with:
|
|
49
49
|
name: wheels-linux-${{ matrix.target }}
|
|
50
50
|
path: dist
|
|
@@ -55,8 +55,8 @@ jobs:
|
|
|
55
55
|
matrix:
|
|
56
56
|
target: [x64]
|
|
57
57
|
steps:
|
|
58
|
-
- uses: actions/checkout@
|
|
59
|
-
- uses: actions/setup-python@
|
|
58
|
+
- uses: actions/checkout@v6
|
|
59
|
+
- uses: actions/setup-python@v6
|
|
60
60
|
with:
|
|
61
61
|
python-version: '3.10'
|
|
62
62
|
architecture: ${{ matrix.target }}
|
|
@@ -67,7 +67,7 @@ jobs:
|
|
|
67
67
|
args: --release --out dist --manifest-path python/Cargo.toml
|
|
68
68
|
sccache: 'true'
|
|
69
69
|
- name: Upload wheels
|
|
70
|
-
uses: actions/upload-artifact@
|
|
70
|
+
uses: actions/upload-artifact@v7
|
|
71
71
|
with:
|
|
72
72
|
name: wheels-windows-${{ matrix.target }}
|
|
73
73
|
path: dist
|
|
@@ -78,8 +78,8 @@ jobs:
|
|
|
78
78
|
matrix:
|
|
79
79
|
target: [x86_64, aarch64]
|
|
80
80
|
steps:
|
|
81
|
-
- uses: actions/checkout@
|
|
82
|
-
- uses: actions/setup-python@
|
|
81
|
+
- uses: actions/checkout@v6
|
|
82
|
+
- uses: actions/setup-python@v6
|
|
83
83
|
with:
|
|
84
84
|
python-version: '3.10'
|
|
85
85
|
- name: Install OpenBLAS
|
|
@@ -91,7 +91,7 @@ jobs:
|
|
|
91
91
|
args: --release --out dist --manifest-path python/Cargo.toml
|
|
92
92
|
sccache: 'true'
|
|
93
93
|
- name: Upload wheels
|
|
94
|
-
uses: actions/upload-artifact@
|
|
94
|
+
uses: actions/upload-artifact@v7
|
|
95
95
|
with:
|
|
96
96
|
name: wheels-macos-${{ matrix.target }}
|
|
97
97
|
path: dist
|
|
@@ -99,14 +99,14 @@ jobs:
|
|
|
99
99
|
sdist:
|
|
100
100
|
runs-on: ubuntu-latest
|
|
101
101
|
steps:
|
|
102
|
-
- uses: actions/checkout@
|
|
102
|
+
- uses: actions/checkout@v6
|
|
103
103
|
- name: Build sdist
|
|
104
104
|
uses: PyO3/maturin-action@v1
|
|
105
105
|
with:
|
|
106
106
|
command: sdist
|
|
107
107
|
args: --out dist --manifest-path python/Cargo.toml
|
|
108
108
|
- name: Upload sdist
|
|
109
|
-
uses: actions/upload-artifact@
|
|
109
|
+
uses: actions/upload-artifact@v7
|
|
110
110
|
with:
|
|
111
111
|
name: wheels-sdist
|
|
112
112
|
path: dist
|
|
@@ -122,7 +122,7 @@ jobs:
|
|
|
122
122
|
id-token: write # IMPORTANT: this permission is mandatory for trusted publishing
|
|
123
123
|
contents: write # needed to create GitHub Release
|
|
124
124
|
steps:
|
|
125
|
-
- uses: actions/download-artifact@
|
|
125
|
+
- uses: actions/download-artifact@v7
|
|
126
126
|
with:
|
|
127
127
|
path: dist
|
|
128
128
|
pattern: wheels-*
|
|
@@ -1,4 +1,7 @@
|
|
|
1
1
|
/target
|
|
2
|
+
/fuzz/artifacts/
|
|
3
|
+
/fuzz/coverage/
|
|
4
|
+
/fuzz/target/
|
|
2
5
|
reference/
|
|
3
6
|
rlib/
|
|
4
7
|
julia-portable/
|
|
@@ -6,6 +9,8 @@ julia-portable.zip
|
|
|
6
9
|
flamegraph.svg
|
|
7
10
|
artifacts/
|
|
8
11
|
benchmark-results/
|
|
12
|
+
benchmark-site/
|
|
13
|
+
site/
|
|
9
14
|
|
|
10
15
|
# Python bindings
|
|
11
16
|
python/target/
|
|
@@ -15,6 +15,7 @@ It currently covers these benchmark families:
|
|
|
15
15
|
- end-to-end `lmer()` fitting on `sleepstudy`
|
|
16
16
|
- end-to-end weighted `lmer_weighted()` fitting on fixture-backed and large synthetic cases
|
|
17
17
|
- end-to-end `glmer()` fitting on `grouseticks` and `cbpp`
|
|
18
|
+
- `glmm_agq_cbpp`: same CBPP binomial fit with `n_agq = 1` (Laplace) vs `n_agq = 7` (scalar AGQ), lower sample size because AGQ is expensive
|
|
18
19
|
- population-level and conditional prediction on a larger repeated `sleepstudy` frame
|
|
19
20
|
- response-scale and conditional response-scale GLMM prediction on repeated Poisson and Binomial frames
|
|
20
21
|
- GLMM post-fit helpers such as Wald confidence intervals
|
|
@@ -82,7 +83,7 @@ Recommended rules:
|
|
|
82
83
|
- note when optimizers are not directly comparable across ecosystems
|
|
83
84
|
- keep output artifacts or raw logs so later releases can be compared to the same baseline
|
|
84
85
|
|
|
85
|
-
For this repo, the most defensible cross-language benchmark set would start with the same reference datasets already used in `
|
|
86
|
+
For this repo, the most defensible cross-language benchmark set would start with the same reference datasets already used in `comparisons/COMPARISONS.md`:
|
|
86
87
|
|
|
87
88
|
- `sleepstudy`
|
|
88
89
|
- `dyestuff`
|
|
@@ -123,6 +124,33 @@ The repository also includes a dedicated workflow in [.github/workflows/benchmar
|
|
|
123
124
|
- uploads the resulting artifacts in CI
|
|
124
125
|
- attaches them to GitHub Releases on tag pushes
|
|
125
126
|
|
|
127
|
+
## Latest published results
|
|
128
|
+
|
|
129
|
+
The latest published benchmark artifacts are attached to the [v0.1.3 release](https://github.com/x4g4p3x/lme-rs/releases/tag/v0.1.3).
|
|
130
|
+
|
|
131
|
+
That release currently includes:
|
|
132
|
+
|
|
133
|
+
- `criterion-e8a82e0b97b88c5549bc61e89c22dc12c9060a02.tar.gz`
|
|
134
|
+
- `cross-language-e8a82e0b97b88c5549bc61e89c22dc12c9060a02.json`
|
|
135
|
+
|
|
136
|
+
The cross-language JSON includes representative timings for:
|
|
137
|
+
|
|
138
|
+
- `sleepstudy`
|
|
139
|
+
- `pastes`
|
|
140
|
+
- `cbpp`
|
|
141
|
+
- `grouseticks`
|
|
142
|
+
|
|
143
|
+
across:
|
|
144
|
+
|
|
145
|
+
- Rust
|
|
146
|
+
- Python
|
|
147
|
+
- R
|
|
148
|
+
- Julia
|
|
149
|
+
|
|
150
|
+
Treat those numbers as versioned release artifacts, not as universal constants. They were produced on GitHub-hosted runners with the workflow's pinned toolchain setup, so they are useful for release-to-release comparison and public transparency, but not as machine-independent proof of absolute speed.
|
|
151
|
+
|
|
152
|
+
If you want to cite benchmark results in release notes or external docs, prefer linking the release asset directly instead of copying raw numbers into the README. That keeps the landing page stable while still making the measured outputs inspectable.
|
|
153
|
+
|
|
126
154
|
## How to interpret results
|
|
127
155
|
|
|
128
156
|
Use the existing suite primarily for:
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to this project will be documented in this file.
|
|
4
|
+
|
|
5
|
+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|
6
|
+
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
|
+
|
|
8
|
+
## [Unreleased]
|
|
9
|
+
|
|
10
|
+
## [0.1.7] - 2026-05-18
|
|
11
|
+
|
|
12
|
+
### Added
|
|
13
|
+
|
|
14
|
+
- **Type II** fixed-effects ANOVA via `LmeFit::anova_typed(AnovaType::Type2, ddf)` ([`src/anova_contrasts.rs`](src/anova_contrasts.rs), `lmerTest`-style Doolittle contrasts for contained terms). `anova(ddf)` remains Type III. Python: `fit.anova("satterthwaite", anova_type="II")`.
|
|
15
|
+
- Design-matrix support for **`FixedEffect`** / **`InteractionTerm`** fiasto roles and two-way categorical interactions (`y ~ a * b`).
|
|
16
|
+
- Golden parity case **`pastes_cask_multi_dof_reml`** in [`tests/data/golden_parity_manifest.json`](tests/data/golden_parity_manifest.json) (Type III Satterthwaite ANOVA for `cask` on the pastes dataset), with fixture [`tests/data/pastes_cask_reml.json`](tests/data/pastes_cask_reml.json) and R regeneration via [`tests/generate_test_data.R`](tests/generate_test_data.R).
|
|
17
|
+
- Numeric parity checks for categorical multi-DoF ANOVA in [`tests/categorical_anova_test.rs`](tests/categorical_anova_test.rs) and [`python/examples/verification_project/parity.py`](python/examples/verification_project/parity.py).
|
|
18
|
+
|
|
19
|
+
### Changed
|
|
20
|
+
|
|
21
|
+
- Multi-DoF Type III ANOVA denominator df for Satterthwaite now follows **`lmerTest::contestMD()`** ([`src/ddf.rs`](src/ddf.rs)): eigen-decomposed Wald contrasts, per-direction Satterthwaite dfs, and `get_Fstat_ddf()` pooling (replacing `min()` of marginal dfs). Kenward–Roger multi-DoF rows use the same pooling on marginal dfs.
|
|
22
|
+
|
|
23
|
+
## [0.1.6] - 2026-03-27
|
|
24
|
+
|
|
25
|
+
### Added
|
|
26
|
+
|
|
27
|
+
- Python `examples/plotting_demo`: matplotlib figures from `lme_python`, optional **lme4** parity (`plot_r.R`), side-by-side PNGs (`figures_compare/`), numeric overlay on shared axes (`figures_overlay/` via `figures_data/` JSON/CSV), `run_all.py`, Windows `Rscript` discovery (`find_rscript.py`), and raster fallback (`figures_overlay_raster/`).
|
|
28
|
+
- `scripts/local_ci.sh` and `scripts/local_ci.ps1` to run the same checks as [`.github/workflows/ci.yml`](.github/workflows/ci.yml) locally (`fmt`, `clippy`, build, test, `doc`).
|
|
29
|
+
|
|
30
|
+
## [0.1.5] - 2026-03-22
|
|
31
|
+
|
|
32
|
+
### Added
|
|
33
|
+
|
|
34
|
+
- Added automatic categorical dummy encoding (dropping collinear intercepts) directly from categorical/string Polars dataframe columns natively.
|
|
35
|
+
- Implemented Multi-DoF Joint Wald F-Tests tracking dummy groups in `anova()` (Type III Satterthwaite representations) for valid categorical fixed-effect testing.
|
|
36
|
+
- Added support for generating `Gaussian` families in Python's `glmer` mapping, alongside exposing an equivalent `lmer_weighted` function.
|
|
37
|
+
- Plumbed explicit Adaptive Gauss-Hermite Quadrature (`nAGQ`) scaling configuration arrays throughout the optimizer targeting upcoming structural convergence capabilities.
|
|
38
|
+
|
|
39
|
+
## [0.1.4] - 2026-03-22
|
|
40
|
+
|
|
41
|
+
### Added
|
|
42
|
+
|
|
43
|
+
- Formula-string entry point `lm()` and corresponding Python binding for fitting ordinary least squares models using DataFrames.
|
|
44
|
+
- New Python examples directory `python/examples` with five runnable demonstration scripts mapping to common mixed-modeling workflows.
|
|
45
|
+
|
|
46
|
+
### Changed
|
|
47
|
+
|
|
48
|
+
- Renamed `examples/` directory to `comparisons/` to clarify that it contains cross-language parity scripts, updating all build and documentation references accordingly.
|
|
49
|
+
- Promoted Kenward-Roger degrees of freedom from "provisional" status after validating numerical parity (within 0.01 df) against R's `pbkrtest`.
|
|
50
|
+
|
|
51
|
+
## [0.1.3] - 2026-03-12
|
|
52
|
+
|
|
53
|
+
### Added
|
|
54
|
+
|
|
55
|
+
- Expanded the benchmark suite to cover parsing, matrix construction, prediction paths, inference helpers, weighted fits, Kenward-Roger timing, and size sweeps.
|
|
56
|
+
- Added automated cross-language benchmark scripting and a GitHub workflow that saves benchmark artifacts in CI and on release tags.
|
|
57
|
+
- Added `CONTRIBUTING.md`, `RELEASING.md`, and `BENCHMARKS.md` to document contributor setup, release flow, and benchmark methodology.
|
|
58
|
+
|
|
59
|
+
### Changed
|
|
60
|
+
|
|
61
|
+
- Reworked the README, Rust guide, Python guide, and comparison documentation to better reflect current capabilities, limitations, and release workflow.
|
|
62
|
+
- Switched the crate homepage to the docs.rs site and expanded repository metadata sync for GitHub description, topics, and website fields.
|
|
63
|
+
- Hardened the benchmark automation and example scripts so cross-language benchmark runs complete consistently on GitHub Actions.
|
|
64
|
+
|
|
65
|
+
## [0.1.2] - 2026-03-09
|
|
66
|
+
|
|
67
|
+
### Fixed
|
|
68
|
+
|
|
69
|
+
- Fixed a NaN deviance issue in the fitting path.
|
|
70
|
+
- Expanded Python test coverage for the 0.1.2 release.
|
|
71
|
+
|
|
72
|
+
### Changed
|
|
73
|
+
|
|
74
|
+
- Aligned `Cargo.lock` with the 0.1.2 version bump.
|
|
75
|
+
|
|
76
|
+
## [0.1.1] - 2026-03-09
|
|
77
|
+
|
|
78
|
+
### Changed
|
|
79
|
+
|
|
80
|
+
- Bumped the crate and Python extension versions for the 0.1.1 release.
|
|
81
|
+
- Updated lockfiles to remove yanked dependencies.
|
|
82
|
+
- Fixed missing documentation warnings needed for publishing.
|
|
83
|
+
|
|
84
|
+
### Fixed
|
|
85
|
+
|
|
86
|
+
- Hardened the GitHub Actions and wheel build pipeline across Linux, macOS, and Windows.
|
|
87
|
+
- Restored missing dependencies and build flags needed for OpenBLAS-based wheel builds.
|
|
88
|
+
- Fixed several maturin and PyO3 packaging workflow issues for the Python release path.
|
|
89
|
+
|
|
90
|
+
## [0.1.0] - 2026-03-08
|
|
91
|
+
|
|
92
|
+
### Added
|
|
93
|
+
|
|
94
|
+
- **Core LMM** - `lmer()` with REML and ML estimation, matching R's `lme4` to 4 decimal places
|
|
95
|
+
- **GLMM** - `glmer()` with Poisson, Binomial, Gaussian, and Gamma families via Laplace approximation
|
|
96
|
+
- **Predictions** - `predict()`, `predict_conditional()`, `predict_response()`, `predict_conditional_response()` with `allow_new_levels` support
|
|
97
|
+
- **Inference** - Satterthwaite and Kenward-Roger degrees of freedom, robust sandwich standard errors
|
|
98
|
+
- **Model comparison** - `anova()` for likelihood ratio tests between nested models
|
|
99
|
+
- **Diagnostics** - `confint()` for Wald confidence intervals, `simulate()` for parametric bootstrap
|
|
100
|
+
- **Formula parser** - Wilkinson notation with nested (`a/b`), crossed (`a + b`), and correlated slope+intercept (`x | group`) random effects
|
|
101
|
+
- **Sparse matrix architecture** - Compressed sparse column format with sparse Cholesky for large datasets
|
|
102
|
+
- **Python bindings** - `lme_python` package via PyO3/maturin with `lmer()`, `glmer()`, `predict()`
|
|
103
|
+
- **Documentation** - `GUIDE.md`, `PYTHON_GUIDE.md`, and cross-language `COMPARISONS.md`
|