ruvector_mincut/connectivity/
polylog.rs1use crate::graph::VertexId;
25use std::collections::{HashMap, HashSet, VecDeque};
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] = self.level_sizes[old_level].saturating_sub(1);
345 self.level_sizes[level] += 1;
346
347 for ll in old_level..=level {
349 self.levels[ll].non_tree_edges.remove(&rep_edge);
350 self.levels[ll].tree_edges.insert(rep_edge);
351 }
352 }
353 } else {
354 self.component_count += 1;
356 }
357 }
358 }
359
360 self.rebuild_level(level);
362 }
363
364 pub fn connected(&mut self, u: VertexId, v: VertexId) -> bool {
368 self.stats.queries += 1;
369
370 self.levels[0].connected(u, v)
372 }
373
374 pub fn is_connected(&self) -> bool {
376 self.component_count <= 1
377 }
378
379 pub fn component_count(&self) -> usize {
381 self.component_count
382 }
383
384 pub fn vertex_count(&self) -> usize {
386 self.vertex_count
387 }
388
389 pub fn edge_count(&self) -> usize {
391 self.edges.len()
392 }
393
394 pub fn stats(&self) -> &PolylogStats {
396 &self.stats
397 }
398
399 fn find_replacement(
402 &mut self,
403 u: VertexId,
404 v: VertexId,
405 level: usize,
406 ) -> Option<(VertexId, VertexId)> {
407 let size_u = self.levels[level].get_component_size(u);
409 let size_v = self.levels[level].get_component_size(v);
410 let (start, _target) = if size_u <= size_v { (u, v) } else { (v, u) };
411
412 let mut visited = HashSet::with_capacity(size_u.min(size_v).min(1000));
414 let mut queue = VecDeque::with_capacity(64);
415
416 queue.push_back(start);
418 visited.insert(start);
419
420 let max_search = (self.vertex_count / 2).max(100);
422
423 while let Some(current) = queue.pop_front() {
424 let non_tree_edges: Vec<_> = self.levels[level]
426 .non_tree_edges
427 .iter()
428 .filter(|&&(a, b)| a == current || b == current)
429 .copied()
430 .collect();
431
432 for (a, b) in non_tree_edges {
433 let other = if a == current { b } else { a };
434
435 if !visited.contains(&other) {
437 return Some((a, b));
438 }
439 }
440
441 let neighbors: Vec<_> = self.levels[level].neighbors(current).to_vec();
443 for neighbor in neighbors {
444 if !visited.contains(&neighbor) {
445 visited.insert(neighbor);
446 queue.push_back(neighbor);
447 }
448 }
449
450 if visited.len() >= max_search {
452 break;
453 }
454 }
455
456 None
457 }
458
459 fn check_rebuild(&mut self, level: usize) {
461 if self.initial_sizes[level] == 0 {
462 self.initial_sizes[level] = self.level_sizes[level].max(1);
463 return;
464 }
465
466 let threshold = (self.initial_sizes[level] as f64 * REBUILD_FACTOR) as usize;
467 if self.level_sizes[level] > threshold {
468 self.rebuild_level(level);
469 }
470 }
471
472 fn rebuild_level(&mut self, level: usize) {
474 self.stats.rebuilds += 1;
475 self.stats.max_level = self.stats.max_level.max(level);
476
477 let edges_to_rebuild: Vec<_> = self
479 .edges
480 .iter()
481 .filter(|(_, &l)| l >= level)
482 .map(|(&e, &l)| (e, l))
483 .collect();
484
485 self.levels[level] = LevelForest::new();
487 self.level_sizes[level] = 0;
488
489 for ((u, v), _) in edges_to_rebuild {
491 self.levels[level].insert_edge(u, v);
492 self.level_sizes[level] += 1;
493 }
494
495 self.initial_sizes[level] = self.level_sizes[level].max(1);
497 }
498}
499
500impl Default for PolylogConnectivity {
501 fn default() -> Self {
502 Self::new()
503 }
504}
505
506#[cfg(test)]
507mod tests {
508 use super::*;
509
510 #[test]
511 fn test_basic_connectivity() {
512 let mut conn = PolylogConnectivity::new();
513
514 conn.insert_edge(0, 1);
515 conn.insert_edge(1, 2);
516
517 assert!(conn.connected(0, 1));
518 assert!(conn.connected(0, 2));
519 assert!(conn.connected(1, 2));
520 assert!(!conn.connected(0, 3));
521 }
522
523 #[test]
524 fn test_delete_edge() {
525 let mut conn = PolylogConnectivity::new();
526
527 conn.insert_edge(0, 1);
528 conn.insert_edge(1, 2);
529 conn.insert_edge(2, 3);
530
531 assert!(conn.connected(0, 3));
532
533 conn.delete_edge(1, 2);
534
535 assert!(conn.connected(0, 1));
536 assert!(conn.connected(2, 3));
537 assert!(!conn.connected(0, 2));
538 }
539
540 #[test]
541 fn test_component_count() {
542 let mut conn = PolylogConnectivity::new();
543
544 conn.insert_edge(0, 1);
545 assert_eq!(conn.component_count(), 1);
546
547 conn.insert_edge(2, 3);
548 assert_eq!(conn.component_count(), 2);
549
550 conn.insert_edge(1, 2);
551 assert_eq!(conn.component_count(), 1);
552
553 conn.delete_edge(1, 2);
554 assert_eq!(conn.component_count(), 2);
555 }
556
557 #[test]
558 fn test_replacement_edge() {
559 let mut conn = PolylogConnectivity::new();
560
561 conn.insert_edge(0, 1);
563 conn.insert_edge(1, 2);
564 conn.insert_edge(2, 3);
565 conn.insert_edge(3, 0);
566
567 assert_eq!(conn.component_count(), 1);
568
569 conn.delete_edge(1, 2);
571
572 assert!(conn.connected(0, 2));
574 assert_eq!(conn.component_count(), 1);
575 }
576
577 #[test]
578 fn test_stats() {
579 let mut conn = PolylogConnectivity::new();
580
581 conn.insert_edge(0, 1);
582 conn.insert_edge(1, 2);
583 conn.delete_edge(0, 1);
584 conn.connected(1, 2);
585
586 let stats = conn.stats();
587 assert_eq!(stats.insertions, 2);
588 assert_eq!(stats.deletions, 1);
589 assert_eq!(stats.queries, 1);
590 }
591}