ruvector_mincut/fragment/
mod.rs1use crate::connectivity::DynamicConnectivity;
7use crate::graph::{DynamicGraph, EdgeId, VertexId};
8use crate::instance::WitnessHandle;
9use roaring::RoaringBitmap;
10use std::collections::{HashMap, HashSet, VecDeque};
11use std::sync::Arc;
12
13#[derive(Debug, Clone)]
15pub struct Fragment {
16 pub id: u64,
18 pub vertices: HashSet<VertexId>,
20 pub edges: Vec<EdgeId>,
22 pub min_cut: u64,
24 pub witness: Option<WitnessHandle>,
26}
27
28#[derive(Debug, Clone)]
30pub enum FragmentResult {
31 Connected {
33 min_cut: u64,
35 witness: WitnessHandle,
37 },
38 Disconnected {
40 fragments: Vec<Fragment>,
42 global_min_cut: u64,
44 },
45}
46
47pub struct FragmentingAlgorithm {
49 graph: Arc<DynamicGraph>,
51 fragments: Vec<Fragment>,
53 vertex_fragment: HashMap<VertexId, u64>,
55 next_id: u64,
57 connectivity: DynamicConnectivity,
59}
60
61impl FragmentingAlgorithm {
62 pub fn new(graph: Arc<DynamicGraph>) -> Self {
64 let mut alg = Self {
65 graph,
66 fragments: Vec::new(),
67 vertex_fragment: HashMap::new(),
68 next_id: 0,
69 connectivity: DynamicConnectivity::new(),
70 };
71 alg.rebuild();
72 alg
73 }
74
75 pub fn rebuild(&mut self) {
77 self.fragments.clear();
78 self.vertex_fragment.clear();
79 self.next_id = 0;
80 self.connectivity = DynamicConnectivity::new();
81
82 for edge in self.graph.edges() {
84 self.connectivity.insert_edge(edge.source, edge.target);
85 }
86
87 let components = self.find_connected_components();
89
90 for component in components {
92 self.create_fragment(component);
93 }
94 }
95
96 fn find_connected_components(&self) -> Vec<HashSet<VertexId>> {
98 let mut visited = HashSet::new();
99 let mut components = Vec::new();
100
101 for vertex in self.graph.vertices() {
102 if !visited.contains(&vertex) {
103 let component = self.bfs_component(vertex, &mut visited);
104 if !component.is_empty() {
105 components.push(component);
106 }
107 }
108 }
109
110 components
111 }
112
113 fn bfs_component(&self, start: VertexId, visited: &mut HashSet<VertexId>) -> HashSet<VertexId> {
115 let mut component = HashSet::new();
116 let mut queue = VecDeque::new();
117
118 queue.push_back(start);
119 visited.insert(start);
120 component.insert(start);
121
122 while let Some(current) = queue.pop_front() {
123 for (neighbor, _edge_id) in self.graph.neighbors(current) {
124 if visited.insert(neighbor) {
125 queue.push_back(neighbor);
126 component.insert(neighbor);
127 }
128 }
129 }
130
131 component
132 }
133
134 fn create_fragment(&mut self, vertices: HashSet<VertexId>) {
136 let fragment_id = self.next_id;
137 self.next_id += 1;
138
139 let edges: Vec<EdgeId> = self
141 .graph
142 .edges()
143 .into_iter()
144 .filter(|e| vertices.contains(&e.source) && vertices.contains(&e.target))
145 .map(|e| e.id)
146 .collect();
147
148 let (min_cut, witness) = self.compute_fragment_min_cut(&vertices);
150
151 let fragment = Fragment {
152 id: fragment_id,
153 vertices: vertices.clone(),
154 edges,
155 min_cut,
156 witness,
157 };
158
159 for &v in &vertices {
161 self.vertex_fragment.insert(v, fragment_id);
162 }
163
164 self.fragments.push(fragment);
165 }
166
167 fn compute_fragment_min_cut(
169 &self,
170 vertices: &HashSet<VertexId>,
171 ) -> (u64, Option<WitnessHandle>) {
172 if vertices.len() <= 1 {
173 return (u64::MAX, None);
174 }
175
176 if vertices.len() < 20 {
178 return self.brute_force_min_cut(vertices);
179 }
180
181 self.heuristic_min_cut(vertices)
183 }
184
185 fn brute_force_min_cut(&self, vertices: &HashSet<VertexId>) -> (u64, Option<WitnessHandle>) {
187 let vertex_vec: Vec<_> = vertices.iter().copied().collect();
188 let n = vertex_vec.len();
189
190 if n >= 20 {
191 return (u64::MAX, None);
192 }
193
194 let mut min_cut = u64::MAX;
195 let mut best_set = HashSet::new();
196
197 let max_mask = 1u64 << n;
199 for mask in 1..max_mask - 1 {
200 let mut subset: HashSet<VertexId> = HashSet::new();
201 for (i, &v) in vertex_vec.iter().enumerate() {
202 if mask & (1 << i) != 0 {
203 subset.insert(v);
204 }
205 }
206
207 if !self.is_connected_within(&subset, vertices) {
209 continue;
210 }
211
212 let boundary = self.compute_boundary_within(&subset, vertices);
214
215 if boundary < min_cut {
216 min_cut = boundary;
217 best_set = subset;
218 }
219 }
220
221 if min_cut == u64::MAX || best_set.is_empty() {
222 return (u64::MAX, None);
223 }
224
225 let membership: RoaringBitmap = best_set.iter().map(|&v| v as u32).collect();
227 let seed = *best_set.iter().next().unwrap();
228 let witness = WitnessHandle::new(seed, membership, min_cut);
229
230 (min_cut, Some(witness))
231 }
232
233 fn heuristic_min_cut(&self, vertices: &HashSet<VertexId>) -> (u64, Option<WitnessHandle>) {
235 let mut min_degree = u64::MAX;
237 let mut min_vertex = None;
238
239 for &v in vertices {
240 let degree = self
241 .graph
242 .neighbors(v)
243 .into_iter()
244 .filter(|(n, _)| vertices.contains(n))
245 .count() as u64;
246
247 if degree < min_degree {
248 min_degree = degree;
249 min_vertex = Some(v);
250 }
251 }
252
253 if let Some(v) = min_vertex {
254 let mut membership = RoaringBitmap::new();
255 membership.insert(v as u32);
256 let witness = WitnessHandle::new(v, membership, min_degree);
257 return (min_degree, Some(witness));
258 }
259
260 (u64::MAX, None)
261 }
262
263 fn is_connected_within(
265 &self,
266 subset: &HashSet<VertexId>,
267 fragment: &HashSet<VertexId>,
268 ) -> bool {
269 if subset.is_empty() {
270 return true;
271 }
272
273 let start = *subset.iter().next().unwrap();
274 let mut visited = HashSet::new();
275 let mut queue = VecDeque::new();
276
277 queue.push_back(start);
278 visited.insert(start);
279
280 while let Some(current) = queue.pop_front() {
281 for (neighbor, _edge_id) in self.graph.neighbors(current) {
282 if subset.contains(&neighbor)
283 && fragment.contains(&neighbor)
284 && visited.insert(neighbor)
285 {
286 queue.push_back(neighbor);
287 }
288 }
289 }
290
291 visited.len() == subset.len()
292 }
293
294 fn compute_boundary_within(
296 &self,
297 subset: &HashSet<VertexId>,
298 fragment: &HashSet<VertexId>,
299 ) -> u64 {
300 let mut boundary = 0u64;
301
302 for edge in self.graph.edges().into_iter() {
303 if !fragment.contains(&edge.source) || !fragment.contains(&edge.target) {
305 continue;
306 }
307
308 let src_in = subset.contains(&edge.source);
309 let tgt_in = subset.contains(&edge.target);
310
311 if src_in != tgt_in {
312 boundary += 1;
313 }
314 }
315
316 boundary
317 }
318
319 pub fn insert_edge(&mut self, _edge_id: EdgeId, u: VertexId, v: VertexId) {
321 self.connectivity.insert_edge(u, v);
322
323 let u_frag = self.vertex_fragment.get(&u).copied();
325 let v_frag = self.vertex_fragment.get(&v).copied();
326
327 match (u_frag, v_frag) {
328 (Some(uf), Some(vf)) if uf != vf => {
329 self.merge_fragments(uf, vf);
331 }
332 (None, Some(_)) | (Some(_), None) | (None, None) => {
333 self.rebuild();
335 }
336 _ => {
337 self.update_fragment_containing(u);
339 }
340 }
341 }
342
343 pub fn delete_edge(&mut self, _edge_id: EdgeId, u: VertexId, v: VertexId) {
345 self.connectivity.delete_edge(u, v);
346
347 if !self.connectivity.connected(u, v) {
349 self.rebuild();
351 } else {
352 self.update_fragment_containing(u);
354 }
355 }
356
357 fn merge_fragments(&mut self, _frag1_id: u64, _frag2_id: u64) {
359 self.rebuild();
362 }
363
364 fn update_fragment_containing(&mut self, v: VertexId) {
366 if let Some(&frag_id) = self.vertex_fragment.get(&v) {
367 let vertices = self
369 .fragments
370 .iter()
371 .find(|f| f.id == frag_id)
372 .map(|f| f.vertices.clone());
373
374 if let Some(vertices) = vertices {
375 let (min_cut, witness) = self.compute_fragment_min_cut(&vertices);
377
378 if let Some(frag) = self.fragments.iter_mut().find(|f| f.id == frag_id) {
380 frag.min_cut = min_cut;
381 frag.witness = witness;
382 }
383 }
384 }
385 }
386
387 pub fn query(&self) -> FragmentResult {
389 if self.fragments.len() <= 1 {
390 if let Some(frag) = self.fragments.first() {
391 if let Some(ref witness) = frag.witness {
392 return FragmentResult::Connected {
393 min_cut: frag.min_cut,
394 witness: witness.clone(),
395 };
396 }
397 }
398 let mut membership = RoaringBitmap::new();
400 membership.insert(0);
401 return FragmentResult::Connected {
402 min_cut: u64::MAX,
403 witness: WitnessHandle::new(0, membership, u64::MAX),
404 };
405 }
406
407 FragmentResult::Disconnected {
408 fragments: self.fragments.clone(),
409 global_min_cut: 0,
410 }
411 }
412
413 pub fn num_fragments(&self) -> usize {
415 self.fragments.len()
416 }
417
418 pub fn is_connected(&self) -> bool {
420 self.fragments.len() <= 1
421 }
422}
423
424#[cfg(test)]
425mod tests {
426 use super::*;
427
428 #[test]
429 fn test_empty_graph() {
430 let graph = Arc::new(DynamicGraph::new());
431 let alg = FragmentingAlgorithm::new(graph);
432 assert_eq!(alg.num_fragments(), 0);
433 }
434
435 #[test]
436 fn test_connected_graph() {
437 let graph = Arc::new(DynamicGraph::new());
438 graph.insert_edge(0, 1, 1.0).unwrap();
439 graph.insert_edge(1, 2, 1.0).unwrap();
440
441 let alg = FragmentingAlgorithm::new(graph);
442 assert_eq!(alg.num_fragments(), 1);
443 assert!(alg.is_connected());
444 }
445
446 #[test]
447 fn test_disconnected_graph() {
448 let graph = Arc::new(DynamicGraph::new());
449 graph.insert_edge(0, 1, 1.0).unwrap();
450 graph.insert_edge(2, 3, 1.0).unwrap();
451
452 let alg = FragmentingAlgorithm::new(graph);
453 assert_eq!(alg.num_fragments(), 2);
454 assert!(!alg.is_connected());
455 }
456
457 #[test]
458 fn test_dynamic_split() {
459 let graph = Arc::new(DynamicGraph::new());
460 let _e1 = graph.insert_edge(0, 1, 1.0).unwrap();
461 let e2 = graph.insert_edge(1, 2, 1.0).unwrap();
462
463 let mut alg = FragmentingAlgorithm::new(Arc::clone(&graph));
464 assert!(alg.is_connected());
465
466 graph.delete_edge(1, 2).unwrap();
468 alg.delete_edge(e2, 1, 2);
469
470 assert!(!alg.is_connected());
471 assert_eq!(alg.num_fragments(), 2);
472 }
473
474 #[test]
475 fn test_dynamic_merge() {
476 let graph = Arc::new(DynamicGraph::new());
477 graph.insert_edge(0, 1, 1.0).unwrap();
478 graph.insert_edge(2, 3, 1.0).unwrap();
479
480 let mut alg = FragmentingAlgorithm::new(Arc::clone(&graph));
481 assert!(!alg.is_connected());
482
483 let bridge = graph.insert_edge(1, 2, 1.0).unwrap();
485 alg.insert_edge(bridge, 1, 2);
486
487 assert!(alg.is_connected());
488 assert_eq!(alg.num_fragments(), 1);
489 }
490
491 #[test]
492 fn test_query_connected() {
493 let graph = Arc::new(DynamicGraph::new());
494 graph.insert_edge(0, 1, 1.0).unwrap();
495 graph.insert_edge(1, 2, 1.0).unwrap();
496 graph.insert_edge(2, 0, 1.0).unwrap();
497
498 let alg = FragmentingAlgorithm::new(graph);
499
500 match alg.query() {
501 FragmentResult::Connected { min_cut, .. } => {
502 assert_eq!(min_cut, 2); }
504 _ => panic!("Expected connected result"),
505 }
506 }
507
508 #[test]
509 fn test_query_disconnected() {
510 let graph = Arc::new(DynamicGraph::new());
511 graph.insert_edge(0, 1, 1.0).unwrap();
512 graph.insert_edge(2, 3, 1.0).unwrap();
513
514 let alg = FragmentingAlgorithm::new(graph);
515
516 match alg.query() {
517 FragmentResult::Disconnected { global_min_cut, .. } => {
518 assert_eq!(global_min_cut, 0);
519 }
520 _ => panic!("Expected disconnected result"),
521 }
522 }
523}