From 067a1f70f86774339a62b04ebd6e2b5f8bae406c Mon Sep 17 00:00:00 2001 From: jakelodwick <25925+jakelodwick@users.noreply.github.com> Date: Sat, 14 Mar 2026 06:24:10 -0600 Subject: [PATCH] Remove dependency on unmaintained 'statistical' crate The `statistical` crate hasn't been updated since 2019 and depends on `rand 0.6`, which pulls 25 transitive packages that duplicate hyperfine's existing `rand 0.8` stack. hyperfine uses three functions from `statistical`: `mean`, `median`, and `standard_deviation`. This replaces them with equivalent implementations in a new `util::stats` module (~20 lines). All existing tests pass without modification. Similar to #693 which replaced `atty` with `std::io::IsTerminal`. --- Cargo.lock | 261 ++------------------------------------ Cargo.toml | 1 - src/benchmark/executor.rs | 2 +- src/benchmark/mod.rs | 2 +- src/outlier_detection.rs | 2 +- src/util/mod.rs | 1 + src/util/stats.rs | 22 ++++ 7 files changed, 34 insertions(+), 257 deletions(-) create mode 100644 src/util/stats.rs diff --git a/Cargo.lock b/Cargo.lock index cda887710..6d6688124 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -108,27 +108,12 @@ dependencies = [ "wait-timeout", ] -[[package]] -name = "autocfg" -version = "0.1.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0dde43e75fd43e8a1bf86103336bc699aa8d17ad1be60c76c0bdfd4828e19b78" -dependencies = [ - "autocfg 1.5.0", -] - [[package]] name = "autocfg" version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" -[[package]] -name = "bitflags" -version = "1.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" - [[package]] name = "bitflags" version = "2.10.0" @@ -264,15 +249,6 @@ version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a1d728cc89cf3aee9ff92b05e62b19ee65a02b5702cff7d5a377e32c6ae29d8d" -[[package]] -name = "cloudabi" -version = "0.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f" -dependencies = [ - "bitflags 1.3.2", -] - [[package]] name = "colorchoice" version = "1.0.4" @@ -366,12 +342,6 @@ dependencies = [ "num-traits", ] -[[package]] -name = "fuchsia-cprng" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba" - [[package]] name = "funty" version = "2.0.0" @@ -433,12 +403,11 @@ dependencies = [ "nix", "once_cell", "predicates", - "rand 0.8.5", + "rand", "rust_decimal", "serde", "serde_json", "shell-words", - "statistical", "tempfile", "thiserror", "windows-sys 0.59.0", @@ -540,7 +509,7 @@ version = "0.29.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "71e2746dc3a24dd78b3cfcb7be93368c6de9963d30f43a6a73998a9cf4b17b46" dependencies = [ - "bitflags 2.10.0", + "bitflags", "cfg-if", "cfg_aliases", "libc", @@ -552,80 +521,13 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "61807f77802ff30975e01f4f071c8ba10c022052f98b3294119f3e615d13e5be" -[[package]] -name = "num" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8536030f9fea7127f841b45bb6243b27255787fb4eb83958aa1ef9d2fdc0c36" -dependencies = [ - "num-bigint", - "num-complex", - "num-integer", - "num-iter", - "num-rational", - "num-traits", -] - -[[package]] -name = "num-bigint" -version = "0.2.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "090c7f9998ee0ff65aa5b723e4009f7b217707f1fb5ea551329cc4d6231fb304" -dependencies = [ - "autocfg 1.5.0", - "num-integer", - "num-traits", -] - -[[package]] -name = "num-complex" -version = "0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6b19411a9719e753aff12e5187b74d60d3dc449ec3f4dc21e3989c3f554bc95" -dependencies = [ - "autocfg 1.5.0", - "num-traits", -] - -[[package]] -name = "num-integer" -version = "0.1.46" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" -dependencies = [ - "num-traits", -] - -[[package]] -name = "num-iter" -version = "0.1.45" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1429034a0490724d0075ebb2bc9e875d6503c3cf69e235a8941aa757d83ef5bf" -dependencies = [ - "autocfg 1.5.0", - "num-integer", - "num-traits", -] - -[[package]] -name = "num-rational" -version = "0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c000134b5dbf44adc5cb772486d335293351644b801551abe8f75c84cfa4aef" -dependencies = [ - "autocfg 1.5.0", - "num-bigint", - "num-integer", - "num-traits", -] - [[package]] name = "num-traits" version = "0.2.19" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" dependencies = [ - "autocfg 1.5.0", + "autocfg", ] [[package]] @@ -750,25 +652,6 @@ version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dc33ff2d4973d518d823d61aa239014831e521c75da58e3df4840d3f47749d09" -[[package]] -name = "rand" -version = "0.6.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d71dacdc3c88c1fde3885a3be3fbab9f35724e6ce99467f7d9c5026132184ca" -dependencies = [ - "autocfg 0.1.8", - "libc", - "rand_chacha 0.1.1", - "rand_core 0.4.2", - "rand_hc", - "rand_isaac", - "rand_jitter", - "rand_os", - "rand_pcg", - "rand_xorshift", - "winapi", -] - [[package]] name = "rand" version = "0.8.5" @@ -776,18 +659,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" dependencies = [ "libc", - "rand_chacha 0.3.1", - "rand_core 0.6.4", -] - -[[package]] -name = "rand_chacha" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "556d3a1ca6600bfcbab7c7c91ccb085ac7fbbcd70e008a98742e7847f4f7bcef" -dependencies = [ - "autocfg 0.1.8", - "rand_core 0.3.1", + "rand_chacha", + "rand_core", ] [[package]] @@ -797,24 +670,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" dependencies = [ "ppv-lite86", - "rand_core 0.6.4", -] - -[[package]] -name = "rand_core" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a6fdeb83b075e8266dcc8762c22776f6877a63111121f5f8c7411e5be7eed4b" -dependencies = [ - "rand_core 0.4.2", + "rand_core", ] -[[package]] -name = "rand_core" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c33a3c44ca05fa6f1807d8e6743f3824e8509beca625669633be0acbdf509dc" - [[package]] name = "rand_core" version = "0.6.4" @@ -824,77 +682,6 @@ dependencies = [ "getrandom 0.2.16", ] -[[package]] -name = "rand_hc" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b40677c7be09ae76218dc623efbf7b18e34bced3f38883af07bb75630a21bc4" -dependencies = [ - "rand_core 0.3.1", -] - -[[package]] -name = "rand_isaac" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ded997c9d5f13925be2a6fd7e66bf1872597f759fd9dd93513dd7e92e5a5ee08" -dependencies = [ - "rand_core 0.3.1", -] - -[[package]] -name = "rand_jitter" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1166d5c91dc97b88d1decc3285bb0a99ed84b05cfd0bc2341bdf2d43fc41e39b" -dependencies = [ - "libc", - "rand_core 0.4.2", - "winapi", -] - -[[package]] -name = "rand_os" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b75f676a1e053fc562eafbb47838d67c84801e38fc1ba459e8f180deabd5071" -dependencies = [ - "cloudabi", - "fuchsia-cprng", - "libc", - "rand_core 0.4.2", - "rdrand", - "winapi", -] - -[[package]] -name = "rand_pcg" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "abf9b09b01790cfe0364f52bf32995ea3c39f4d2dd011eac241d2914146d0b44" -dependencies = [ - "autocfg 0.1.8", - "rand_core 0.4.2", -] - -[[package]] -name = "rand_xorshift" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cbf7e9e623549b0e21f6e97cf8ecf247c1a8fd2e8a992ae265314300b2455d5c" -dependencies = [ - "rand_core 0.3.1", -] - -[[package]] -name = "rdrand" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "678054eb77286b51581ba43620cc911abf02758c91f93f479767aed0f90458b2" -dependencies = [ - "rand_core 0.3.1", -] - [[package]] name = "regex" version = "1.12.2" @@ -972,7 +759,7 @@ dependencies = [ "borsh", "bytes", "num-traits", - "rand 0.8.5", + "rand", "rkyv", "serde", "serde_json", @@ -984,7 +771,7 @@ version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cd15f8a2c5551a84d56efdc1cd049089e409ac19a3072d5037a17fd70719ff3e" dependencies = [ - "bitflags 2.10.0", + "bitflags", "errno", "libc", "linux-raw-sys", @@ -1070,16 +857,6 @@ version = "2.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bbbb5d9659141646ae647b42fe094daf6c6192d1620870b449d9557f748b2daa" -[[package]] -name = "statistical" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49d57902bb128e5e38b5218d3681215ae3e322d99f65d5420e9849730d2ea372" -dependencies = [ - "num", - "rand 0.6.5", -] - [[package]] name = "strsim" version = "0.11.1" @@ -1317,28 +1094,6 @@ dependencies = [ "unicode-ident", ] -[[package]] -name = "winapi" -version = "0.3.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" -dependencies = [ - "winapi-i686-pc-windows-gnu", - "winapi-x86_64-pc-windows-gnu", -] - -[[package]] -name = "winapi-i686-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" - -[[package]] -name = "winapi-x86_64-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" - [[package]] name = "windows-link" version = "0.2.1" diff --git a/Cargo.toml b/Cargo.toml index b3ef3dee6..2e28880c9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -19,7 +19,6 @@ windows_process_extensions_main_thread_handle = [] [dependencies] colored = "2.1" indicatif = "=0.17.4" -statistical = "1.0" csv = "1.3" serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" diff --git a/src/benchmark/executor.rs b/src/benchmark/executor.rs index 915b735b6..5f5892d26 100644 --- a/src/benchmark/executor.rs +++ b/src/benchmark/executor.rs @@ -13,8 +13,8 @@ use crate::util::units::Second; use super::timing_result::TimingResult; +use crate::util::stats::mean; use anyhow::{bail, Context, Result}; -use statistical::mean; pub enum BenchmarkIteration { NonBenchmarkRun, diff --git a/src/benchmark/mod.rs b/src/benchmark/mod.rs index e3534a7bc..419135344 100644 --- a/src/benchmark/mod.rs +++ b/src/benchmark/mod.rs @@ -22,9 +22,9 @@ use crate::util::units::Second; use benchmark_result::BenchmarkResult; use timing_result::TimingResult; +use crate::util::stats::{mean, median, standard_deviation}; use anyhow::{anyhow, Result}; use colored::*; -use statistical::{mean, median, standard_deviation}; use self::executor::Executor; diff --git a/src/outlier_detection.rs b/src/outlier_detection.rs index 270e522f7..e4215fab2 100644 --- a/src/outlier_detection.rs +++ b/src/outlier_detection.rs @@ -5,7 +5,7 @@ //! The ASQC Basic References in Quality Control: Statistical Techniques, Edward F. Mykytka, //! Ph.D., Editor. -use statistical::median; +use crate::util::stats::median; /// Minimum modified Z-score for a datapoint to be an outlier. Here, 1.4826 is a factor that /// converts the MAD to an estimator for the standard deviation. The second factor is the number diff --git a/src/util/mod.rs b/src/util/mod.rs index de9e1682c..a9248d012 100644 --- a/src/util/mod.rs +++ b/src/util/mod.rs @@ -2,4 +2,5 @@ pub mod exit_code; pub mod min_max; pub mod number; pub mod randomized_environment_offset; +pub mod stats; pub mod units; diff --git a/src/util/stats.rs b/src/util/stats.rs new file mode 100644 index 000000000..c35f592d2 --- /dev/null +++ b/src/util/stats.rs @@ -0,0 +1,22 @@ +pub fn mean(xs: &[f64]) -> f64 { + xs.iter().sum::() / xs.len() as f64 +} + +pub fn median(xs: &[f64]) -> f64 { + assert!(!xs.is_empty()); + let mut sorted = xs.to_vec(); + sorted.sort_by(|a, b| a.total_cmp(b)); + let mid = sorted.len() / 2; + if sorted.len() % 2 == 1 { + sorted[mid] + } else { + (sorted[mid - 1] + sorted[mid]) / 2.0 + } +} + +pub fn standard_deviation(xs: &[f64], xbar: Option) -> f64 { + assert!(xs.len() > 1); + let m = xbar.unwrap_or_else(|| mean(xs)); + let variance = xs.iter().map(|x| (x - m).powi(2)).sum::() / (xs.len() as f64 - 1.0); + variance.sqrt() +}