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