From 526bd1a736acc44990961c690171a71a5471dcbc Mon Sep 17 00:00:00 2001 From: Nelson Spence Date: Mon, 25 May 2026 11:28:42 -0500 Subject: [PATCH 1/2] chore(deps): bump rand + rand_chacha to 0.10 (RngExt migration) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Combined bump of the rand + rand_chacha dev-deps (test/bench corpora only) to 0.10 — a version-locked pair, so Dependabot's separate #46 (rand) and #44 (rand_chacha) can't resolve independently. This does both bumps + the API migration in one PR. rand 0.9 renamed gen_range->random_range and gen()->random(); rand 0.10 then moved those off the Rng trait onto RngExt. Migrated all 51 call-sites (49 gen_range + 2 gen) and the 10 'use rand::{Rng, SeedableRng}' imports -> RngExt across src/ tests/ examples/. Verified: fmt, clippy --all-targets --all-features -D warnings, cargo test (default + experimental), MSRV 1.89 compile (rand 0.10.1 + rand_chacha 0.10.0 declare rust-version 1.85). Seeded ChaCha8Rng tests pass — they assert retrieval properties (self-retrieval, scalar/SIMD parity), robust to 0.10's changed range sampling. Supersedes #44 + #46. --- Cargo.lock | 351 ++++++++++++++++++++++++++++++++++-- Cargo.toml | 4 +- examples/bench_rank.rs | 10 +- src/sign_bitmap.rs | 16 +- src/util.rs | 6 +- tests/index/bitmap.rs | 32 ++-- tests/index/fastscan.rs | 14 +- tests/index/main.rs | 4 +- tests/index/multi_bucket.rs | 4 +- tests/index/quant.rs | 14 +- tests/index/rank.rs | 10 +- tests/redteam_beta.rs | 12 +- 12 files changed, 397 insertions(+), 80 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index c0ed16e5..adb3c1b5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,18 +2,50 @@ # It is not intended for manual editing. version = 4 +[[package]] +name = "anyhow" +version = "1.0.102" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f202df86484c868dbad7eaa557ef785d5c66295e41b460ef922eca0723b842c" + [[package]] name = "autocfg" version = "1.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f2032f911046de80f0a198e0901378627c33f59ea0ac00e363d481118bd70a53" +[[package]] +name = "bitflags" +version = "2.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4512299f36f043ab09a583e57bceb5a5aab7a73db1805848e8fef3c9e8c78b3" + [[package]] name = "cfg-if" version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" +[[package]] +name = "chacha20" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f8d983286843e49675a4b7a2d174efe136dc93a18d69130dd18198a6c167601" +dependencies = [ + "cfg-if", + "cpufeatures", + "rand_core", +] + +[[package]] +name = "cpufeatures" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b2a41393f66f16b0823bb79094d54ac5fbd34ab292ddafb9a0456ac9f87d201" +dependencies = [ + "libc", +] + [[package]] name = "crossbeam-deque" version = "0.8.6" @@ -45,23 +77,71 @@ version = "1.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "91622ff5e7162018101f2fea40d6ebf4a78bbe5a49736a2020649edf9693679e" +[[package]] +name = "equivalent" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" + +[[package]] +name = "foldhash" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2" + [[package]] name = "getrandom" -version = "0.2.17" +version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff2abc00be7fca6ebc474524697ae276ad847ad0a6b3faa4bcb027e9a4614ad0" +checksum = "0de51e6874e94e7bf76d726fc5d13ba782deca734ff60d5bb2fb2607c7406555" dependencies = [ "cfg-if", "libc", - "wasi", + "r-efi", + "rand_core", + "wasip2", + "wasip3", +] + +[[package]] +name = "hashbrown" +version = "0.15.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1" +dependencies = [ + "foldhash", ] +[[package]] +name = "hashbrown" +version = "0.17.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed5909b6e89a2db4456e54cd5f673791d7eca6732202bbf2a9cc504fe2f9b84a" + [[package]] name = "heck" version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" +[[package]] +name = "id-arena" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d3067d79b975e8844ca9eb072e16b31c3c1c36928edf9c6789548c524d0d954" + +[[package]] +name = "indexmap" +version = "2.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d466e9454f08e4a911e14806c24e16fba1b4c121d1ea474396f396069cf949d9" +dependencies = [ + "equivalent", + "hashbrown 0.17.1", + "serde", + "serde_core", +] + [[package]] name = "indoc" version = "2.0.7" @@ -71,12 +151,30 @@ dependencies = [ "rustversion", ] +[[package]] +name = "itoa" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + +[[package]] +name = "leb128fmt" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09edd9e8b54e49e587e4f6295a7d29c3ea94d469cb40ab8ca70b288248a81db2" + [[package]] name = "libc" version = "0.2.186" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "68ab91017fe16c622486840e4c83c9a37afeff978bd239b5293d61ece587de66" +[[package]] +name = "log" +version = "0.4.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "616ec5685824bcc94416c6d4a7a446eea774a31efd7062c8480ba6fd06d7a6e5" + [[package]] name = "matrixmultiply" version = "0.3.10" @@ -87,6 +185,12 @@ dependencies = [ "rawpointer", ] +[[package]] +name = "memchr" +version = "2.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8ca58f447f06ed17d5fc4043ce1b10dd205e060fb3ce5b979b8ed8e59ff3f79" + [[package]] name = "memoffset" version = "0.9.1" @@ -212,6 +316,16 @@ dependencies = [ "zerocopy", ] +[[package]] +name = "prettyplease" +version = "0.2.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "479ca8adacdd7ce8f1fb39ce9ecccbfe93a3f1344b3d0d97f20bc0196208f62b" +dependencies = [ + "proc-macro2", + "syn", +] + [[package]] name = "proc-macro2" version = "1.0.106" @@ -291,22 +405,28 @@ dependencies = [ "proc-macro2", ] +[[package]] +name = "r-efi" +version = "6.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8dcc9c7d52a811697d2151c701e0d08956f92b0e24136cf4cf27b57a6a0d9bf" + [[package]] name = "rand" -version = "0.8.6" +version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ca0ecfa931c29007047d1bc58e623ab12e5590e8c7cc53200d5202b69266d8a" +checksum = "d2e8e8bcc7961af1fdac401278c6a831614941f6164ee3bf4ce61b7edb162207" dependencies = [ - "libc", - "rand_chacha", + "chacha20", + "getrandom", "rand_core", ] [[package]] name = "rand_chacha" -version = "0.3.1" +version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +checksum = "3e6af7f3e25ded52c41df4e0b1af2d047e45896c2f3281792ed68a1c243daedb" dependencies = [ "ppv-lite86", "rand_core", @@ -314,12 +434,9 @@ dependencies = [ [[package]] name = "rand_core" -version = "0.6.4" +version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" -dependencies = [ - "getrandom", -] +checksum = "63b8176103e19a2643978565ca18b50549f6101881c443590420e4dc998a3c69" [[package]] name = "rawpointer" @@ -359,6 +476,54 @@ version = "1.0.22" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" +[[package]] +name = "semver" +version = "1.0.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a7852d02fc848982e0c167ef163aaff9cd91dc640ba85e263cb1ce46fae51cd" + +[[package]] +name = "serde" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e" +dependencies = [ + "serde_core", +] + +[[package]] +name = "serde_core" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "serde_json" +version = "1.0.150" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e8014e44b4736ed0538adeecded0fce2a272f22dc9578a7eb6b2d9993c74cfb9" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + [[package]] name = "syn" version = "2.0.117" @@ -382,6 +547,12 @@ version = "1.0.24" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75" +[[package]] +name = "unicode-xid" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" + [[package]] name = "unindent" version = "0.2.4" @@ -389,10 +560,150 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7264e107f553ccae879d21fbea1d6724ac785e8c3bfc762137959b5802826ef3" [[package]] -name = "wasi" -version = "0.11.1+wasi-snapshot-preview1" +name = "wasip2" +version = "1.0.3+wasi-0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "20064672db26d7cdc89c7798c48a0fdfac8213434a1186e5ef29fd560ae223d6" +dependencies = [ + "wit-bindgen 0.57.1", +] + +[[package]] +name = "wasip3" +version = "0.4.0+wasi-0.3.0-rc-2026-01-06" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5428f8bf88ea5ddc08faddef2ac4a67e390b88186c703ce6dbd955e1c145aca5" +dependencies = [ + "wit-bindgen 0.51.0", +] + +[[package]] +name = "wasm-encoder" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "990065f2fe63003fe337b932cfb5e3b80e0b4d0f5ff650e6985b1048f62c8319" +dependencies = [ + "leb128fmt", + "wasmparser", +] + +[[package]] +name = "wasm-metadata" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb0e353e6a2fbdc176932bbaab493762eb1255a7900fe0fea1a2f96c296cc909" +dependencies = [ + "anyhow", + "indexmap", + "wasm-encoder", + "wasmparser", +] + +[[package]] +name = "wasmparser" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "47b807c72e1bac69382b3a6fb3dbe8ea4c0ed87ff5629b8685ae6b9a611028fe" +dependencies = [ + "bitflags", + "hashbrown 0.15.5", + "indexmap", + "semver", +] + +[[package]] +name = "wit-bindgen" +version = "0.51.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" +checksum = "d7249219f66ced02969388cf2bb044a09756a083d0fab1e566056b04d9fbcaa5" +dependencies = [ + "wit-bindgen-rust-macro", +] + +[[package]] +name = "wit-bindgen" +version = "0.57.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ebf944e87a7c253233ad6766e082e3cd714b5d03812acc24c318f549614536e" + +[[package]] +name = "wit-bindgen-core" +version = "0.51.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea61de684c3ea68cb082b7a88508a8b27fcc8b797d738bfc99a82facf1d752dc" +dependencies = [ + "anyhow", + "heck", + "wit-parser", +] + +[[package]] +name = "wit-bindgen-rust" +version = "0.51.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7c566e0f4b284dd6561c786d9cb0142da491f46a9fbed79ea69cdad5db17f21" +dependencies = [ + "anyhow", + "heck", + "indexmap", + "prettyplease", + "syn", + "wasm-metadata", + "wit-bindgen-core", + "wit-component", +] + +[[package]] +name = "wit-bindgen-rust-macro" +version = "0.51.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c0f9bfd77e6a48eccf51359e3ae77140a7f50b1e2ebfe62422d8afdaffab17a" +dependencies = [ + "anyhow", + "prettyplease", + "proc-macro2", + "quote", + "syn", + "wit-bindgen-core", + "wit-bindgen-rust", +] + +[[package]] +name = "wit-component" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d66ea20e9553b30172b5e831994e35fbde2d165325bec84fc43dbf6f4eb9cb2" +dependencies = [ + "anyhow", + "bitflags", + "indexmap", + "log", + "serde", + "serde_derive", + "serde_json", + "wasm-encoder", + "wasm-metadata", + "wasmparser", + "wit-parser", +] + +[[package]] +name = "wit-parser" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ecc8ac4bc1dc3381b7f59c34f00b67e18f910c2c0f50015669dde7def656a736" +dependencies = [ + "anyhow", + "id-arena", + "indexmap", + "log", + "semver", + "serde", + "serde_derive", + "serde_json", + "unicode-xid", + "wasmparser", +] [[package]] name = "zerocopy" @@ -413,3 +724,9 @@ dependencies = [ "quote", "syn", ] + +[[package]] +name = "zmij" +version = "1.0.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8848ee67ecc8aedbaf3e4122217aff892639231befc6a1b58d29fff4c2cabaa" diff --git a/Cargo.toml b/Cargo.toml index 91275a62..bfe5b571 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -34,8 +34,8 @@ ordered-float = "5" [dev-dependencies] # Test/bench corpora are seeded with these; not needed by the library. -rand = "0.8" -rand_chacha = "0.3" +rand = "0.10" +rand_chacha = "0.10" [features] # SIMD is always compiled, never feature-gated: x86_64 dispatches AVX-512/AVX2 at diff --git a/examples/bench_rank.rs b/examples/bench_rank.rs index b4a7fd6d..e8c76b08 100644 --- a/examples/bench_rank.rs +++ b/examples/bench_rank.rs @@ -37,7 +37,7 @@ //! downstream tooling. use ordvec::search_asymmetric_byte_lut; -use rand::{Rng, SeedableRng}; +use rand::{RngExt, SeedableRng}; use rand_chacha::ChaCha8Rng; use std::time::Instant; // `RankQuantFastscan` is `#[doc(hidden)]` (optional b=2 scan path); @@ -232,8 +232,8 @@ fn load_npy_f32(path: &str) -> (Vec, usize, usize) { /// Sample a single standard-normal value. fn gauss(rng: &mut ChaCha8Rng) -> f32 { - let u1: f32 = rng.gen_range(1e-9..1.0); - let u2: f32 = rng.gen_range(0.0..1.0); + let u1: f32 = rng.random_range(1e-9..1.0); + let u2: f32 = rng.random_range(0.0..1.0); (-2.0 * u1.ln()).sqrt() * (std::f32::consts::TAU * u2).cos() } @@ -293,14 +293,14 @@ fn make_clustered_corpus(cfg: &Config, seed: u64) -> (Vec, Vec, Vec Vec { let mut rng = ChaCha8Rng::seed_from_u64(seed); - (0..n * D).map(|_| rng.gen_range(-1.0..1.0)).collect() + (0..n * D).map(|_| rng.random_range(-1.0..1.0)).collect() } fn scalar_hamming(q: &[u64], d: &[u64]) -> u32 { @@ -498,7 +498,7 @@ mod tests { let mut idx = SignBitmap::new(D); idx.add(&corpus); let mut rng = ChaCha8Rng::seed_from_u64(11); - let query: Vec = (0..D).map(|_| rng.gen_range(-1.0..1.0)).collect(); + let query: Vec = (0..D).map(|_| rng.random_range(-1.0..1.0)).collect(); let candidates = idx.top_m_candidates(&query, 10); assert_eq!(candidates.len(), 10); // Recompute Hamming distance for each returned candidate and @@ -525,7 +525,7 @@ mod tests { idx.add(&corpus); let mut rng = ChaCha8Rng::seed_from_u64(99); let batch: usize = 5; - let queries: Vec = (0..batch * D).map(|_| rng.gen_range(-1.0..1.0)).collect(); + let queries: Vec = (0..batch * D).map(|_| rng.random_range(-1.0..1.0)).collect(); for m in [10usize, 30, 100] { let single: Vec> = (0..batch) .map(|bi| idx.top_m_candidates(&queries[bi * D..(bi + 1) * D], m)) @@ -552,7 +552,7 @@ mod tests { const BIG_D: usize = 65_536; // u16::MAX + 1 — the smallest dim above the old cap let n = 4; let mut rng = ChaCha8Rng::seed_from_u64(41); - let corpus: Vec = (0..n * BIG_D).map(|_| rng.gen_range(-1.0..1.0)).collect(); + let corpus: Vec = (0..n * BIG_D).map(|_| rng.random_range(-1.0..1.0)).collect(); let mut original = SignBitmap::new(BIG_D); original.add(&corpus); @@ -586,7 +586,7 @@ mod tests { // Sanity: same query produces same top-M. let mut rng = ChaCha8Rng::seed_from_u64(23); - let query: Vec = (0..D).map(|_| rng.gen_range(-1.0..1.0)).collect(); + let query: Vec = (0..D).map(|_| rng.random_range(-1.0..1.0)).collect(); let orig_top = original.top_m_candidates(&query, 10); let loaded_top = loaded.top_m_candidates(&query, 10); assert_eq!(orig_top, loaded_top); @@ -616,10 +616,10 @@ mod tests { const PROD_D: usize = 1024; let n = 256; let mut rng = ChaCha8Rng::seed_from_u64(31); - let corpus: Vec = (0..n * PROD_D).map(|_| rng.gen_range(-1.0..1.0)).collect(); + let corpus: Vec = (0..n * PROD_D).map(|_| rng.random_range(-1.0..1.0)).collect(); let mut idx = SignBitmap::new(PROD_D); idx.add(&corpus); - let queries: Vec = (0..3 * PROD_D).map(|_| rng.gen_range(-1.0..1.0)).collect(); + let queries: Vec = (0..3 * PROD_D).map(|_| rng.random_range(-1.0..1.0)).collect(); // Batched (AVX-512 dispatched at qpv=16) must agree with scalar // reference computed via simple Hamming. let batched = idx.top_m_candidates_batched(&queries, 32); diff --git a/src/util.rs b/src/util.rs index c164cfa2..933dc0c5 100644 --- a/src/util.rs +++ b/src/util.rs @@ -454,7 +454,7 @@ impl TopK { #[cfg(test)] mod tests { use super::{and_popcount, checked_new_len, xor_popcount, TopK}; - use rand::{Rng, SeedableRng}; + use rand::{RngExt, SeedableRng}; use rand_chacha::ChaCha8Rng; fn naive_and(d: &[u64], q: &[u64]) -> u32 { @@ -476,8 +476,8 @@ mod tests { let mut rng = ChaCha8Rng::seed_from_u64(0xC0FFEE); for qpv in [1usize, 2, 3, 4, 7, 8, 15, 16, 17, 31] { for _ in 0..64 { - let d: Vec = (0..qpv).map(|_| rng.gen()).collect(); - let q: Vec = (0..qpv).map(|_| rng.gen()).collect(); + let d: Vec = (0..qpv).map(|_| rng.random()).collect(); + let q: Vec = (0..qpv).map(|_| rng.random()).collect(); assert_eq!(and_popcount(&d, &q), naive_and(&d, &q), "AND qpv={qpv}"); assert_eq!(xor_popcount(&d, &q), naive_xor(&d, &q), "XOR qpv={qpv}"); } diff --git a/tests/index/bitmap.rs b/tests/index/bitmap.rs index b9defca9..be094d49 100644 --- a/tests/index/bitmap.rs +++ b/tests/index/bitmap.rs @@ -4,7 +4,7 @@ use ordvec::rank::rank_transform; use ordvec::{Bitmap, RankQuant}; -use rand::{Rng, SeedableRng}; +use rand::{RngExt, SeedableRng}; use rand_chacha::ChaCha8Rng; use crate::{make_corpus, D, N}; @@ -24,7 +24,7 @@ fn rank_io_round_trip_bitmap_index() { assert_eq!(loaded.n_top(), idx.n_top()); let mut rng = ChaCha8Rng::seed_from_u64(142); - let q: Vec = (0..D).map(|_| rng.gen_range(-1.0..1.0)).collect(); + let q: Vec = (0..D).map(|_| rng.random_range(-1.0..1.0)).collect(); let r1 = idx.search(&q, 10); let r2 = loaded.search(&q, 10); assert_eq!(r1.indices_for_query(0), r2.indices_for_query(0)); @@ -61,7 +61,7 @@ fn bitmap_then_subset_recovers_exact_when_m_eq_n() { rq.add(&corpus); let mut rng = ChaCha8Rng::seed_from_u64(99_999); - let query: Vec = (0..D).map(|_| rng.gen_range(-1.0..1.0)).collect(); + let query: Vec = (0..D).map(|_| rng.random_range(-1.0..1.0)).collect(); // Stage 1 with M = N: candidate set is every doc. let cands = bitmap.top_m_candidates(&query, N); @@ -130,7 +130,7 @@ fn bitmap_top_m_candidates_uses_no_ground_truth() { let mut bitmap = Bitmap::new(D, n_top); bitmap.add(&corpus); let mut rng = ChaCha8Rng::seed_from_u64(50); - let query: Vec = (0..D).map(|_| rng.gen_range(-1.0..1.0)).collect(); + let query: Vec = (0..D).map(|_| rng.random_range(-1.0..1.0)).collect(); let a = bitmap.top_m_candidates(&query, 50); let b = bitmap.top_m_candidates(&query, 50); assert_eq!(a, b, "candidate selection must be deterministic"); @@ -150,21 +150,21 @@ fn bitmap_top_m_candidates_deterministic_at_ties() { // First 150 docs are exact duplicates → all score identically // against any query. Remaining 50 are random. let mut rng = ChaCha8Rng::seed_from_u64(404); - let duplicate_vec: Vec = (0..TIE_D).map(|_| rng.gen_range(-1.0..1.0)).collect(); + let duplicate_vec: Vec = (0..TIE_D).map(|_| rng.random_range(-1.0..1.0)).collect(); let mut corpus: Vec = Vec::with_capacity(TIE_N * TIE_D); for _ in 0..150 { corpus.extend_from_slice(&duplicate_vec); } for _ in 0..50 { for _ in 0..TIE_D { - corpus.push(rng.gen_range(-1.0..1.0)); + corpus.push(rng.random_range(-1.0..1.0)); } } let _ = rank_transform(&duplicate_vec); // assert symbol is in scope let n_top = TIE_D / 4; let mut bitmap = Bitmap::new(TIE_D, n_top); bitmap.add(&corpus); - let query: Vec = (0..TIE_D).map(|_| rng.gen_range(-1.0..1.0)).collect(); + let query: Vec = (0..TIE_D).map(|_| rng.random_range(-1.0..1.0)).collect(); // Repeated calls must produce identical candidate sets — the // composite key forces a unique partition even when 150 docs @@ -180,7 +180,7 @@ fn bitmap_top_m_candidates_deterministic_at_ties() { // Batched path agrees with single-query (the batched-equivalence // guarantee from `bitmap_batched_matches_single_query` extended // to the high-tie regime). - let queries: Vec = (0..3 * TIE_D).map(|_| rng.gen_range(-1.0..1.0)).collect(); + let queries: Vec = (0..3 * TIE_D).map(|_| rng.random_range(-1.0..1.0)).collect(); for q in [ &queries[..TIE_D], &queries[TIE_D..2 * TIE_D], @@ -211,10 +211,10 @@ fn bitmap_batched_avx512_production_dim() { const BATCH: usize = 5; let mut rng = ChaCha8Rng::seed_from_u64(7); let corpus: Vec = (0..N_DOCS * PROD_D) - .map(|_| rng.gen_range(-1.0..1.0)) + .map(|_| rng.random_range(-1.0..1.0)) .collect(); let queries: Vec = (0..BATCH * PROD_D) - .map(|_| rng.gen_range(-1.0..1.0)) + .map(|_| rng.random_range(-1.0..1.0)) .collect(); let n_top = PROD_D / 4; let mut bitmap = Bitmap::new(PROD_D, n_top); @@ -247,10 +247,10 @@ fn bitmap_batched_hot_plus_tail_split() { const BATCH: usize = 11; let mut rng = ChaCha8Rng::seed_from_u64(101); let corpus: Vec = (0..N_DOCS * PROD_D) - .map(|_| rng.gen_range(-1.0..1.0)) + .map(|_| rng.random_range(-1.0..1.0)) .collect(); let queries: Vec = (0..BATCH * PROD_D) - .map(|_| rng.gen_range(-1.0..1.0)) + .map(|_| rng.random_range(-1.0..1.0)) .collect(); let n_top = PROD_D / 4; let mut bitmap = Bitmap::new(PROD_D, n_top); @@ -286,7 +286,7 @@ fn bitmap_batched_edge_cases() { // m == 0: each per-query slot is an empty Vec. let mut rng = ChaCha8Rng::seed_from_u64(202); - let queries: Vec = (0..3 * D).map(|_| rng.gen_range(-1.0..1.0)).collect(); + let queries: Vec = (0..3 * D).map(|_| rng.random_range(-1.0..1.0)).collect(); let res = bitmap.top_m_candidates_batched(&queries, 0); assert_eq!(res.len(), 3); for c in &res { @@ -333,10 +333,10 @@ fn bitmap_batched_avx512_high_qpv_no_panic() { const BATCH: usize = 3; let mut rng = ChaCha8Rng::seed_from_u64(123); let corpus: Vec = (0..N_DOCS * HIGH_D) - .map(|_| rng.gen_range(-1.0..1.0)) + .map(|_| rng.random_range(-1.0..1.0)) .collect(); let queries: Vec = (0..BATCH * HIGH_D) - .map(|_| rng.gen_range(-1.0..1.0)) + .map(|_| rng.random_range(-1.0..1.0)) .collect(); let n_top = HIGH_D / 4; let mut bitmap = Bitmap::new(HIGH_D, n_top); @@ -367,7 +367,7 @@ fn bitmap_batched_matches_single_query() { bitmap.add(&corpus); let mut rng = ChaCha8Rng::seed_from_u64(99); let batch: usize = 7; // intentionally non-power-of-2 - let queries: Vec = (0..batch * D).map(|_| rng.gen_range(-1.0..1.0)).collect(); + let queries: Vec = (0..batch * D).map(|_| rng.random_range(-1.0..1.0)).collect(); for m in [10usize, 50, 100] { let single: Vec> = (0..batch) .map(|bi| bitmap.top_m_candidates(&queries[bi * D..(bi + 1) * D], m)) diff --git a/tests/index/fastscan.rs b/tests/index/fastscan.rs index a9d409ca..c8ed4736 100644 --- a/tests/index/fastscan.rs +++ b/tests/index/fastscan.rs @@ -14,7 +14,7 @@ use std::sync::Arc; use std::thread; use ordvec::{RankQuant, RankQuantFastscan}; -use rand::{Rng, SeedableRng}; +use rand::{RngExt, SeedableRng}; use rand_chacha::ChaCha8Rng; use crate::{make_corpus, D, N}; @@ -30,8 +30,8 @@ fn fastscan_b2_top10_matches_avx512_kernel() { const FN: usize = 100; let mut rng = ChaCha8Rng::seed_from_u64(31337); - let docs: Vec = (0..FN * FD).map(|_| rng.gen_range(-1.0..1.0)).collect(); - let queries: Vec = (0..3 * FD).map(|_| rng.gen_range(-1.0..1.0)).collect(); + let docs: Vec = (0..FN * FD).map(|_| rng.random_range(-1.0..1.0)).collect(); + let queries: Vec = (0..3 * FD).map(|_| rng.random_range(-1.0..1.0)).collect(); // Reference: the production RankQuant asym kernel. let mut idx = RankQuant::new(FD, 2); @@ -74,7 +74,7 @@ fn fastscan_handles_k_zero() { // parallel scan (Codex stop-hook regression, source c4fd4d6). let corpus = make_corpus(250); let mut rng = ChaCha8Rng::seed_from_u64(251); - let queries: Vec = (0..(2 * D)).map(|_| rng.gen_range(-1.0..1.0)).collect(); + let queries: Vec = (0..(2 * D)).map(|_| rng.random_range(-1.0..1.0)).collect(); let mut fs = RankQuantFastscan::new(D); fs.add(&corpus); @@ -116,7 +116,7 @@ fn fastscan_handles_k_greater_than_n_vectors() { const N_SMALL: usize = 5; let mut rng = ChaCha8Rng::seed_from_u64(261); let corpus: Vec = (0..(N_SMALL * D)) - .map(|_| rng.gen_range(-1.0..1.0)) + .map(|_| rng.random_range(-1.0..1.0)) .collect(); let mut fs = RankQuantFastscan::new(D); fs.add(&corpus); @@ -140,7 +140,7 @@ fn fastscan_handles_k_greater_than_n_vectors() { fn fastscan_search_is_thread_safe() { let corpus = make_corpus(262); let mut rng = ChaCha8Rng::seed_from_u64(263); - let queries: Vec = (0..(4 * D)).map(|_| rng.gen_range(-1.0..1.0)).collect(); + let queries: Vec = (0..(4 * D)).map(|_| rng.random_range(-1.0..1.0)).collect(); let mut fs = RankQuantFastscan::new(D); fs.add(&corpus); @@ -174,7 +174,7 @@ fn fastscan_dim_boundary_matrix() { const N_SMALL: usize = 16; let mut rng = ChaCha8Rng::seed_from_u64(270 + dim as u64); let corpus: Vec = (0..(N_SMALL * dim)) - .map(|_| rng.gen_range(-1.0..1.0)) + .map(|_| rng.random_range(-1.0..1.0)) .collect(); let mut fs = RankQuantFastscan::new(dim); fs.add(&corpus); diff --git a/tests/index/main.rs b/tests/index/main.rs index 0408b24f..f20bd3b8 100644 --- a/tests/index/main.rs +++ b/tests/index/main.rs @@ -21,7 +21,7 @@ use std::io::Write; use ordvec::rank::{bucket_centre, bucket_ranks, rank_norm, rank_transform, rankquant_norm}; use ordvec::{Bitmap, Rank, RankQuant, SignBitmap}; -use rand::{Rng, SeedableRng}; +use rand::{RngExt, SeedableRng}; use rand_chacha::ChaCha8Rng; mod bitmap; @@ -41,7 +41,7 @@ pub fn make_corpus(seed: u64) -> Vec { let mut rng = ChaCha8Rng::seed_from_u64(seed); let mut v = vec![0.0f32; N * D]; for x in v.iter_mut() { - *x = rng.gen_range(-1.0..1.0); + *x = rng.random_range(-1.0..1.0); } v } diff --git a/tests/index/multi_bucket.rs b/tests/index/multi_bucket.rs index 773bd4a8..922f4017 100644 --- a/tests/index/multi_bucket.rs +++ b/tests/index/multi_bucket.rs @@ -3,7 +3,7 @@ use ordvec::rank::{bucket_centre, bucket_ranks, rank_transform}; use ordvec::MultiBucketBitmap; -use rand::{Rng, SeedableRng}; +use rand::{RngExt, SeedableRng}; use rand_chacha::ChaCha8Rng; use crate::{make_corpus, D, N}; @@ -21,7 +21,7 @@ fn multi_bucket_bilinear_equals_symmetric_rankquant_inner(bits: u8) { let w = mb.outer_product_weights(); let mut rng = ChaCha8Rng::seed_from_u64(700 + bits as u64); - let query: Vec = (0..D).map(|_| rng.gen_range(-1.0..1.0)).collect(); + let query: Vec = (0..D).map(|_| rng.random_range(-1.0..1.0)).collect(); let q_bitmaps = mb.query_bitmaps_from_ranks(&query); let q_ranks = rank_transform(&query); diff --git a/tests/index/quant.rs b/tests/index/quant.rs index 2627e3cb..79d9e6ef 100644 --- a/tests/index/quant.rs +++ b/tests/index/quant.rs @@ -1,7 +1,7 @@ //! RankQuant (B-bit bucket-packed) integration tests. use ordvec::RankQuant; -use rand::{Rng, SeedableRng}; +use rand::{RngExt, SeedableRng}; use rand_chacha::ChaCha8Rng; use crate::{make_corpus, ref_rankquant_asymmetric, D, N}; @@ -27,7 +27,7 @@ fn rankquant_asymmetric_matches_reference(bits: u8) { idx.add(&corpus); let mut rng = ChaCha8Rng::seed_from_u64(200 + bits as u64); - let query: Vec = (0..D).map(|_| rng.gen_range(-1.0..1.0)).collect(); + let query: Vec = (0..D).map(|_| rng.random_range(-1.0..1.0)).collect(); let res = idx.search_asymmetric(&query, 10); @@ -82,11 +82,11 @@ fn rankquant_b2_recovers_planted_neighbour_in_top_10() { let mut queries = Vec::with_capacity(n_q * D); let mut planted = Vec::with_capacity(n_q); for _ in 0..n_q { - let target = rng.gen_range(0..N); + let target = rng.random_range(0..N); planted.push(target); let src = &corpus[target * D..(target + 1) * D]; for &v in src.iter() { - queries.push(v + rng.gen_range(-0.05..0.05)); + queries.push(v + rng.random_range(-0.05..0.05)); } } // Re-encode the corpus *after* sampling targets so the targets are @@ -142,7 +142,7 @@ fn rank_io_round_trip_rankquant_index() { assert_eq!(loaded.bits(), idx.bits()); let mut rng = ChaCha8Rng::seed_from_u64(141); - let q: Vec = (0..D).map(|_| rng.gen_range(-1.0..1.0)).collect(); + let q: Vec = (0..D).map(|_| rng.random_range(-1.0..1.0)).collect(); let r1 = idx.search_asymmetric(&q, 10); let r2 = loaded.search_asymmetric(&q, 10); assert_eq!(r1.indices_for_query(0), r2.indices_for_query(0)); @@ -160,11 +160,11 @@ fn rankquant_asymmetric_correct_on_simd_invalid_dims() { for &(dim, bits) in &[(48usize, 4u8), (80, 2), (20, 2), (36, 2)] { let n = 40usize; let mut rng = ChaCha8Rng::seed_from_u64(900 + dim as u64 * 8 + bits as u64); - let corpus: Vec = (0..n * dim).map(|_| rng.gen_range(-1.0..1.0)).collect(); + let corpus: Vec = (0..n * dim).map(|_| rng.random_range(-1.0..1.0)).collect(); let mut idx = RankQuant::new(dim, bits); idx.add(&corpus); - let query: Vec = (0..dim).map(|_| rng.gen_range(-1.0..1.0)).collect(); + let query: Vec = (0..dim).map(|_| rng.random_range(-1.0..1.0)).collect(); let res = idx.search_asymmetric(&query, 10); let ref_scores: Vec = (0..n) diff --git a/tests/index/rank.rs b/tests/index/rank.rs index 572a32a2..7660e065 100644 --- a/tests/index/rank.rs +++ b/tests/index/rank.rs @@ -1,7 +1,7 @@ //! Rank (full-precision u16 ranks) integration tests. use ordvec::Rank; -use rand::{Rng, SeedableRng}; +use rand::{RngExt, SeedableRng}; use rand_chacha::ChaCha8Rng; use crate::{make_corpus, ref_asymmetric, ref_rank_cosine, D, N}; @@ -13,7 +13,7 @@ fn rank_index_symmetric_matches_reference() { idx.add(&corpus); let mut rng = ChaCha8Rng::seed_from_u64(99); - let query: Vec = (0..D).map(|_| rng.gen_range(-1.0..1.0)).collect(); + let query: Vec = (0..D).map(|_| rng.random_range(-1.0..1.0)).collect(); let res = idx.search(&query, 10); assert_eq!(res.nq, 1); @@ -54,7 +54,7 @@ fn rank_index_asymmetric_matches_reference() { idx.add(&corpus); let mut rng = ChaCha8Rng::seed_from_u64(100); - let query: Vec = (0..D).map(|_| rng.gen_range(-1.0..1.0)).collect(); + let query: Vec = (0..D).map(|_| rng.random_range(-1.0..1.0)).collect(); let res = idx.search_asymmetric(&query, 10); @@ -98,7 +98,7 @@ fn rank_index_recall_at_10_matches_fp32() { let mut rng = ChaCha8Rng::seed_from_u64(8); let mut queries = Vec::with_capacity(20 * D); for _ in 0..(20 * D) { - queries.push(rng.gen_range(-1.0..1.0)); + queries.push(rng.random_range(-1.0..1.0)); } let res = idx.search(&queries, 10); @@ -163,7 +163,7 @@ fn rank_io_round_trip_rank_index() { assert_eq!(loaded.dim(), idx.dim()); let mut rng = ChaCha8Rng::seed_from_u64(140); - let q: Vec = (0..D).map(|_| rng.gen_range(-1.0..1.0)).collect(); + let q: Vec = (0..D).map(|_| rng.random_range(-1.0..1.0)).collect(); let r1 = idx.search(&q, 10); let r2 = loaded.search(&q, 10); assert_eq!(r1.indices_for_query(0), r2.indices_for_query(0)); diff --git a/tests/redteam_beta.rs b/tests/redteam_beta.rs index 73e25c88..a884d041 100644 --- a/tests/redteam_beta.rs +++ b/tests/redteam_beta.rs @@ -23,7 +23,7 @@ //! end-to-end (routed away from the {2,4}-only byte-LUT path) and //! match a scalar reference. -use rand::{Rng, SeedableRng}; +use rand::{RngExt, SeedableRng}; use rand_chacha::ChaCha8Rng; use ordvec::rank::{bucket_centre, bucket_ranks, rank_transform, rankquant_norm}; @@ -32,7 +32,7 @@ use ordvec::{Rank, RankQuant, SearchResults, SignBitmap}; fn make_corpus(seed: u64, n: usize, dim: usize) -> Vec { let mut rng = ChaCha8Rng::seed_from_u64(seed); - (0..n * dim).map(|_| rng.gen_range(-1.0..1.0)).collect() + (0..n * dim).map(|_| rng.random_range(-1.0..1.0)).collect() } /// Scalar reference for asymmetric RankQuant scoring of one query @@ -78,7 +78,7 @@ fn assert_asym_matches_byte_lut(dim: usize, bits: u8, seed: u64) { idx.add(&corpus); let mut rng = ChaCha8Rng::seed_from_u64(seed.wrapping_add(7)); - let query: Vec = (0..dim).map(|_| rng.gen_range(-1.0..1.0)).collect(); + let query: Vec = (0..dim).map(|_| rng.random_range(-1.0..1.0)).collect(); let k = 10; let prod = idx.search_asymmetric(&query, k); @@ -162,7 +162,7 @@ fn subset_rejects_out_of_range_candidate() { idx.add(&corpus); let mut rng = ChaCha8Rng::seed_from_u64(202); - let query: Vec = (0..dim).map(|_| rng.gen_range(-1.0..1.0)).collect(); + let query: Vec = (0..dim).map(|_| rng.random_range(-1.0..1.0)).collect(); // n_vectors == 32, so id 999 is out of range. let candidates: Vec = vec![0, 1, 999]; @@ -179,7 +179,7 @@ fn subset_accepts_in_range_candidates() { idx.add(&corpus); let mut rng = ChaCha8Rng::seed_from_u64(204); - let query: Vec = (0..dim).map(|_| rng.gen_range(-1.0..1.0)).collect(); + let query: Vec = (0..dim).map(|_| rng.random_range(-1.0..1.0)).collect(); let candidates: Vec = vec![0, 5, (n - 1) as u32]; let (scores, global) = idx.search_asymmetric_subset(&query, &candidates, 3); @@ -351,7 +351,7 @@ fn rankquant_b1_asymmetric_works_and_matches_reference() { idx.add(&corpus); let mut rng = ChaCha8Rng::seed_from_u64(402); - let query: Vec = (0..dim).map(|_| rng.gen_range(-1.0..1.0)).collect(); + let query: Vec = (0..dim).map(|_| rng.random_range(-1.0..1.0)).collect(); let k = 10; let res = idx.search_asymmetric(&query, k); From 815d5702150520cbe0a3712e758dc6a54b7b7b0f Mon Sep 17 00:00:00 2001 From: Nelson Spence Date: Mon, 25 May 2026 11:39:46 -0500 Subject: [PATCH 2/2] chore: apply rustfmt to rand 0.10 migration call sites random_range is longer than the old gen_range, pushing several .map(|_| rng.random_range(..)).collect() chains over the line width. rustfmt wraps them across lines. No behaviour change; fixes the cargo fmt --check gate (rustfmt under cargo 1.95.0). --- src/sign_bitmap.rs | 16 ++++++++++++---- tests/index/bitmap.rs | 8 ++++++-- 2 files changed, 18 insertions(+), 6 deletions(-) diff --git a/src/sign_bitmap.rs b/src/sign_bitmap.rs index 1ab7bbc6..4cf98a02 100644 --- a/src/sign_bitmap.rs +++ b/src/sign_bitmap.rs @@ -525,7 +525,9 @@ mod tests { idx.add(&corpus); let mut rng = ChaCha8Rng::seed_from_u64(99); let batch: usize = 5; - let queries: Vec = (0..batch * D).map(|_| rng.random_range(-1.0..1.0)).collect(); + let queries: Vec = (0..batch * D) + .map(|_| rng.random_range(-1.0..1.0)) + .collect(); for m in [10usize, 30, 100] { let single: Vec> = (0..batch) .map(|bi| idx.top_m_candidates(&queries[bi * D..(bi + 1) * D], m)) @@ -552,7 +554,9 @@ mod tests { const BIG_D: usize = 65_536; // u16::MAX + 1 — the smallest dim above the old cap let n = 4; let mut rng = ChaCha8Rng::seed_from_u64(41); - let corpus: Vec = (0..n * BIG_D).map(|_| rng.random_range(-1.0..1.0)).collect(); + let corpus: Vec = (0..n * BIG_D) + .map(|_| rng.random_range(-1.0..1.0)) + .collect(); let mut original = SignBitmap::new(BIG_D); original.add(&corpus); @@ -616,10 +620,14 @@ mod tests { const PROD_D: usize = 1024; let n = 256; let mut rng = ChaCha8Rng::seed_from_u64(31); - let corpus: Vec = (0..n * PROD_D).map(|_| rng.random_range(-1.0..1.0)).collect(); + let corpus: Vec = (0..n * PROD_D) + .map(|_| rng.random_range(-1.0..1.0)) + .collect(); let mut idx = SignBitmap::new(PROD_D); idx.add(&corpus); - let queries: Vec = (0..3 * PROD_D).map(|_| rng.random_range(-1.0..1.0)).collect(); + let queries: Vec = (0..3 * PROD_D) + .map(|_| rng.random_range(-1.0..1.0)) + .collect(); // Batched (AVX-512 dispatched at qpv=16) must agree with scalar // reference computed via simple Hamming. let batched = idx.top_m_candidates_batched(&queries, 32); diff --git a/tests/index/bitmap.rs b/tests/index/bitmap.rs index be094d49..24689039 100644 --- a/tests/index/bitmap.rs +++ b/tests/index/bitmap.rs @@ -180,7 +180,9 @@ fn bitmap_top_m_candidates_deterministic_at_ties() { // Batched path agrees with single-query (the batched-equivalence // guarantee from `bitmap_batched_matches_single_query` extended // to the high-tie regime). - let queries: Vec = (0..3 * TIE_D).map(|_| rng.random_range(-1.0..1.0)).collect(); + let queries: Vec = (0..3 * TIE_D) + .map(|_| rng.random_range(-1.0..1.0)) + .collect(); for q in [ &queries[..TIE_D], &queries[TIE_D..2 * TIE_D], @@ -367,7 +369,9 @@ fn bitmap_batched_matches_single_query() { bitmap.add(&corpus); let mut rng = ChaCha8Rng::seed_from_u64(99); let batch: usize = 7; // intentionally non-power-of-2 - let queries: Vec = (0..batch * D).map(|_| rng.random_range(-1.0..1.0)).collect(); + let queries: Vec = (0..batch * D) + .map(|_| rng.random_range(-1.0..1.0)) + .collect(); for m in [10usize, 50, 100] { let single: Vec> = (0..batch) .map(|bi| bitmap.top_m_candidates(&queries[bi * D..(bi + 1) * D], m))