metrale_grammar/support/
union_find.rs1use std::collections::HashMap;
9use std::hash::Hash;
10
11#[derive(Debug, Default, Clone)]
16pub struct UnionFindSet<T> {
17 parent_and_size: HashMap<T, (T, usize)>,
19}
20
21impl<T: Clone + Eq + Hash + Ord> UnionFindSet<T> {
22 pub fn new() -> Self {
24 Self {
25 parent_and_size: HashMap::new(),
26 }
27 }
28
29 pub fn add(&mut self, element: T) -> bool {
33 if self.parent_and_size.contains_key(&element) {
34 return false;
35 }
36 self.parent_and_size.insert(element.clone(), (element, 1));
37 true
38 }
39
40 pub fn clear(&mut self) {
42 self.parent_and_size.clear();
43 }
44
45 pub fn contains(&self, element: &T) -> bool {
47 self.parent_and_size.contains_key(element)
48 }
49
50 pub fn len(&self) -> usize {
52 self.parent_and_size.len()
53 }
54
55 pub fn is_empty(&self) -> bool {
57 self.parent_and_size.is_empty()
58 }
59
60 pub fn find(&mut self, element: &T) -> T {
67 let parent = self
68 .parent_and_size
69 .get(element)
70 .expect("Element not found in union-find set.")
71 .0
72 .clone();
73 if &parent == element {
74 return parent;
75 }
76 let root = self.find(&parent);
77 if let Some(entry) = self.parent_and_size.get_mut(element) {
79 entry.0 = root.clone();
80 }
81 root
82 }
83
84 pub fn union_sets(&mut self, a: &T, b: &T) {
89 assert!(
90 self.parent_and_size.contains_key(a),
91 "Element not found in union-find set."
92 );
93 assert!(
94 self.parent_and_size.contains_key(b),
95 "Element not found in union-find set."
96 );
97 let mut root_a = self.find(a);
98 let mut root_b = self.find(b);
99 if root_a == root_b {
100 return;
101 }
102 let size_a = self.parent_and_size[&root_a].1;
103 let size_b = self.parent_and_size[&root_b].1;
104 if size_a < size_b {
106 std::mem::swap(&mut root_a, &mut root_b);
107 }
108 let combined = self.parent_and_size[&root_a].1 + self.parent_and_size[&root_b].1;
109 self.parent_and_size.get_mut(&root_b).unwrap().0 = root_a.clone();
110 self.parent_and_size.get_mut(&root_a).unwrap().1 = combined;
111 }
112
113 pub fn all_sets(&mut self) -> Vec<Vec<T>> {
118 let elements: Vec<T> = self.parent_and_size.keys().cloned().collect();
119 let mut root_to_idx: HashMap<T, usize> = HashMap::new();
120 let mut result: Vec<Vec<T>> = Vec::new();
121 for value in elements {
122 let root = self.find(&value);
123 let idx = *root_to_idx.entry(root).or_insert_with(|| {
124 result.push(Vec::new());
125 result.len() - 1
126 });
127 result[idx].push(value);
128 }
129 for vec in result.iter_mut() {
130 vec.sort();
131 }
132 result.sort_by(|v1, v2| v1[0].cmp(&v2[0]));
133 result
134 }
135}
136
137#[cfg(test)]
138mod tests {
139 use super::*;
140
141 #[test]
142 fn add_returns_false_on_duplicate() {
143 let mut uf: UnionFindSet<i32> = UnionFindSet::new();
144 assert!(uf.add(1));
145 assert!(!uf.add(1));
146 assert_eq!(uf.len(), 1);
147 }
148
149 #[test]
150 fn singleton_is_its_own_root() {
151 let mut uf = UnionFindSet::new();
152 uf.add(5);
153 assert_eq!(uf.find(&5), 5);
154 }
155
156 #[test]
157 fn union_merges_sets() {
158 let mut uf = UnionFindSet::new();
159 for i in 1..=4 {
160 uf.add(i);
161 }
162 uf.union_sets(&1, &2);
163 uf.union_sets(&3, &4);
164 assert_eq!(uf.find(&1), uf.find(&2));
165 assert_eq!(uf.find(&3), uf.find(&4));
166 assert_ne!(uf.find(&1), uf.find(&3));
167 uf.union_sets(&2, &3);
168 assert_eq!(uf.find(&1), uf.find(&4));
169 }
170
171 #[test]
172 fn union_idempotent_on_same_set() {
173 let mut uf = UnionFindSet::new();
174 uf.add(1);
175 uf.add(2);
176 uf.union_sets(&1, &2);
177 uf.union_sets(&1, &2);
178 assert_eq!(uf.find(&1), uf.find(&2));
179 }
180
181 #[test]
182 fn all_sets_is_deterministic() {
183 let mut uf = UnionFindSet::new();
184 for i in 1..=6 {
185 uf.add(i);
186 }
187 uf.union_sets(&1, &3);
188 uf.union_sets(&3, &5);
189 uf.union_sets(&2, &4);
190 let sets = uf.all_sets();
191 assert_eq!(sets, vec![vec![1, 3, 5], vec![2, 4], vec![6]]);
192 }
193
194 #[test]
195 fn clear_empties_the_set() {
196 let mut uf = UnionFindSet::new();
197 uf.add(1);
198 uf.add(2);
199 uf.clear();
200 assert!(uf.is_empty());
201 assert!(!uf.contains(&1));
202 }
203
204 #[test]
205 fn contains_reports_membership() {
206 let mut uf = UnionFindSet::new();
207 uf.add(42);
208 assert!(uf.contains(&42));
209 assert!(!uf.contains(&7));
210 }
211
212 #[test]
213 #[should_panic(expected = "Element not found")]
214 fn find_missing_panics() {
215 let mut uf: UnionFindSet<i32> = UnionFindSet::new();
216 uf.find(&99);
217 }
218
219 #[test]
220 fn works_with_string_elements() {
221 let mut uf: UnionFindSet<String> = UnionFindSet::new();
222 uf.add("a".to_string());
223 uf.add("b".to_string());
224 uf.add("c".to_string());
225 uf.union_sets(&"a".to_string(), &"c".to_string());
226 let sets = uf.all_sets();
227 assert_eq!(
228 sets,
229 vec![
230 vec!["a".to_string(), "c".to_string()],
231 vec!["b".to_string()]
232 ]
233 );
234 }
235}