ruvector_mincut/connectivity/
polylog.rs1use std::collections::{HashMap, HashSet, VecDeque};
25use crate::graph::VertexId;
26
27const MAX_LEVELS: usize = 64;
29
30const REBUILD_FACTOR: f64 = 2.0;
32
33#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
35struct LeveledEdge {
36 u: VertexId,
37 v: VertexId,
38 level: usize,
39}
40
41impl LeveledEdge {
42 fn new(u: VertexId, v: VertexId, level: usize) -> Self {
43 let (u, v) = if u < v { (u, v) } else { (v, u) };
44 Self { u, v, level }
45 }
46
47 fn endpoints(&self) -> (VertexId, VertexId) {
48 (self.u, self.v)
49 }
50}
51
52#[derive(Debug, Clone)]
54struct LevelForest {
55 parent: HashMap<VertexId, VertexId>,
57 rank: HashMap<VertexId, usize>,
59 component_size: HashMap<VertexId, usize>,
61 tree_edges: HashSet<(VertexId, VertexId)>,
63 non_tree_edges: HashSet<(VertexId, VertexId)>,
65 adjacency: HashMap<VertexId, Vec<VertexId>>,
67 size: usize,
69}
70
71impl LevelForest {
72 fn new() -> Self {
73 Self {
74 parent: HashMap::new(),
75 rank: HashMap::new(),
76 component_size: HashMap::new(),
77 tree_edges: HashSet::new(),
78 non_tree_edges: HashSet::new(),
79 adjacency: HashMap::new(),
80 size: 0,
81 }
82 }
83
84 #[inline]
85 fn add_vertex(&mut self, v: VertexId) {
86 if !self.parent.contains_key(&v) {
87 self.parent.insert(v, v);
88 self.rank.insert(v, 0);
89 self.component_size.insert(v, 1);
90 self.adjacency.insert(v, Vec::new());
91 self.size += 1;
92 }
93 }
94
95 #[inline]
96 fn find(&mut self, v: VertexId) -> VertexId {
97 if !self.parent.contains_key(&v) {
98 return v;
99 }
100
101 let p = self.parent[&v];
102 if p == v {
103 return v;
104 }
105
106 let mut path = Vec::with_capacity(8);
108 let mut current = v;
109 while self.parent[¤t] != current {
110 path.push(current);
111 current = self.parent[¤t];
112 }
113 let root = current;
114
115 for node in path {
117 self.parent.insert(node, root);
118 }
119 root
120 }
121
122 #[inline]
123 fn union(&mut self, u: VertexId, v: VertexId) -> bool {
124 let root_u = self.find(u);
125 let root_v = self.find(v);
126
127 if root_u == root_v {
128 return false;
129 }
130
131 let size_u = *self.component_size.get(&root_u).unwrap_or(&1);
133 let size_v = *self.component_size.get(&root_v).unwrap_or(&1);
134
135 if size_u < size_v {
136 self.parent.insert(root_u, root_v);
137 self.component_size.insert(root_v, size_u + size_v);
138 } else {
139 self.parent.insert(root_v, root_u);
140 self.component_size.insert(root_u, size_u + size_v);
141 }
142
143 true
144 }
145
146 #[inline]
147 fn connected(&mut self, u: VertexId, v: VertexId) -> bool {
148 self.find(u) == self.find(v)
149 }
150
151 #[inline]
152 fn insert_edge(&mut self, u: VertexId, v: VertexId) -> bool {
153 self.add_vertex(u);
154 self.add_vertex(v);
155
156 self.adjacency.entry(u).or_default().push(v);
158 self.adjacency.entry(v).or_default().push(u);
159
160 let edge = if u < v { (u, v) } else { (v, u) };
161
162 if self.union(u, v) {
163 self.tree_edges.insert(edge);
165 true
166 } else {
167 self.non_tree_edges.insert(edge);
169 false
170 }
171 }
172
173 fn remove_edge(&mut self, u: VertexId, v: VertexId) -> bool {
174 let edge = if u < v { (u, v) } else { (v, u) };
175
176 if let Some(neighbors) = self.adjacency.get_mut(&u) {
178 neighbors.retain(|&x| x != v);
179 }
180 if let Some(neighbors) = self.adjacency.get_mut(&v) {
181 neighbors.retain(|&x| x != u);
182 }
183
184 if self.tree_edges.remove(&edge) {
185 true
186 } else {
187 self.non_tree_edges.remove(&edge);
188 false
189 }
190 }
191
192 #[inline]
194 fn neighbors(&self, v: VertexId) -> &[VertexId] {
195 self.adjacency.get(&v).map_or(&[], |n| n.as_slice())
196 }
197
198 #[inline]
200 fn get_component_size(&mut self, v: VertexId) -> usize {
201 let root = self.find(v);
202 *self.component_size.get(&root).unwrap_or(&1)
203 }
204}
205
206#[derive(Debug)]
225pub struct PolylogConnectivity {
226 levels: Vec<LevelForest>,
228 edges: HashMap<(VertexId, VertexId), usize>,
230 level_sizes: Vec<usize>,
232 initial_sizes: Vec<usize>,
234 vertex_count: usize,
236 component_count: usize,
238 stats: PolylogStats,
240}
241
242#[derive(Debug, Clone, Default)]
244pub struct PolylogStats {
245 pub insertions: u64,
247 pub deletions: u64,
249 pub queries: u64,
251 pub rebuilds: u64,
253 pub max_level: usize,
255}
256
257impl PolylogConnectivity {
258 pub fn new() -> Self {
260 Self {
261 levels: (0..MAX_LEVELS).map(|_| LevelForest::new()).collect(),
262 edges: HashMap::new(),
263 level_sizes: vec![0; MAX_LEVELS],
264 initial_sizes: vec![0; MAX_LEVELS],
265 vertex_count: 0,
266 component_count: 0,
267 stats: PolylogStats::default(),
268 }
269 }
270
271 pub fn insert_edge(&mut self, u: VertexId, v: VertexId) {
275 self.stats.insertions += 1;
276
277 let edge = if u < v { (u, v) } else { (v, u) };
278
279 if self.edges.contains_key(&edge) {
280 return; }
282
283 let u_new = !self.levels[0].parent.contains_key(&u);
285 let v_new = !self.levels[0].parent.contains_key(&v);
286
287 if u_new {
288 self.vertex_count += 1;
289 self.component_count += 1;
290 }
291 if v_new {
292 self.vertex_count += 1;
293 self.component_count += 1;
294 }
295
296 let is_tree_edge = self.levels[0].insert_edge(u, v);
298 self.edges.insert(edge, 0);
299 self.level_sizes[0] += 1;
300
301 if is_tree_edge {
302 self.component_count -= 1;
304 }
305
306 self.check_rebuild(0);
308 }
309
310 pub fn delete_edge(&mut self, u: VertexId, v: VertexId) {
314 self.stats.deletions += 1;
315
316 let edge = if u < v { (u, v) } else { (v, u) };
317
318 let level = match self.edges.remove(&edge) {
319 Some(l) => l,
320 None => return, };
322
323 self.level_sizes[level] = self.level_sizes[level].saturating_sub(1);
324
325 for l in 0..=level {
327 let was_tree = self.levels[l].remove_edge(u, v);
328
329 if was_tree && l == level {
330 if let Some(replacement) = self.find_replacement(u, v, level) {
332 let rep_edge = if replacement.0 < replacement.1 {
334 (replacement.0, replacement.1)
335 } else {
336 (replacement.1, replacement.0)
337 };
338
339 if let Some(rep_level) = self.edges.get_mut(&rep_edge) {
340 let old_level = *rep_level;
341 *rep_level = level;
342
343 self.level_sizes[old_level] =
345 self.level_sizes[old_level].saturating_sub(1);
346 self.level_sizes[level] += 1;
347
348 for ll in old_level..=level {
350 self.levels[ll].non_tree_edges.remove(&rep_edge);
351 self.levels[ll].tree_edges.insert(rep_edge);
352 }
353 }
354 } else {
355 self.component_count += 1;
357 }
358 }
359 }
360
361 self.rebuild_level(level);
363 }
364
365 pub fn connected(&mut self, u: VertexId, v: VertexId) -> bool {
369 self.stats.queries += 1;
370
371 self.levels[0].connected(u, v)
373 }
374
375 pub fn is_connected(&self) -> bool {
377 self.component_count <= 1
378 }
379
380 pub fn component_count(&self) -> usize {
382 self.component_count
383 }
384
385 pub fn vertex_count(&self) -> usize {
387 self.vertex_count
388 }
389
390 pub fn edge_count(&self) -> usize {
392 self.edges.len()
393 }
394
395 pub fn stats(&self) -> &PolylogStats {
397 &self.stats
398 }
399
400 fn find_replacement(&mut self, u: VertexId, v: VertexId, level: usize) -> Option<(VertexId, VertexId)> {
403 let size_u = self.levels[level].get_component_size(u);
405 let size_v = self.levels[level].get_component_size(v);
406 let (start, _target) = if size_u <= size_v { (u, v) } else { (v, u) };
407
408 let mut visited = HashSet::with_capacity(size_u.min(size_v).min(1000));
410 let mut queue = VecDeque::with_capacity(64);
411
412 queue.push_back(start);
414 visited.insert(start);
415
416 let max_search = (self.vertex_count / 2).max(100);
418
419 while let Some(current) = queue.pop_front() {
420 let non_tree_edges: Vec<_> = self.levels[level]
422 .non_tree_edges
423 .iter()
424 .filter(|&&(a, b)| a == current || b == current)
425 .copied()
426 .collect();
427
428 for (a, b) in non_tree_edges {
429 let other = if a == current { b } else { a };
430
431 if !visited.contains(&other) {
433 return Some((a, b));
434 }
435 }
436
437 let neighbors: Vec<_> = self.levels[level].neighbors(current).to_vec();
439 for neighbor in neighbors {
440 if !visited.contains(&neighbor) {
441 visited.insert(neighbor);
442 queue.push_back(neighbor);
443 }
444 }
445
446 if visited.len() >= max_search {
448 break;
449 }
450 }
451
452 None
453 }
454
455 fn check_rebuild(&mut self, level: usize) {
457 if self.initial_sizes[level] == 0 {
458 self.initial_sizes[level] = self.level_sizes[level].max(1);
459 return;
460 }
461
462 let threshold = (self.initial_sizes[level] as f64 * REBUILD_FACTOR) as usize;
463 if self.level_sizes[level] > threshold {
464 self.rebuild_level(level);
465 }
466 }
467
468 fn rebuild_level(&mut self, level: usize) {
470 self.stats.rebuilds += 1;
471 self.stats.max_level = self.stats.max_level.max(level);
472
473 let edges_to_rebuild: Vec<_> = self
475 .edges
476 .iter()
477 .filter(|(_, &l)| l >= level)
478 .map(|(&e, &l)| (e, l))
479 .collect();
480
481 self.levels[level] = LevelForest::new();
483 self.level_sizes[level] = 0;
484
485 for ((u, v), _) in edges_to_rebuild {
487 self.levels[level].insert_edge(u, v);
488 self.level_sizes[level] += 1;
489 }
490
491 self.initial_sizes[level] = self.level_sizes[level].max(1);
493 }
494}
495
496impl Default for PolylogConnectivity {
497 fn default() -> Self {
498 Self::new()
499 }
500}
501
502#[cfg(test)]
503mod tests {
504 use super::*;
505
506 #[test]
507 fn test_basic_connectivity() {
508 let mut conn = PolylogConnectivity::new();
509
510 conn.insert_edge(0, 1);
511 conn.insert_edge(1, 2);
512
513 assert!(conn.connected(0, 1));
514 assert!(conn.connected(0, 2));
515 assert!(conn.connected(1, 2));
516 assert!(!conn.connected(0, 3));
517 }
518
519 #[test]
520 fn test_delete_edge() {
521 let mut conn = PolylogConnectivity::new();
522
523 conn.insert_edge(0, 1);
524 conn.insert_edge(1, 2);
525 conn.insert_edge(2, 3);
526
527 assert!(conn.connected(0, 3));
528
529 conn.delete_edge(1, 2);
530
531 assert!(conn.connected(0, 1));
532 assert!(conn.connected(2, 3));
533 assert!(!conn.connected(0, 2));
534 }
535
536 #[test]
537 fn test_component_count() {
538 let mut conn = PolylogConnectivity::new();
539
540 conn.insert_edge(0, 1);
541 assert_eq!(conn.component_count(), 1);
542
543 conn.insert_edge(2, 3);
544 assert_eq!(conn.component_count(), 2);
545
546 conn.insert_edge(1, 2);
547 assert_eq!(conn.component_count(), 1);
548
549 conn.delete_edge(1, 2);
550 assert_eq!(conn.component_count(), 2);
551 }
552
553 #[test]
554 fn test_replacement_edge() {
555 let mut conn = PolylogConnectivity::new();
556
557 conn.insert_edge(0, 1);
559 conn.insert_edge(1, 2);
560 conn.insert_edge(2, 3);
561 conn.insert_edge(3, 0);
562
563 assert_eq!(conn.component_count(), 1);
564
565 conn.delete_edge(1, 2);
567
568 assert!(conn.connected(0, 2));
570 assert_eq!(conn.component_count(), 1);
571 }
572
573 #[test]
574 fn test_stats() {
575 let mut conn = PolylogConnectivity::new();
576
577 conn.insert_edge(0, 1);
578 conn.insert_edge(1, 2);
579 conn.delete_edge(0, 1);
580 conn.connected(1, 2);
581
582 let stats = conn.stats();
583 assert_eq!(stats.insertions, 2);
584 assert_eq!(stats.deletions, 1);
585 assert_eq!(stats.queries, 1);
586 }
587}