diff --git a/Cargo.lock.MSRV b/Cargo.lock.MSRV index d7585419..9faa9327 100644 --- a/Cargo.lock.MSRV +++ b/Cargo.lock.MSRV @@ -347,12 +347,12 @@ dependencies = [ [[package]] name = "kdtree" -version = "0.7.0" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f0a0e9f770b65bac9aad00f97a67ab5c5319effed07f6da385da3c2115e47ba" +checksum = "9cd666c2aae5dde60d2f9bfa4e1f8c17698fce13d599c0f9b76725641fec13d9" dependencies = [ "num-traits", - "thiserror 1.0.69", + "thiserror", ] [[package]] @@ -718,7 +718,7 @@ dependencies = [ "nalgebra", "num-traits", "rand", - "thiserror 2.0.19", + "thiserror", ] [[package]] @@ -743,33 +743,13 @@ dependencies = [ "unicode-ident", ] -[[package]] -name = "thiserror" -version = "1.0.69" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" -dependencies = [ - "thiserror-impl 1.0.69", -] - [[package]] name = "thiserror" version = "2.0.19" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09a43598840e33d5b0331f38c5e30d13bb11c11210a4b58f0d9b18a5a5eefcd9" dependencies = [ - "thiserror-impl 2.0.19", -] - -[[package]] -name = "thiserror-impl" -version = "1.0.69" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.119", + "thiserror-impl", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index 120e3bfa..6e3fd32e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -53,7 +53,7 @@ optional = true default-features = false [dependencies.kdtree] -version = "0.7.0" +version = "0.8.1" optional = true [dev-dependencies] diff --git a/src/density/kde.rs b/src/density/kde.rs index caa17720..3d561d24 100644 --- a/src/density/kde.rs +++ b/src/density/kde.rs @@ -1,7 +1,7 @@ use kdtree::distance::squared_euclidean; use crate::{ - density::{Container, DensityError, nearest_neighbors}, + density::{Container, DensityError, nearest_neighbors, neighborhood_radius}, function::kernel::{Gaussian, Kernel}, }; @@ -30,7 +30,7 @@ where if neighbors.is_empty() { Err(DensityError::EmptyNeighborhood) } else { - let radius = neighbors.last().unwrap().sqrt(); // safe to unwrap here since `neighbors` is not empty + let radius = neighborhood_radius(&neighbors).unwrap(); let d = x.length() as i32; Ok((1. / (n_samples * radius.powi(d))) * samples diff --git a/src/density/knn.rs b/src/density/knn.rs index 1f58637d..95d44dd4 100644 --- a/src/density/knn.rs +++ b/src/density/knn.rs @@ -1,6 +1,6 @@ use super::Container; use crate::{ - density::{DensityError, nearest_neighbors}, + density::{DensityError, nearest_neighbors, neighborhood_radius}, function::gamma::gamma, }; use core::f64::consts::PI; @@ -30,7 +30,7 @@ where if neighbors.is_empty() { Err(DensityError::EmptyNeighborhood) } else { - let radius = neighbors.last().unwrap().sqrt(); + let radius = neighborhood_radius(&neighbors).unwrap(); let d = x.length() as f64; Ok((k / n_samples) * (gamma(d / 2. + 1.) / (PI.powf(d / 2.) * radius.powf(d)))) } diff --git a/src/density/mod.rs b/src/density/mod.rs index cfb51cbc..0e18eca9 100644 --- a/src/density/mod.rs +++ b/src/density/mod.rs @@ -79,6 +79,14 @@ impl_container!( ); pub type NearestNeighbors = (Vec, f64); +pub(crate) fn neighborhood_radius(neighbors: &[f64]) -> Option { + neighbors + .iter() + .copied() + .max_by(f64::total_cmp) + .map(f64::sqrt) +} + pub(crate) fn nearest_neighbors( x: &X, samples: &S, @@ -118,6 +126,11 @@ mod tests { use super::*; + #[test] + fn neighborhood_radius_uses_farthest_distance() { + assert_eq!(neighborhood_radius(&[4.0, 1.0, 9.0, 2.0]), Some(3.0)); + } + #[test] fn test_vec_container() { let v1 = vec![1.0, 2.0, 3.0];