natural_breaks/lib.rs
1#![doc = include_str!("../README.md")]
2
3pub mod error;
4pub mod k_n2;
5pub mod k_nlogn;
6pub mod kn;
7pub(crate) mod util;
8
9use error::Error;
10/// Re-exported so downstream users can use the `ToPrimitive` bound in their own
11/// generic code without adding `num-traits` to their `Cargo.toml`.
12pub use num_traits::ToPrimitive;
13
14/// Clustered values returned by [`classify`] and [`classify_with_sort`].
15pub type ClassifiedResult<T> = Vec<Vec<T>>;
16
17/// Half-open index ranges `[start, end)` returned by [`classify_indices`] and
18/// [`classify_indices_with_sort`].
19pub type IndexRanges = Vec<(usize, usize)>;
20
21// Default top-level convenience functions using the O(kn log n) implementation.
22// For specific algorithm choice, use the module directly:
23// k_n2::KNSquared, k_nlogn::KNLogN, kn::KN
24
25/// Classifies pre-sorted data into `k` clusters using the natural breaks algorithm.
26///
27/// Uses the O(kn log n) divide-and-conquer algorithm.
28/// See [`k_nlogn::KNLogN`] for details.
29///
30/// # Warning
31/// **`data` MUST be sorted in ascending order.** Passing unsorted data will produce
32/// meaningless results without any error. Use [`classify_with_sort`] if your data is
33/// not pre-sorted.
34///
35/// Returns an error if the data contains NaN values.
36pub fn classify<T>(data: Vec<T>, k: usize) -> Result<ClassifiedResult<T>, Error>
37where
38 T: PartialOrd + Clone + ToPrimitive,
39{
40 k_nlogn::KNLogN::classify(data, k)
41}
42
43/// Classifies pre-sorted data into `k` clusters, returning [`IndexRanges`].
44///
45/// Each returned tuple `(start, end)` represents a half-open range `[start, end)`
46/// into the input slice.
47///
48/// Uses the O(kn log n) divide-and-conquer algorithm.
49/// See [`k_nlogn::KNLogN`] for details.
50///
51/// # Warning
52/// **`data` MUST be sorted in ascending order.** Passing unsorted data will produce
53/// meaningless results without any error. Use [`classify_indices_with_sort`] if your
54/// data is not pre-sorted.
55pub fn classify_indices<T>(data: &[T], k: usize) -> Result<IndexRanges, Error>
56where
57 T: PartialOrd + Clone + ToPrimitive,
58{
59 k_nlogn::KNLogN::classify_indices(data, k)
60}
61
62/// Sorts the data and classifies it into `k` clusters using the natural breaks algorithm.
63///
64/// Uses the O(kn log n + n log n) divide-and-conquer algorithm.
65/// See [`k_nlogn::KNLogN`] for details.
66///
67/// Returns an error if the data contains NaN values.
68pub fn classify_with_sort<T>(data: Vec<T>, k: usize) -> Result<ClassifiedResult<T>, Error>
69where
70 T: PartialOrd + Clone + ToPrimitive,
71{
72 k_nlogn::KNLogN::classify_with_sort(data, k)
73}
74
75/// Sorts the data and classifies into `k` clusters, returning [`IndexRanges`].
76///
77/// Each returned tuple `(start, end)` represents a half-open range `[start, end)`
78/// into the **sorted** data.
79///
80/// Uses the O(kn log n + n log n) divide-and-conquer algorithm.
81/// See [`k_nlogn::KNLogN`] for details.
82///
83/// Returns an error if the data contains NaN values.
84pub fn classify_indices_with_sort<T>(data: Vec<T>, k: usize) -> Result<IndexRanges, Error>
85where
86 T: PartialOrd + Clone + ToPrimitive,
87{
88 k_nlogn::KNLogN::classify_indices_with_sort(data, k)
89}