geop_core_math/disjoint_set/
mod.rs1use crate::scalars::Scalar;
13use crate::vector::Vector;
14
15pub trait Mergeable: Copy {
19 fn could_be_equal(&self, other: &Self) -> bool;
20 fn union(&self, other: &Self) -> Self;
21}
22
23impl<S: Scalar> Mergeable for S {
24 fn could_be_equal(&self, other: &Self) -> bool {
25 Scalar::could_be_equal(*self, *other)
26 }
27 fn union(&self, other: &Self) -> Self {
28 Scalar::union(*self, *other)
29 }
30}
31
32impl<S: Scalar, const N: usize> Mergeable for Vector<S, N> {
33 fn could_be_equal(&self, other: &Self) -> bool {
34 Vector::could_be_equal(self, other)
35 }
36 fn union(&self, other: &Self) -> Self {
37 Vector::union(self, other)
38 }
39}
40
41impl<A: Mergeable, B: Mergeable> Mergeable for (A, B) {
42 fn could_be_equal(&self, other: &Self) -> bool {
43 self.0.could_be_equal(&other.0) && self.1.could_be_equal(&other.1)
44 }
45 fn union(&self, other: &Self) -> Self {
46 (self.0.union(&other.0), self.1.union(&other.1))
47 }
48}
49
50#[derive(Clone, Debug)]
53pub struct DisjointSet<T: Mergeable> {
54 items: Vec<T>,
55}
56
57impl<T: Mergeable> DisjointSet<T> {
58 pub fn new() -> Self {
59 Self { items: Vec::new() }
60 }
61
62 pub fn len(&self) -> usize {
64 self.items.len()
65 }
66
67 pub fn is_empty(&self) -> bool {
68 self.items.is_empty()
69 }
70
71 pub fn iter(&self) -> impl Iterator<Item = &T> {
72 self.items.iter()
73 }
74
75 pub fn insert(&mut self, mut candidate: T) {
85 let mut at: Option<usize> = None;
86 while let Some(i) = self
87 .items
88 .iter()
89 .position(|item| item.could_be_equal(&candidate))
90 {
91 candidate = candidate.union(&self.items.remove(i));
92 at = Some(at.map_or(i, |a| a.min(i)));
93 }
94 match at {
95 Some(i) => self.items.insert(i, candidate),
96 None => self.items.push(candidate),
97 }
98 }
99
100 pub fn into_vec(self) -> Vec<T> {
101 self.items
102 }
103}
104
105impl<T: Mergeable> Default for DisjointSet<T> {
106 fn default() -> Self {
107 Self::new()
108 }
109}
110
111#[cfg(test)]
112mod tests {
113 use super::DisjointSet;
114 use crate::{for_all_scalars, scalars::Scalar};
115
116 fn check_disjoint_scalars_stay_separate<S: Scalar>() {
117 let mut set = DisjointSet::new();
118 set.insert(S::from_f64(0.1));
119 set.insert(S::from_f64(0.9));
120 assert_eq!(set.len(), 2);
121 }
122 #[test]
123 fn disjoint_scalars_stay_separate() {
124 for_all_scalars!(check_disjoint_scalars_stay_separate);
125 }
126
127 fn check_overlapping_scalars_merge<S: Scalar>() {
128 let mut set = DisjointSet::new();
129 set.insert(S::from_f64(0.5));
130 set.insert(S::from_f64(0.5));
131 assert_eq!(set.len(), 1);
132 }
133 #[test]
134 fn overlapping_scalars_merge() {
135 for_all_scalars!(check_overlapping_scalars_merge);
136 }
137
138 fn check_bridging_candidate_joins_two_solutions<S: Scalar>() {
142 let mut set = DisjointSet::new();
143 set.insert(S::from_f64(0.0));
144 set.insert(S::from_f64(1.0));
145 assert_eq!(set.len(), 2);
146
147 let bridge = S::from_f64(-0.5).union(S::from_f64(1.5));
150 set.insert(bridge);
151 assert_eq!(
152 set.len(),
153 1,
154 "a candidate overlapping both existing entries should merge them into one"
155 );
156 }
157 #[test]
158 fn bridging_candidate_joins_two_solutions() {
159 for_all_scalars!(check_bridging_candidate_joins_two_solutions);
160 }
161}