1 #![allow(non_snake_case)]
2 #![allow(non_camel_case_types)]
3
4 //! An implementation of a fast union-find implementation for "T: ToFromU32" items
5 //! in some dense range [0, N-1].
6
7 use std::marker::PhantomData;
8
9 //=============================================================================
10 // ToFromU32
11
12 // First, we need this. You can store anything you like in this union-find
13 // mechanism, so long as it is really a u32. Reminds me of that old joke
14 // about the Model T Ford being available in any colour you want, so long as
15 // it is black.
16 pub trait ToFromU32<T: Sized = Self> {
to_u32(x: Self) -> u3217 fn to_u32(x: Self) -> u32;
from_u32(x: u32) -> Self18 fn from_u32(x: u32) -> Self;
19 }
20 //impl ToFromU32 for i32 {
21 // fn to_u32(x: i32) -> u32 {
22 // x as u32
23 // }
24 // fn from_u32(x: u32) -> i32 {
25 // x as i32
26 // }
27 //}
28 impl ToFromU32 for u32 {
to_u32(x: u32) -> u3229 fn to_u32(x: u32) -> u32 {
30 x
31 }
from_u32(x: u32) -> u3232 fn from_u32(x: u32) -> u32 {
33 x
34 }
35 }
36
37 //=============================================================================
38 // UnionFind
39
40 // This is a fast union-find implementation for "T: ToFromU32" items in some
41 // dense range [0, N-1]. The allowed operations are:
42 //
43 // (1) create a new `UnionFind`er
44 //
45 // (2) mark two elements as being in the same equivalence class
46 //
47 // (3) get the equivalence classes wrapped up in an opaque structure
48 // `UnionFindEquivClasses`, which makes it possible to cheaply find and
49 // iterate through the equivalence class of any item.
50 //
51 // (4) get an iterator over the "equivalence class leaders". Iterating this
52 // produces one value from each equivalence class. By presenting each of
53 // these to (3), it is possible to enumerate all the equivalence classes
54 // exactly once.
55 //
56 // `UnionFind` and the operations `union` and `find` are loosely based on the
57 // discussion in Chapter 8 of "Data Structures and Algorithm Analysis in C"
58 // (Mark Allen Weiss, 1993). `UnionFindEquivClasses` and the algorithm to
59 // construct it is home-grown; although I'm sure the same idea has been
60 // implemented many times before.
61
62 pub struct UnionFind<T: ToFromU32> {
63 // These are the trees that we are building. A value that is negative means
64 // that this node is a tree root, and the negation of its value is the size
65 // of the tree. A value that is positive (which must be in the range [0,
66 // N-1]) indicates that this tree is a subtree and that its parent has the
67 // given index.
68 //
69 // One consequence of this representation is that at most 2^31-1 values can
70 // be supported. Doesn't seem like much of a limitation in practice, given
71 // that all of this allocator's data structures are limited to 2^32 entries.
72 /*priv*/
73 parent_or_size: Vec<i32>,
74
75 // Keep the typechecker happy
76 /*priv*/
77 anchor: PhantomData<T>,
78 }
79
80 /*priv*/
81 const UF_MAX_SIZE: u32 = 0x7FFF_FFF0;
82
83 impl<T: ToFromU32> UnionFind<T> {
new(size: usize) -> Self84 pub fn new(size: usize) -> Self {
85 // Test a slightly conservative limit to avoid any off-by-one errors.
86 if size > UF_MAX_SIZE as usize {
87 panic!("UnionFind::new: too many elements; max = 2^31 - 16.");
88 }
89 let mut parent_or_size = Vec::<i32>::new();
90 parent_or_size.resize(size, -1);
91 Self {
92 parent_or_size,
93 anchor: PhantomData,
94 }
95 }
96
97 // Find, with path compression. Returns the index of tree root for the
98 // given element. This is not for external use. There's no boundary
99 // checking since Rust will do that anyway.
100 //
101 // This was initially implemented using a recursive function. However,
102 // this function gets called a lot, and the recursion led to significant
103 // expense. Attempts to replace the recursion with an explicit stack
104 // didn't give much speedup. Hence the following scheme, which retains
105 // the recursion but unrolls the function. To avoid performance problems
106 // caused by the interaction of inlining and recursion, it is split into
107 // two functions: `find` and `find_slow`.
108 //
109 // This is the main function. It is hot, so it is unrolled 4 times. If
110 // those 4 iterations don't complete the traversal back to the root, it
111 // calls onwards to `find_slow`, which recurses. The idea is that `find`
112 // handles the majority of the cases and can always be inlined, and we
113 // hand off the remaining cases to `find_slow` which will never be inlined
114 // (and hence will not interfere with the inlining of this function).
115 //
116 // As a reminder of the comments above:
117 //
118 // * A `parent_or_size` value that is negative means that this node is a
119 // tree root.
120 //
121 // * A `parent_or_size` that is non-negative indicates that this tree is a
122 // subtree, and its parent has the given index in `parent_or_size`.
123 #[inline(always)]
find(&mut self, elem0: u32) -> u32124 fn find(&mut self, elem0: u32) -> u32 {
125 // Handle up to 4 steps up the tree in-line.
126 let elem0_parent_or_size: i32 = self.parent_or_size[elem0 as usize];
127 if elem0_parent_or_size < 0 {
128 // We're at a tree root.
129 return elem0;
130 }
131
132 let elem1 = elem0_parent_or_size as u32;
133 let elem1_parent_or_size: i32 = self.parent_or_size[elem1 as usize];
134 if elem1_parent_or_size < 0 {
135 self.parent_or_size[elem0 as usize] = elem1 as i32;
136 return elem1;
137 }
138
139 let elem2 = elem1_parent_or_size as u32;
140 let elem2_parent_or_size: i32 = self.parent_or_size[elem2 as usize];
141 if elem2_parent_or_size < 0 {
142 self.parent_or_size[elem1 as usize] = elem2 as i32;
143 self.parent_or_size[elem0 as usize] = elem2 as i32;
144 return elem2;
145 }
146
147 let elem3 = elem2_parent_or_size as u32;
148 let elem3_parent_or_size: i32 = self.parent_or_size[elem3 as usize];
149 if elem3_parent_or_size < 0 {
150 self.parent_or_size[elem2 as usize] = elem3 as i32;
151 self.parent_or_size[elem1 as usize] = elem3 as i32;
152 self.parent_or_size[elem0 as usize] = elem3 as i32;
153 return elem3;
154 }
155
156 // Hand off to `find_slow` to deal with all the remaining steps.
157 let elem4 = elem3_parent_or_size as u32;
158 let root = self.find_slow(elem4);
159 assert!(root < UF_MAX_SIZE);
160 self.parent_or_size[elem3 as usize] = root as i32;
161 self.parent_or_size[elem2 as usize] = root as i32;
162 self.parent_or_size[elem1 as usize] = root as i32;
163 self.parent_or_size[elem0 as usize] = root as i32;
164 return root;
165 }
166
167 // This is the same as `find`, except with unroll factor of 2 rather than
168 // 4, and self-recursive. Don't call it directly. It is intended only as
169 // a fallback for `find`.
170 #[inline(never)]
find_slow(&mut self, elem0: u32) -> u32171 fn find_slow(&mut self, elem0: u32) -> u32 {
172 // Recurse up to the root. On the way back out, make all nodes point
173 // directly at the root index.
174
175 let elem0_parent_or_size: i32 = self.parent_or_size[elem0 as usize];
176 if elem0_parent_or_size < 0 {
177 // We're at a tree root.
178 return elem0;
179 }
180
181 let elem1 = elem0_parent_or_size as u32;
182 let elem1_parent_or_size: i32 = self.parent_or_size[elem1 as usize];
183 if elem1_parent_or_size < 0 {
184 self.parent_or_size[elem0 as usize] = elem1 as i32;
185 return elem1;
186 }
187
188 let elem2 = elem1_parent_or_size as u32;
189 let root = self.find_slow(elem2);
190 assert!(root < UF_MAX_SIZE);
191 self.parent_or_size[elem1 as usize] = root as i32;
192 self.parent_or_size[elem0 as usize] = root as i32;
193 return root;
194 }
195
196 // Union, by size (weight). This is publicly visible.
union(&mut self, elem1t: T, elem2t: T)197 pub fn union(&mut self, elem1t: T, elem2t: T) {
198 let elem1 = ToFromU32::to_u32(elem1t);
199 let elem2 = ToFromU32::to_u32(elem2t);
200 if elem1 == elem2 {
201 // Ideally, we'd alert the callers they're mistakenly do `union` on
202 // identical values repeatedly, but fuzzing hits this repeatedly.
203 return;
204 }
205 let root1: u32 = self.find(elem1);
206 let root2: u32 = self.find(elem2);
207 if root1 == root2 {
208 // `elem1` and `elem2` are already in the same tree. Do nothing.
209 return;
210 }
211 let size1: i32 = self.parent_or_size[root1 as usize];
212 let size2: i32 = self.parent_or_size[root2 as usize];
213 // "They are both roots"
214 assert!(size1 < 0 && size2 < 0);
215 // Make the root of the smaller tree point at the root of the bigger tree.
216 // Update the root of the bigger tree to reflect its increased size. That
217 // only requires adding the two `size` values, since they are both
218 // negative, so adding them will (correctly) drive it more negative.
219 if size1 < size2 {
220 self.parent_or_size[root1 as usize] = root2 as i32;
221 self.parent_or_size[root2 as usize] += size1;
222 } else {
223 self.parent_or_size[root2 as usize] = root1 as i32;
224 self.parent_or_size[root1 as usize] += size2;
225 }
226 }
227 }
228
229 //=============================================================================
230 // UnionFindEquivClasses
231
232 // This is a compact representation for all the equivalence classes in a
233 // `UnionFind`, that can be constructed in more-or-less linear time (meaning,
234 // O(universe size), and allows iteration over the elements of each
235 // equivalence class in time linear in the size of the equivalence class (you
236 // can't ask for better). It doesn't support queries of the form "are these
237 // two elements in the same equivalence class" in linear time, but we don't
238 // care about that. What we care about is being able to find and visit the
239 // equivalence class of an element quickly.
240 //
241 // The fields are non-public. What is publically available is the ability to
242 // get an iterator (for the equivalence class elements), given a starting
243 // element.
244
245 /*priv*/
246 const UFEC_NULL: u32 = 0xFFFF_FFFF;
247
248 /*priv*/
249 #[derive(Clone)]
250 struct LLElem {
251 // This list element
252 elem: u32,
253 // Pointer to the rest of the list (index in `llelems`), or UFEC_NULL.
254 tail: u32,
255 }
256
257 pub struct UnionFindEquivClasses<T: ToFromU32> {
258 // Linked list start "pointers". Has .len() == universe size. Entries must
259 // not be UFEC_NULL since each element is at least a member of its own
260 // equivalence class.
261 /*priv*/
262 heads: Vec<u32>,
263
264 // Linked list elements. Has .len() == universe size.
265 /*priv*/
266 lists: Vec<LLElem>,
267
268 // Keep the typechecker happy
269 /*priv*/
270 anchor: PhantomData<T>,
271 // This struct doesn't have a `new` method since construction is done by a
272 // carefully designed algorithm, `UnionFind::get_equiv_classes`.
273 }
274
275 impl<T: ToFromU32> UnionFind<T> {
276 // This requires mutable `self` because it needs to do a bunch of `find`
277 // operations, and those modify `self` in order to perform path compression.
278 // We could avoid this by using a non-path-compressing `find` operation, but
279 // that could have the serious side effect of making the big-O complexity of
280 // `get_equiv_classes` worse. Hence we play safe and accept the mutability
281 // requirement.
get_equiv_classes(&mut self) -> UnionFindEquivClasses<T>282 pub fn get_equiv_classes(&mut self) -> UnionFindEquivClasses<T> {
283 let nElemsUSize = self.parent_or_size.len();
284 // The construction algorithm requires that all elements have a value
285 // strictly less than 2^31. The union-find machinery, that builds
286 // `parent_or_size` that we read here, however relies on a slightly
287 // tighter bound, which which we reiterate here due to general paranoia:
288 assert!(nElemsUSize < UF_MAX_SIZE as usize);
289 let nElems = nElemsUSize as u32;
290
291 // Avoid reallocation; we know how big these need to be.
292 let mut heads = Vec::<u32>::new();
293 heads.resize(nElems as usize, UFEC_NULL); // all invalid
294
295 let mut lists = Vec::<LLElem>::new();
296 lists.resize(
297 nElems as usize,
298 LLElem {
299 elem: 0,
300 tail: UFEC_NULL,
301 },
302 );
303
304 // As explanation, let there be N elements (`nElems`) which have been
305 // partitioned into M <= N equivalence classes by calls to `union`.
306 //
307 // When we are finished, `lists` will contain M independent linked lists,
308 // each of which represents one equivalence class, and which is terminated
309 // by UFEC_NULL. And `heads` is used to point to the starting point of
310 // each elem's equivalence class, as follows:
311 //
312 // * if heads[elem][bit 31] == 1, then heads[i][bits 30:0] contain the
313 // index in lists[] of the first element in `elem`s equivalence class.
314 //
315 // * if heads[elem][bit 31] == 0, then heads[i][bits 30:0] contain tell us
316 // what `elem`s equivalence class leader is. That is, heads[i][bits
317 // 30:0] tells us the index in `heads` of the entry that contains the
318 // first element in `elem`s equivalence class.
319 //
320 // With this arrangement, we can:
321 //
322 // * detect whether `elem` is an equivalence class leader, by inspecting
323 // heads[elem][bit 31]
324 //
325 // * find the start of `elem`s equivalence class list, either by using
326 // heads[elem][bits 30:0] directly if heads[elem][bit 31] == 1, or
327 // using a single indirection if heads[elem][bit 31] == 0.
328 //
329 // For a universe of size N, this makes it possible to:
330 //
331 // * find the equivalence class list of any elem in O(1) time.
332 //
333 // * find and iterate through any single equivalence class in time O(1) +
334 // O(size of the equivalence class).
335 //
336 // * find all the equivalence class headers in O(N) time.
337 //
338 // * find all the equivalence class headers, and then iterate through each
339 // equivalence class exactly once, in time k1.O(N) + k2.O(N). The first
340 // term is the cost of finding all the headers. The second term is the
341 // cost of visiting all elements of each equivalence class exactly once.
342 //
343 // The construction algorithm requires two forward passes over
344 // `parent_or_size`.
345 //
346 // In the first pass, we visit each element. If a element is a tree root,
347 // its `heads` entry is left at UFEC_NULL. If a element isn't a tree
348 // root, we use `find` to find the root element, and set
349 // `heads[elem][30:0]` to be the tree root, and heads[elem][31] to 0.
350 // Hence, after the first pass, `heads` maps each non-root element to its
351 // equivalence class leader.
352 //
353 // The second pass builds the lists. We again visit each element. If a
354 // element is a tree root, it is added as a list element, and its `heads`
355 // entry is updated to point at the list element. If a element isn't a
356 // tree root, we find its root in constant time by inspecting its `head`
357 // entry. The element is added to the the root element's list, and the
358 // root element's `head` entry is accordingly updated. Hence, after the
359 // second pass, the `head` entry for root elements points to a linked list
360 // that contains all elements in that tree. And the `head` entry for
361 // non-root elements is unchanged from the first pass, that is, it points
362 // to the `head` entry for that element's root element.
363 //
364 // Note that the heads[] entry for any class leader (tree root) can never
365 // be UFEC_NULL, since all elements must at least be in an equivalence
366 // class of size 1. Hence there is no confusion possible resulting from
367 // using the heads bit 31 entries as a direct/indirect flag.
368
369 // First pass
370 for i in 0..nElems {
371 if self.parent_or_size[i as usize] >= 0 {
372 // i is non-root
373 let root_i: u32 = self.find(i);
374 assert!(root_i < 0x8000_0000u32);
375 heads[i as usize] = root_i; // .direct flag == 0
376 }
377 }
378
379 // Second pass
380 let mut list_bump = 0u32;
381 for i in 0..nElems {
382 if self.parent_or_size[i as usize] < 0 {
383 // i is root
384 lists[list_bump as usize] = LLElem {
385 elem: i,
386 tail: if heads[i as usize] == UFEC_NULL {
387 UFEC_NULL
388 } else {
389 heads[i as usize] & 0x7FFF_FFFF
390 },
391 };
392 assert!(list_bump < 0x8000_0000u32);
393 heads[i as usize] = list_bump | 0x8000_0000u32; // .direct flag == 1
394 list_bump += 1;
395 } else {
396 // i is non-root
397 let i_root = heads[i as usize];
398 lists[list_bump as usize] = LLElem {
399 elem: i,
400 tail: if heads[i_root as usize] == UFEC_NULL {
401 UFEC_NULL
402 } else {
403 heads[i_root as usize] & 0x7FFF_FFFF
404 },
405 };
406 assert!(list_bump < 0x8000_0000u32);
407 heads[i_root as usize] = list_bump | 0x8000_0000u32; // .direct flag == 1
408 list_bump += 1;
409 }
410 }
411 assert!(list_bump == nElems);
412
413 // It's a wrap!
414 assert!(heads.len() == nElemsUSize);
415 assert!(lists.len() == nElemsUSize);
416 //{
417 // for i in 0 .. heads.len() {
418 // println!("{}: heads {:x} lists.elem {} .tail {:x}", i,
419 // heads[i], lists[i].elem, lists[i].tail);
420 // }
421 //}
422 UnionFindEquivClasses {
423 heads,
424 lists,
425 anchor: PhantomData,
426 }
427 }
428 }
429
430 impl<T: ToFromU32> UnionFindEquivClasses<T> {
431 // Indicates whether `item1` and `item2` are in the same equivalence
432 // class. If either falls outside the "universe", returns `None`.
in_same_equivalence_class(&self, item1: T, item2: T) -> Option<bool>433 pub fn in_same_equivalence_class(&self, item1: T, item2: T) -> Option<bool> {
434 let mut item1num = ToFromU32::to_u32(item1) as usize;
435 let mut item2num = ToFromU32::to_u32(item2) as usize;
436 // If either item is outside our "universe", say we don't know.
437 if item1num >= self.heads.len() || item2num >= self.heads.len() {
438 return None;
439 }
440 // Ensure that `item1num` and `item2num` both point at class leaders.
441 if (self.heads[item1num] & 0x8000_0000) == 0 {
442 item1num = self.heads[item1num] as usize;
443 }
444 if (self.heads[item2num] & 0x8000_0000) == 0 {
445 item2num = self.heads[item2num] as usize;
446 }
447 debug_assert!((self.heads[item1num] & 0x8000_0000) == 0x8000_0000);
448 debug_assert!((self.heads[item2num] & 0x8000_0000) == 0x8000_0000);
449 Some(item1num == item2num)
450 }
451 }
452
453 //=============================================================================
454 // UnionFindEquivClassElemsIter
455
456 // We may want to find the equivalence class for some given element, and
457 // iterate through its elements. This iterator provides that.
458
459 pub struct UnionFindEquivClassElemsIter<'a, T: ToFromU32> {
460 // The equivalence classes
461 /*priv*/
462 ufec: &'a UnionFindEquivClasses<T>,
463 // Index into `ufec.lists`, or UFEC_NULL.
464 /*priv*/
465 next: u32,
466 }
467
468 impl<T: ToFromU32> UnionFindEquivClasses<T> {
equiv_class_elems_iter<'a>(&'a self, item: T) -> UnionFindEquivClassElemsIter<'a, T>469 pub fn equiv_class_elems_iter<'a>(&'a self, item: T) -> UnionFindEquivClassElemsIter<'a, T> {
470 let mut itemU32 = ToFromU32::to_u32(item);
471 assert!((itemU32 as usize) < self.heads.len());
472 if (self.heads[itemU32 as usize] & 0x8000_0000) == 0 {
473 // .direct flag is not set. This is not a class leader. We must
474 // indirect.
475 itemU32 = self.heads[itemU32 as usize];
476 }
477 // Now `itemU32` must point at a class leader.
478 assert!((self.heads[itemU32 as usize] & 0x8000_0000) == 0x8000_0000);
479 let next = self.heads[itemU32 as usize] & 0x7FFF_FFFF;
480 // Now `next` points at the first element in the list.
481 UnionFindEquivClassElemsIter { ufec: &self, next }
482 }
483 }
484
485 impl<'a, T: ToFromU32> Iterator for UnionFindEquivClassElemsIter<'a, T> {
486 type Item = T;
next(&mut self) -> Option<Self::Item>487 fn next(&mut self) -> Option<Self::Item> {
488 if self.next == UFEC_NULL {
489 None
490 } else {
491 let res: T = ToFromU32::from_u32(self.ufec.lists[self.next as usize].elem);
492 self.next = self.ufec.lists[self.next as usize].tail;
493 Some(res)
494 }
495 }
496 }
497
498 // In order to visit all equivalence classes exactly once, we need something
499 // else: a way to enumerate their leaders (some value arbitrarily drawn from
500 // each one). This provides that.
501
502 pub struct UnionFindEquivClassLeadersIter<'a, T: ToFromU32> {
503 // The equivalence classes
504 /*priv*/
505 ufec: &'a UnionFindEquivClasses<T>,
506 // Index into `ufec.heads` of the next unvisited item.
507 /*priv*/
508 next: u32,
509 }
510
511 impl<T: ToFromU32> UnionFindEquivClasses<T> {
equiv_class_leaders_iter<'a>(&'a self) -> UnionFindEquivClassLeadersIter<'a, T>512 pub fn equiv_class_leaders_iter<'a>(&'a self) -> UnionFindEquivClassLeadersIter<'a, T> {
513 UnionFindEquivClassLeadersIter {
514 ufec: &self,
515 next: 0,
516 }
517 }
518 }
519
520 impl<'a, T: ToFromU32> Iterator for UnionFindEquivClassLeadersIter<'a, T> {
521 type Item = T;
next(&mut self) -> Option<Self::Item>522 fn next(&mut self) -> Option<Self::Item> {
523 // Scan forwards through `ufec.heads` to find the next unvisited one which
524 // is a leader (a tree root).
525 loop {
526 if self.next as usize >= self.ufec.heads.len() {
527 return None;
528 }
529 if (self.ufec.heads[self.next as usize] & 0x8000_0000) == 0x8000_0000 {
530 // This is a leader.
531 let res = ToFromU32::from_u32(self.next);
532 self.next += 1;
533 return Some(res);
534 }
535 // No luck, keep one searching.
536 self.next += 1;
537 }
538 /*NOTREACHED*/
539 }
540 }
541
542 //=============================================================================
543 // Testing machinery for UnionFind
544
545 #[cfg(test)]
546 mod union_find_test_utils {
547 use super::UnionFindEquivClasses;
548 // Test that the eclass for `elem` is `expected` (modulo ordering).
test_eclass(eclasses: &UnionFindEquivClasses<u32>, elem: u32, expected: &Vec<u32>)549 pub fn test_eclass(eclasses: &UnionFindEquivClasses<u32>, elem: u32, expected: &Vec<u32>) {
550 let mut expected_sorted = expected.clone();
551 let mut actual = vec![];
552 for ecm in eclasses.equiv_class_elems_iter(elem) {
553 actual.push(ecm);
554 }
555 expected_sorted.sort();
556 actual.sort();
557 assert!(actual == expected_sorted);
558 }
559 // Test that the eclass leaders are exactly `expected`.
test_leaders( univ_size: u32, eclasses: &UnionFindEquivClasses<u32>, expected: &Vec<u32>, )560 pub fn test_leaders(
561 univ_size: u32,
562 eclasses: &UnionFindEquivClasses<u32>,
563 expected: &Vec<u32>,
564 ) {
565 let mut actual = vec![];
566 for leader in eclasses.equiv_class_leaders_iter() {
567 actual.push(leader);
568 }
569 assert!(actual == *expected);
570 // Now use the headers to enumerate each eclass exactly once, and collect
571 // up the elements. The resulting vector should be some permutation of
572 // [0 .. univ_size-1].
573 let mut univ_actual = vec![];
574 for leader in eclasses.equiv_class_leaders_iter() {
575 for elem in eclasses.equiv_class_elems_iter(leader) {
576 univ_actual.push(elem);
577 }
578 }
579 univ_actual.sort();
580 let mut univ_expected = vec![];
581 for i in 0..univ_size {
582 univ_expected.push(i);
583 }
584 assert!(univ_actual == univ_expected);
585 }
586 // Test that `in_same_equivalence_class` produces the expected results.
test_in_same_eclass( eclasses: &UnionFindEquivClasses<u32>, elem1: u32, elem2: u32, expected: Option<bool>, )587 pub fn test_in_same_eclass(
588 eclasses: &UnionFindEquivClasses<u32>,
589 elem1: u32,
590 elem2: u32,
591 expected: Option<bool>,
592 ) {
593 assert!(eclasses.in_same_equivalence_class(elem1, elem2) == expected);
594 assert!(eclasses.in_same_equivalence_class(elem2, elem1) == expected);
595 }
596 }
597
598 #[test]
test_union_find()599 fn test_union_find() {
600 const UNIV_SIZE: u32 = 8;
601 let mut uf = UnionFind::new(UNIV_SIZE as usize);
602 let mut uf_eclasses = uf.get_equiv_classes();
603 union_find_test_utils::test_eclass(&uf_eclasses, 0, &vec![0]);
604 union_find_test_utils::test_eclass(&uf_eclasses, 1, &vec![1]);
605 union_find_test_utils::test_eclass(&uf_eclasses, 2, &vec![2]);
606 union_find_test_utils::test_eclass(&uf_eclasses, 3, &vec![3]);
607 union_find_test_utils::test_eclass(&uf_eclasses, 4, &vec![4]);
608 union_find_test_utils::test_eclass(&uf_eclasses, 5, &vec![5]);
609 union_find_test_utils::test_eclass(&uf_eclasses, 6, &vec![6]);
610 union_find_test_utils::test_eclass(&uf_eclasses, 7, &vec![7]);
611 union_find_test_utils::test_leaders(UNIV_SIZE, &uf_eclasses, &vec![0, 1, 2, 3, 4, 5, 6, 7]);
612
613 uf.union(2, 4);
614 uf_eclasses = uf.get_equiv_classes();
615 union_find_test_utils::test_eclass(&uf_eclasses, 0, &vec![0]);
616 union_find_test_utils::test_eclass(&uf_eclasses, 1, &vec![1]);
617 union_find_test_utils::test_eclass(&uf_eclasses, 2, &vec![4, 2]);
618 union_find_test_utils::test_eclass(&uf_eclasses, 3, &vec![3]);
619 union_find_test_utils::test_eclass(&uf_eclasses, 4, &vec![4, 2]);
620 union_find_test_utils::test_eclass(&uf_eclasses, 5, &vec![5]);
621 union_find_test_utils::test_eclass(&uf_eclasses, 6, &vec![6]);
622 union_find_test_utils::test_eclass(&uf_eclasses, 7, &vec![7]);
623 union_find_test_utils::test_leaders(UNIV_SIZE, &uf_eclasses, &vec![0, 1, 2, 3, 5, 6, 7]);
624
625 uf.union(5, 3);
626 uf_eclasses = uf.get_equiv_classes();
627 union_find_test_utils::test_eclass(&uf_eclasses, 0, &vec![0]);
628 union_find_test_utils::test_eclass(&uf_eclasses, 1, &vec![1]);
629 union_find_test_utils::test_eclass(&uf_eclasses, 2, &vec![4, 2]);
630 union_find_test_utils::test_eclass(&uf_eclasses, 3, &vec![5, 3]);
631 union_find_test_utils::test_eclass(&uf_eclasses, 4, &vec![4, 2]);
632 union_find_test_utils::test_eclass(&uf_eclasses, 5, &vec![5, 3]);
633 union_find_test_utils::test_eclass(&uf_eclasses, 6, &vec![6]);
634 union_find_test_utils::test_eclass(&uf_eclasses, 7, &vec![7]);
635 union_find_test_utils::test_leaders(UNIV_SIZE, &uf_eclasses, &vec![0, 1, 2, 5, 6, 7]);
636
637 uf.union(2, 5);
638 uf_eclasses = uf.get_equiv_classes();
639 union_find_test_utils::test_eclass(&uf_eclasses, 0, &vec![0]);
640 union_find_test_utils::test_eclass(&uf_eclasses, 1, &vec![1]);
641 union_find_test_utils::test_eclass(&uf_eclasses, 2, &vec![5, 4, 3, 2]);
642 union_find_test_utils::test_eclass(&uf_eclasses, 3, &vec![5, 4, 3, 2]);
643 union_find_test_utils::test_eclass(&uf_eclasses, 4, &vec![5, 4, 3, 2]);
644 union_find_test_utils::test_eclass(&uf_eclasses, 5, &vec![5, 4, 3, 2]);
645 union_find_test_utils::test_eclass(&uf_eclasses, 6, &vec![6]);
646 union_find_test_utils::test_eclass(&uf_eclasses, 7, &vec![7]);
647 union_find_test_utils::test_leaders(UNIV_SIZE, &uf_eclasses, &vec![0, 1, 2, 6, 7]);
648 // At this point, also check the "in same equivalence class?" function.
649 union_find_test_utils::test_in_same_eclass(&uf_eclasses, 0, 0, Some(true));
650 union_find_test_utils::test_in_same_eclass(&uf_eclasses, 0, 1, Some(false));
651 union_find_test_utils::test_in_same_eclass(&uf_eclasses, 0, 2, Some(false));
652 union_find_test_utils::test_in_same_eclass(&uf_eclasses, 0, 3, Some(false));
653 union_find_test_utils::test_in_same_eclass(&uf_eclasses, 0, 4, Some(false));
654 union_find_test_utils::test_in_same_eclass(&uf_eclasses, 0, 5, Some(false));
655 union_find_test_utils::test_in_same_eclass(&uf_eclasses, 0, 6, Some(false));
656 union_find_test_utils::test_in_same_eclass(&uf_eclasses, 0, 7, Some(false));
657 union_find_test_utils::test_in_same_eclass(&uf_eclasses, 1, 1, Some(true));
658 union_find_test_utils::test_in_same_eclass(&uf_eclasses, 1, 2, Some(false));
659 union_find_test_utils::test_in_same_eclass(&uf_eclasses, 1, 3, Some(false));
660 union_find_test_utils::test_in_same_eclass(&uf_eclasses, 1, 4, Some(false));
661 union_find_test_utils::test_in_same_eclass(&uf_eclasses, 1, 5, Some(false));
662 union_find_test_utils::test_in_same_eclass(&uf_eclasses, 1, 6, Some(false));
663 union_find_test_utils::test_in_same_eclass(&uf_eclasses, 1, 7, Some(false));
664 union_find_test_utils::test_in_same_eclass(&uf_eclasses, 2, 2, Some(true));
665 union_find_test_utils::test_in_same_eclass(&uf_eclasses, 2, 3, Some(true));
666 union_find_test_utils::test_in_same_eclass(&uf_eclasses, 2, 4, Some(true));
667 union_find_test_utils::test_in_same_eclass(&uf_eclasses, 2, 5, Some(true));
668 union_find_test_utils::test_in_same_eclass(&uf_eclasses, 2, 6, Some(false));
669 union_find_test_utils::test_in_same_eclass(&uf_eclasses, 2, 7, Some(false));
670 union_find_test_utils::test_in_same_eclass(&uf_eclasses, 3, 3, Some(true));
671 union_find_test_utils::test_in_same_eclass(&uf_eclasses, 3, 4, Some(true));
672 union_find_test_utils::test_in_same_eclass(&uf_eclasses, 3, 5, Some(true));
673 union_find_test_utils::test_in_same_eclass(&uf_eclasses, 3, 6, Some(false));
674 union_find_test_utils::test_in_same_eclass(&uf_eclasses, 3, 7, Some(false));
675 union_find_test_utils::test_in_same_eclass(&uf_eclasses, 4, 4, Some(true));
676 union_find_test_utils::test_in_same_eclass(&uf_eclasses, 4, 5, Some(true));
677 union_find_test_utils::test_in_same_eclass(&uf_eclasses, 4, 6, Some(false));
678 union_find_test_utils::test_in_same_eclass(&uf_eclasses, 4, 7, Some(false));
679 union_find_test_utils::test_in_same_eclass(&uf_eclasses, 5, 5, Some(true));
680 union_find_test_utils::test_in_same_eclass(&uf_eclasses, 5, 6, Some(false));
681 union_find_test_utils::test_in_same_eclass(&uf_eclasses, 5, 7, Some(false));
682 union_find_test_utils::test_in_same_eclass(&uf_eclasses, 6, 6, Some(true));
683 union_find_test_utils::test_in_same_eclass(&uf_eclasses, 6, 7, Some(false));
684 union_find_test_utils::test_in_same_eclass(&uf_eclasses, 7, 7, Some(true));
685 union_find_test_utils::test_in_same_eclass(&uf_eclasses, 0, 8, None);
686 union_find_test_utils::test_in_same_eclass(&uf_eclasses, 8, 0, None);
687 union_find_test_utils::test_in_same_eclass(&uf_eclasses, 8, 8, None);
688
689 uf.union(7, 1);
690 uf_eclasses = uf.get_equiv_classes();
691 union_find_test_utils::test_eclass(&uf_eclasses, 0, &vec![0]);
692 union_find_test_utils::test_eclass(&uf_eclasses, 1, &vec![7, 1]);
693 union_find_test_utils::test_eclass(&uf_eclasses, 2, &vec![5, 4, 3, 2]);
694 union_find_test_utils::test_eclass(&uf_eclasses, 3, &vec![5, 4, 3, 2]);
695 union_find_test_utils::test_eclass(&uf_eclasses, 4, &vec![5, 4, 3, 2]);
696 union_find_test_utils::test_eclass(&uf_eclasses, 5, &vec![5, 4, 3, 2]);
697 union_find_test_utils::test_eclass(&uf_eclasses, 6, &vec![6]);
698 union_find_test_utils::test_eclass(&uf_eclasses, 7, &vec![7, 1]);
699 union_find_test_utils::test_leaders(UNIV_SIZE, &uf_eclasses, &vec![0, 2, 6, 7]);
700
701 uf.union(6, 7);
702 uf_eclasses = uf.get_equiv_classes();
703 union_find_test_utils::test_eclass(&uf_eclasses, 0, &vec![0]);
704 union_find_test_utils::test_eclass(&uf_eclasses, 1, &vec![7, 6, 1]);
705 union_find_test_utils::test_eclass(&uf_eclasses, 2, &vec![5, 4, 3, 2]);
706 union_find_test_utils::test_eclass(&uf_eclasses, 3, &vec![5, 4, 3, 2]);
707 union_find_test_utils::test_eclass(&uf_eclasses, 4, &vec![5, 4, 3, 2]);
708 union_find_test_utils::test_eclass(&uf_eclasses, 5, &vec![5, 4, 3, 2]);
709 union_find_test_utils::test_eclass(&uf_eclasses, 6, &vec![7, 6, 1]);
710 union_find_test_utils::test_eclass(&uf_eclasses, 7, &vec![7, 6, 1]);
711 union_find_test_utils::test_leaders(UNIV_SIZE, &uf_eclasses, &vec![0, 2, 6]);
712
713 uf.union(4, 1);
714 uf_eclasses = uf.get_equiv_classes();
715 union_find_test_utils::test_eclass(&uf_eclasses, 0, &vec![0]);
716 union_find_test_utils::test_eclass(&uf_eclasses, 1, &vec![7, 6, 5, 4, 3, 2, 1]);
717 union_find_test_utils::test_eclass(&uf_eclasses, 2, &vec![7, 6, 5, 4, 3, 2, 1]);
718 union_find_test_utils::test_eclass(&uf_eclasses, 3, &vec![7, 6, 5, 4, 3, 2, 1]);
719 union_find_test_utils::test_eclass(&uf_eclasses, 4, &vec![7, 6, 5, 4, 3, 2, 1]);
720 union_find_test_utils::test_eclass(&uf_eclasses, 5, &vec![7, 6, 5, 4, 3, 2, 1]);
721 union_find_test_utils::test_eclass(&uf_eclasses, 6, &vec![7, 6, 5, 4, 3, 2, 1]);
722 union_find_test_utils::test_eclass(&uf_eclasses, 7, &vec![7, 6, 5, 4, 3, 2, 1]);
723 union_find_test_utils::test_leaders(UNIV_SIZE, &uf_eclasses, &vec![0, 6]);
724
725 uf.union(0, 3);
726 uf_eclasses = uf.get_equiv_classes();
727 union_find_test_utils::test_eclass(&uf_eclasses, 0, &vec![7, 6, 5, 4, 3, 2, 1, 0]);
728 union_find_test_utils::test_eclass(&uf_eclasses, 1, &vec![7, 6, 5, 4, 3, 2, 1, 0]);
729 union_find_test_utils::test_eclass(&uf_eclasses, 2, &vec![7, 6, 5, 4, 3, 2, 1, 0]);
730 union_find_test_utils::test_eclass(&uf_eclasses, 3, &vec![7, 6, 5, 4, 3, 2, 1, 0]);
731 union_find_test_utils::test_eclass(&uf_eclasses, 4, &vec![7, 6, 5, 4, 3, 2, 1, 0]);
732 union_find_test_utils::test_eclass(&uf_eclasses, 5, &vec![7, 6, 5, 4, 3, 2, 1, 0]);
733 union_find_test_utils::test_eclass(&uf_eclasses, 6, &vec![7, 6, 5, 4, 3, 2, 1, 0]);
734 union_find_test_utils::test_eclass(&uf_eclasses, 7, &vec![7, 6, 5, 4, 3, 2, 1, 0]);
735 union_find_test_utils::test_leaders(UNIV_SIZE, &uf_eclasses, &vec![0]);
736
737 // Pointless, because the classes are already maximal.
738 uf.union(1, 2);
739 uf_eclasses = uf.get_equiv_classes();
740 union_find_test_utils::test_eclass(&uf_eclasses, 0, &vec![7, 6, 5, 4, 3, 2, 1, 0]);
741 union_find_test_utils::test_eclass(&uf_eclasses, 1, &vec![7, 6, 5, 4, 3, 2, 1, 0]);
742 union_find_test_utils::test_eclass(&uf_eclasses, 2, &vec![7, 6, 5, 4, 3, 2, 1, 0]);
743 union_find_test_utils::test_eclass(&uf_eclasses, 3, &vec![7, 6, 5, 4, 3, 2, 1, 0]);
744 union_find_test_utils::test_eclass(&uf_eclasses, 4, &vec![7, 6, 5, 4, 3, 2, 1, 0]);
745 union_find_test_utils::test_eclass(&uf_eclasses, 5, &vec![7, 6, 5, 4, 3, 2, 1, 0]);
746 union_find_test_utils::test_eclass(&uf_eclasses, 6, &vec![7, 6, 5, 4, 3, 2, 1, 0]);
747 union_find_test_utils::test_eclass(&uf_eclasses, 7, &vec![7, 6, 5, 4, 3, 2, 1, 0]);
748 union_find_test_utils::test_leaders(UNIV_SIZE, &uf_eclasses, &vec![0]);
749 }
750