From 7c68c82db5e2f5925905d6d4f08fc45efefbb11d Mon Sep 17 00:00:00 2001 From: "Lorenzo (Mec-iS)" Date: Mon, 12 Oct 2026 03:17:40 +0100 Subject: [PATCH 1/2] chore: fold unreleased changes into the 0.6.16 release notes 0.6.16 has not been published to crates.io yet, so the [Unreleased] section is folded into the existing 0.6.16 entry instead of opening a new version. Covers #475, #478, #481, #482, #485. All release gates verified locally: - cargo test --all-features (614 unit + 73 doctests, 0 failed) - cargo fmt --all -- --check - cargo clippy --all-features (2018+2024 idioms, -Dwarnings) - cargo +1.85.0 build --all-features (MSRV) - cargo package (146 files, 2.1MiB) --- CHANGELOG.md | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ee8a8742..585b81e3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,17 +5,20 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). ## [Unreleased] -### Fixed -- The ndarray implementation of `Array2::from_iterator` now preserves column-major input order, including for rectangular matrices that previously caused a panic. Column-major input produces a column-major array (#482). ## [0.6.16] ### Fixed - `predict`, `predict_proba`, `predict_oob`, `predict_matrix` and `decision_function` now return `Err(Failed)` instead of panicking when `fit` has not run (#469, #470). Models return the same unfitted error even after deserialization, when the state fields are `None`. The guarded methods cover the decision trees, the random forests, the extra-trees regressor, the KNN classifier and regressor, `SVC`, `MultiClassSVC`, `SVR`, the linear models, the naive Bayes classifiers and `XGRegressor`. - `KNNClassifier::fit` now accepts `k = 1`, as `KNNRegressor` already did (#476). `k = 0` is still rejected. +- The ndarray implementation of `Array2::from_iterator` now preserves column-major input order, including for rectangular matrices that previously caused a panic. Column-major input produces a column-major array (#482). +- `ensemble`: `RandomForestRegressor` and `RandomForestClassifier` now give each tree its own seed (`seed + tree index`). Before this change, all trees of a forest used the same seed, so all trees picked the same feature samples (#475). A forest fitted with a fixed `seed` now returns different predictions, because the trees no longer share one feature sample. Fits with the same seed stay reproducible. +- `ensemble`: sample weights now follow the scikit-learn rules. With `bootstrap = true`, the weights are used in the bootstrap phase only. With `bootstrap = false`, the weights go to each tree (#478). New tests compare `RandomForestRegressor` and `ExtraTreesRegressor` predictions (train, probe and OOB) with reference values from scikit-learn 1.9.1. ### Changed - The error text for an unfitted `MultiClassSVC::predict` changed from "MultiClassSVC is not fitted" to the common "'fit' should be called before calling 'predict'". Code that matched the old string must be updated. - The error text for an invalid `k` in `KNNClassifier::fit` changed from "k should be > 1" to "k should be > 0", the same text `KNNRegressor` uses. Code that matched the old string must be updated. +- `tree`: `BaseTreeRegressor` (used by `DecisionTreeRegressor`, `RandomForestRegressor` and `ExtraTreesRegressor`) runs faster: less allocation, less sorting, node rows stored as `(start, end)` spans, and no partition step for child nodes that cannot split (#481). Split values no longer fall between adjacent floating-point numbers, so fitted values can differ slightly from earlier versions. New tests check parity of `RandomForestRegressor` with scikit-learn. +- CI: the coverage job runs cargo-tarpaulin with the LLVM engine instead of the default engine (#485, fixes #484). ## [0.6.15] ### Fixed From ab63e8ba23ca6d57d06e4a05b8b2dc5447b0e3a2 Mon Sep 17 00:00:00 2001 From: "Lorenzo (Mec-iS)" Date: Mon, 12 Oct 2026 03:25:30 +0100 Subject: [PATCH 2/2] ci: run coverage in release mode and shrink test_logit The LLVM coverage engine instruments the whole serial test run (--test-threads 1). On a slow shared runner the instrumented run could exceed tarpaulin's default 60 s per-binary timeout; observed as 'Timed out waiting for test response' while test_logit (a 52181x94 logistic-regression fit) was running. Two changes: - test_logit now uses a 10000x94 matrix with the same class ratio (418 of 10000 positive). The test asserts the same property and finishes in ~0.5 s instead of ~3.5 s. - The coverage job builds in release mode (--release) and raises the tarpaulin timeout to 600 s. --- .github/workflows/coverage.yml | 2 +- CHANGELOG.md | 3 ++- src/linear/logistic_regression.rs | 9 +++++---- 3 files changed, 8 insertions(+), 6 deletions(-) diff --git a/.github/workflows/coverage.yml b/.github/workflows/coverage.yml index 9fd5c3f4..c530a9c8 100644 --- a/.github/workflows/coverage.yml +++ b/.github/workflows/coverage.yml @@ -28,7 +28,7 @@ jobs: - name: Install cargo-tarpaulin run: cargo install --locked cargo-tarpaulin - name: Run cargo-tarpaulin - run: cargo tarpaulin --engine llvm --all-features --run-types Tests --run-types Doctests --out Lcov --fail-under 44 -- --test-threads 1 + run: cargo tarpaulin --engine llvm --release --all-features --run-types Tests --run-types Doctests --out Lcov --fail-under 44 --timeout 600 -- --test-threads 1 - name: Upload to codecov.io if: always() uses: codecov/codecov-action@v4 diff --git a/CHANGELOG.md b/CHANGELOG.md index 585b81e3..2c0ff5c5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -18,7 +18,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - The error text for an unfitted `MultiClassSVC::predict` changed from "MultiClassSVC is not fitted" to the common "'fit' should be called before calling 'predict'". Code that matched the old string must be updated. - The error text for an invalid `k` in `KNNClassifier::fit` changed from "k should be > 1" to "k should be > 0", the same text `KNNRegressor` uses. Code that matched the old string must be updated. - `tree`: `BaseTreeRegressor` (used by `DecisionTreeRegressor`, `RandomForestRegressor` and `ExtraTreesRegressor`) runs faster: less allocation, less sorting, node rows stored as `(start, end)` spans, and no partition step for child nodes that cannot split (#481). Split values no longer fall between adjacent floating-point numbers, so fitted values can differ slightly from earlier versions. New tests check parity of `RandomForestRegressor` with scikit-learn. -- CI: the coverage job runs cargo-tarpaulin with the LLVM engine instead of the default engine (#485, fixes #484). +- `linear`: the `test_logit` fixture now uses a 10000 x 94 random matrix instead of 52181 x 94. The class ratio stays the same (418 of 10000 rows are positive). The test checks the same property and runs much faster, so it stays inside the CI coverage time budget. +- CI: the coverage job runs cargo-tarpaulin with the LLVM engine, in release mode and with a 600 s timeout, instead of the default engine (#485, fixes #484). ## [0.6.15] ### Fixed diff --git a/src/linear/logistic_regression.rs b/src/linear/logistic_regression.rs index 031dfd9d..8e65f562 100644 --- a/src/linear/logistic_regression.rs +++ b/src/linear/logistic_regression.rs @@ -988,9 +988,10 @@ mod tests { #[test] fn test_logit() { - let x: &DenseMatrix = &DenseMatrix::rand(52181, 94); - let y1: Vec = vec![1; 2181]; - let y2: Vec = vec![0; 50000]; + // Class ratio matches the original 52181-row fixture (2181 positive of 52181). + let x: &DenseMatrix = &DenseMatrix::rand(10000, 94); + let y1: Vec = vec![1; 418]; + let y2: Vec = vec![0; 9582]; let y: &Vec = &(y1.into_iter().chain(y2).collect()); println!("y vec height: {:?}", y.len()); println!("x matrix shape: {:?}", x.shape()); @@ -1000,7 +1001,7 @@ mod tests { println!("y_hat shape: {:?}", y_hat.shape()); - assert_eq!(y_hat.shape(), 52181); + assert_eq!(y_hat.shape(), 10000); } #[cfg_attr(