1use std::usize;
2
3use crate::dendrogram::Dendrogram;
4use crate::Method;
5
6#[derive(Clone, Debug)]
15pub struct LinkageUnionFind {
16 parents: Vec<usize>,
21 next_parent: usize,
23}
24
25impl Default for LinkageUnionFind {
26 fn default() -> LinkageUnionFind {
27 LinkageUnionFind::new()
28 }
29}
30
31impl LinkageUnionFind {
32 pub fn new() -> LinkageUnionFind {
34 LinkageUnionFind::with_len(0)
35 }
36
37 pub fn with_len(len: usize) -> LinkageUnionFind {
40 let size = if len == 0 { 0 } else { 2 * len - 1 };
41 LinkageUnionFind { parents: (0..size).collect(), next_parent: len }
42 }
43
44 pub fn reset(&mut self, len: usize) {
47 let size = if len == 0 { 0 } else { 2 * len - 1 };
48 self.next_parent = len;
49 self.parents.resize(size, 0);
50 for (i, parent) in self.parents.iter_mut().enumerate() {
51 *parent = i;
52 }
53 }
54
55 pub fn union(&mut self, cluster1: usize, cluster2: usize) {
59 if self.find(cluster1) == self.find(cluster2) {
62 return;
63 }
64
65 assert!(self.next_parent < self.parents.len());
66 self.parents[cluster1] = self.next_parent;
67 self.parents[cluster2] = self.next_parent;
68 self.next_parent = self.next_parent + 1;
69 }
70
71 pub fn find(&mut self, mut cluster: usize) -> usize {
73 let mut parent = cluster;
77 while let Some(p) = self.parent(parent) {
78 parent = p;
79 }
80 while let Some(p) = self.parent(cluster) {
84 self.parents[cluster] = parent;
85 cluster = p;
86 }
87 parent
88 }
89
90 fn parent(&self, cluster: usize) -> Option<usize> {
93 let p = self.parents[cluster];
94 if p == cluster {
95 None
96 } else {
97 Some(p)
98 }
99 }
100
101 pub fn relabel<T: PartialOrd>(
106 &mut self,
107 dendrogram: &mut Dendrogram<T>,
108 method: Method,
109 ) {
110 self.reset(dendrogram.observations());
111 if method.requires_sorting() {
112 dendrogram.steps_mut().sort_by(|step1, step2| {
113 step1
127 .dissimilarity
128 .partial_cmp(&step2.dissimilarity)
129 .expect("NaNs not allowed in dendrogram")
130 });
131 }
132 for i in 0..dendrogram.len() {
133 let new_cluster1 = self.find(dendrogram[i].cluster1);
134 let new_cluster2 = self.find(dendrogram[i].cluster2);
135 self.union(new_cluster1, new_cluster2);
136
137 let size1 = dendrogram.cluster_size(new_cluster1);
138 let size2 = dendrogram.cluster_size(new_cluster2);
139 dendrogram[i].set_clusters(new_cluster1, new_cluster2);
140 dendrogram[i].size = size1 + size2;
141 }
142 }
143}
144
145#[cfg(test)]
146mod tests {
147 use super::LinkageUnionFind;
148 use crate::dendrogram::{Dendrogram, Step};
149 use crate::Method;
150
151 #[test]
152 fn trivial_find() {
153 let mut set = LinkageUnionFind::with_len(5);
154 for i in 0..5 {
156 assert_eq!(i, set.find(i));
157 }
158 }
159
160 #[test]
161 fn find_with_unions() {
162 let mut set = LinkageUnionFind::with_len(5);
163
164 set.union(1, 3);
165 assert_eq!(0, set.find(0));
166 assert_eq!(5, set.find(1));
167 assert_eq!(2, set.find(2));
168 assert_eq!(5, set.find(3));
169 assert_eq!(4, set.find(4));
170 assert_eq!(5, set.find(5));
171
172 set.union(5, 2);
173 assert_eq!(0, set.find(0));
174 assert_eq!(6, set.find(1));
175 assert_eq!(6, set.find(2));
176 assert_eq!(6, set.find(3));
177 assert_eq!(4, set.find(4));
178 assert_eq!(6, set.find(5));
179 assert_eq!(6, set.find(6));
180
181 set.union(0, 4);
182 assert_eq!(7, set.find(0));
183 assert_eq!(6, set.find(1));
184 assert_eq!(6, set.find(2));
185 assert_eq!(6, set.find(3));
186 assert_eq!(7, set.find(4));
187 assert_eq!(6, set.find(5));
188 assert_eq!(6, set.find(6));
189 assert_eq!(7, set.find(7));
190
191 set.union(6, 7);
192 assert_eq!(8, set.find(0));
193 assert_eq!(8, set.find(1));
194 assert_eq!(8, set.find(2));
195 assert_eq!(8, set.find(3));
196 assert_eq!(8, set.find(4));
197 assert_eq!(8, set.find(5));
198 assert_eq!(8, set.find(6));
199 assert_eq!(8, set.find(7));
200 }
201
202 #[test]
203 fn find_with_unions_all_at_once() {
204 let mut set = LinkageUnionFind::with_len(5);
205
206 set.union(1, 3);
207 set.union(5, 2);
208 set.union(0, 4);
209 set.union(6, 7);
210
211 assert_eq!(8, set.find(0));
213 assert_eq!(8, set.find(1));
214 assert_eq!(8, set.find(2));
215 assert_eq!(8, set.find(3));
216 assert_eq!(8, set.find(4));
217 assert_eq!(8, set.find(5));
218 assert_eq!(8, set.find(6));
219 assert_eq!(8, set.find(7));
220 }
221
222 #[test]
223 fn union_is_idempotent() {
224 let mut set = LinkageUnionFind::with_len(5);
225
226 set.union(1, 3);
227 set.union(5, 2);
228 set.union(5, 1);
230 set.union(0, 4);
231 set.union(6, 7);
232
233 assert_eq!(8, set.find(0));
235 assert_eq!(8, set.find(1));
236 assert_eq!(8, set.find(2));
237 assert_eq!(8, set.find(3));
238 assert_eq!(8, set.find(4));
239 assert_eq!(8, set.find(5));
240 assert_eq!(8, set.find(6));
241 assert_eq!(8, set.find(7));
242
243 set.union(1, 4);
245 assert_eq!(8, set.find(0));
246 assert_eq!(8, set.find(1));
247 assert_eq!(8, set.find(2));
248 assert_eq!(8, set.find(3));
249 assert_eq!(8, set.find(4));
250 assert_eq!(8, set.find(5));
251 assert_eq!(8, set.find(6));
252 assert_eq!(8, set.find(7));
253 }
254
255 #[test]
256 fn relabel() {
257 let mut den = Dendrogram::new(5);
258 den.push(Step::new(1, 3, 0.01, 0));
259 den.push(Step::new(1, 2, 0.02, 0));
260 den.push(Step::new(0, 4, 0.015, 0));
261 den.push(Step::new(1, 4, 0.03, 0));
262
263 let mut set = LinkageUnionFind::new();
264 set.relabel(&mut den, Method::Single);
265
266 assert_eq!(
267 den.steps(),
268 &[
269 Step::new(1, 3, 0.01, 2),
270 Step::new(0, 4, 0.015, 2),
271 Step::new(2, 5, 0.02, 3),
272 Step::new(6, 7, 0.03, 5),
273 ]
274 );
275 }
276}