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(
115 &self,
116 start: VertexId,
117 visited: &mut HashSet<VertexId>,
118 ) -> HashSet<VertexId> {
119 let mut component = HashSet::new();
120 let mut queue = VecDeque::new();
121
122 queue.push_back(start);
123 visited.insert(start);
124 component.insert(start);
125
126 while let Some(current) = queue.pop_front() {
127 for (neighbor, _edge_id) in self.graph.neighbors(current) {
128 if visited.insert(neighbor) {
129 queue.push_back(neighbor);
130 component.insert(neighbor);
131 }
132 }
133 }
134
135 component
136 }
137
138 fn create_fragment(&mut self, vertices: HashSet<VertexId>) {
140 let fragment_id = self.next_id;
141 self.next_id += 1;
142
143 let edges: Vec<EdgeId> = self
145 .graph
146 .edges()
147 .into_iter()
148 .filter(|e| vertices.contains(&e.source) && vertices.contains(&e.target))
149 .map(|e| e.id)
150 .collect();
151
152 let (min_cut, witness) = self.compute_fragment_min_cut(&vertices);
154
155 let fragment = Fragment {
156 id: fragment_id,
157 vertices: vertices.clone(),
158 edges,
159 min_cut,
160 witness,
161 };
162
163 for &v in &vertices {
165 self.vertex_fragment.insert(v, fragment_id);
166 }
167
168 self.fragments.push(fragment);
169 }
170
171 fn compute_fragment_min_cut(
173 &self,
174 vertices: &HashSet<VertexId>,
175 ) -> (u64, Option<WitnessHandle>) {
176 if vertices.len() <= 1 {
177 return (u64::MAX, None);
178 }
179
180 if vertices.len() < 20 {
182 return self.brute_force_min_cut(vertices);
183 }
184
185 self.heuristic_min_cut(vertices)
187 }
188
189 fn brute_force_min_cut(&self, vertices: &HashSet<VertexId>) -> (u64, Option<WitnessHandle>) {
191 let vertex_vec: Vec<_> = vertices.iter().copied().collect();
192 let n = vertex_vec.len();
193
194 if n >= 20 {
195 return (u64::MAX, None);
196 }
197
198 let mut min_cut = u64::MAX;
199 let mut best_set = HashSet::new();
200
201 let max_mask = 1u64 << n;
203 for mask in 1..max_mask - 1 {
204 let mut subset: HashSet<VertexId> = HashSet::new();
205 for (i, &v) in vertex_vec.iter().enumerate() {
206 if mask & (1 << i) != 0 {
207 subset.insert(v);
208 }
209 }
210
211 if !self.is_connected_within(&subset, vertices) {
213 continue;
214 }
215
216 let boundary = self.compute_boundary_within(&subset, vertices);
218
219 if boundary < min_cut {
220 min_cut = boundary;
221 best_set = subset;
222 }
223 }
224
225 if min_cut == u64::MAX || best_set.is_empty() {
226 return (u64::MAX, None);
227 }
228
229 let membership: RoaringBitmap = best_set.iter().map(|&v| v as u32).collect();
231 let seed = *best_set.iter().next().unwrap();
232 let witness = WitnessHandle::new(seed, membership, min_cut);
233
234 (min_cut, Some(witness))
235 }
236
237 fn heuristic_min_cut(&self, vertices: &HashSet<VertexId>) -> (u64, Option<WitnessHandle>) {
239 let mut min_degree = u64::MAX;
241 let mut min_vertex = None;
242
243 for &v in vertices {
244 let degree = self
245 .graph
246 .neighbors(v)
247 .into_iter()
248 .filter(|(n, _)| vertices.contains(n))
249 .count() as u64;
250
251 if degree < min_degree {
252 min_degree = degree;
253 min_vertex = Some(v);
254 }
255 }
256
257 if let Some(v) = min_vertex {
258 let mut membership = RoaringBitmap::new();
259 membership.insert(v as u32);
260 let witness = WitnessHandle::new(v, membership, min_degree);
261 return (min_degree, Some(witness));
262 }
263
264 (u64::MAX, None)
265 }
266
267 fn is_connected_within(
269 &self,
270 subset: &HashSet<VertexId>,
271 fragment: &HashSet<VertexId>,
272 ) -> bool {
273 if subset.is_empty() {
274 return true;
275 }
276
277 let start = *subset.iter().next().unwrap();
278 let mut visited = HashSet::new();
279 let mut queue = VecDeque::new();
280
281 queue.push_back(start);
282 visited.insert(start);
283
284 while let Some(current) = queue.pop_front() {
285 for (neighbor, _edge_id) in self.graph.neighbors(current) {
286 if subset.contains(&neighbor)
287 && fragment.contains(&neighbor)
288 && visited.insert(neighbor)
289 {
290 queue.push_back(neighbor);
291 }
292 }
293 }
294
295 visited.len() == subset.len()
296 }
297
298 fn compute_boundary_within(
300 &self,
301 subset: &HashSet<VertexId>,
302 fragment: &HashSet<VertexId>,
303 ) -> u64 {
304 let mut boundary = 0u64;
305
306 for edge in self.graph.edges().into_iter() {
307 if !fragment.contains(&edge.source) || !fragment.contains(&edge.target) {
309 continue;
310 }
311
312 let src_in = subset.contains(&edge.source);
313 let tgt_in = subset.contains(&edge.target);
314
315 if src_in != tgt_in {
316 boundary += 1;
317 }
318 }
319
320 boundary
321 }
322
323 pub fn insert_edge(&mut self, _edge_id: EdgeId, u: VertexId, v: VertexId) {
325 self.connectivity.insert_edge(u, v);
326
327 let u_frag = self.vertex_fragment.get(&u).copied();
329 let v_frag = self.vertex_fragment.get(&v).copied();
330
331 match (u_frag, v_frag) {
332 (Some(uf), Some(vf)) if uf != vf => {
333 self.merge_fragments(uf, vf);
335 }
336 (None, Some(_)) | (Some(_), None) | (None, None) => {
337 self.rebuild();
339 }
340 _ => {
341 self.update_fragment_containing(u);
343 }
344 }
345 }
346
347 pub fn delete_edge(&mut self, _edge_id: EdgeId, u: VertexId, v: VertexId) {
349 self.connectivity.delete_edge(u, v);
350
351 if !self.connectivity.connected(u, v) {
353 self.rebuild();
355 } else {
356 self.update_fragment_containing(u);
358 }
359 }
360
361 fn merge_fragments(&mut self, _frag1_id: u64, _frag2_id: u64) {
363 self.rebuild();
366 }
367
368 fn update_fragment_containing(&mut self, v: VertexId) {
370 if let Some(&frag_id) = self.vertex_fragment.get(&v) {
371 let vertices = self
373 .fragments
374 .iter()
375 .find(|f| f.id == frag_id)
376 .map(|f| f.vertices.clone());
377
378 if let Some(vertices) = vertices {
379 let (min_cut, witness) = self.compute_fragment_min_cut(&vertices);
381
382 if let Some(frag) = self.fragments.iter_mut().find(|f| f.id == frag_id) {
384 frag.min_cut = min_cut;
385 frag.witness = witness;
386 }
387 }
388 }
389 }
390
391 pub fn query(&self) -> FragmentResult {
393 if self.fragments.len() <= 1 {
394 if let Some(frag) = self.fragments.first() {
395 if let Some(ref witness) = frag.witness {
396 return FragmentResult::Connected {
397 min_cut: frag.min_cut,
398 witness: witness.clone(),
399 };
400 }
401 }
402 let mut membership = RoaringBitmap::new();
404 membership.insert(0);
405 return FragmentResult::Connected {
406 min_cut: u64::MAX,
407 witness: WitnessHandle::new(0, membership, u64::MAX),
408 };
409 }
410
411 FragmentResult::Disconnected {
412 fragments: self.fragments.clone(),
413 global_min_cut: 0,
414 }
415 }
416
417 pub fn num_fragments(&self) -> usize {
419 self.fragments.len()
420 }
421
422 pub fn is_connected(&self) -> bool {
424 self.fragments.len() <= 1
425 }
426}
427
428#[cfg(test)]
429mod tests {
430 use super::*;
431
432 #[test]
433 fn test_empty_graph() {
434 let graph = Arc::new(DynamicGraph::new());
435 let alg = FragmentingAlgorithm::new(graph);
436 assert_eq!(alg.num_fragments(), 0);
437 }
438
439 #[test]
440 fn test_connected_graph() {
441 let graph = Arc::new(DynamicGraph::new());
442 graph.insert_edge(0, 1, 1.0).unwrap();
443 graph.insert_edge(1, 2, 1.0).unwrap();
444
445 let alg = FragmentingAlgorithm::new(graph);
446 assert_eq!(alg.num_fragments(), 1);
447 assert!(alg.is_connected());
448 }
449
450 #[test]
451 fn test_disconnected_graph() {
452 let graph = Arc::new(DynamicGraph::new());
453 graph.insert_edge(0, 1, 1.0).unwrap();
454 graph.insert_edge(2, 3, 1.0).unwrap();
455
456 let alg = FragmentingAlgorithm::new(graph);
457 assert_eq!(alg.num_fragments(), 2);
458 assert!(!alg.is_connected());
459 }
460
461 #[test]
462 fn test_dynamic_split() {
463 let graph = Arc::new(DynamicGraph::new());
464 let _e1 = graph.insert_edge(0, 1, 1.0).unwrap();
465 let e2 = graph.insert_edge(1, 2, 1.0).unwrap();
466
467 let mut alg = FragmentingAlgorithm::new(Arc::clone(&graph));
468 assert!(alg.is_connected());
469
470 graph.delete_edge(1, 2).unwrap();
472 alg.delete_edge(e2, 1, 2);
473
474 assert!(!alg.is_connected());
475 assert_eq!(alg.num_fragments(), 2);
476 }
477
478 #[test]
479 fn test_dynamic_merge() {
480 let graph = Arc::new(DynamicGraph::new());
481 graph.insert_edge(0, 1, 1.0).unwrap();
482 graph.insert_edge(2, 3, 1.0).unwrap();
483
484 let mut alg = FragmentingAlgorithm::new(Arc::clone(&graph));
485 assert!(!alg.is_connected());
486
487 let bridge = graph.insert_edge(1, 2, 1.0).unwrap();
489 alg.insert_edge(bridge, 1, 2);
490
491 assert!(alg.is_connected());
492 assert_eq!(alg.num_fragments(), 1);
493 }
494
495 #[test]
496 fn test_query_connected() {
497 let graph = Arc::new(DynamicGraph::new());
498 graph.insert_edge(0, 1, 1.0).unwrap();
499 graph.insert_edge(1, 2, 1.0).unwrap();
500 graph.insert_edge(2, 0, 1.0).unwrap();
501
502 let alg = FragmentingAlgorithm::new(graph);
503
504 match alg.query() {
505 FragmentResult::Connected { min_cut, .. } => {
506 assert_eq!(min_cut, 2); }
508 _ => panic!("Expected connected result"),
509 }
510 }
511
512 #[test]
513 fn test_query_disconnected() {
514 let graph = Arc::new(DynamicGraph::new());
515 graph.insert_edge(0, 1, 1.0).unwrap();
516 graph.insert_edge(2, 3, 1.0).unwrap();
517
518 let alg = FragmentingAlgorithm::new(graph);
519
520 match alg.query() {
521 FragmentResult::Disconnected { global_min_cut, .. } => {
522 assert_eq!(global_min_cut, 0);
523 }
524 _ => panic!("Expected disconnected result"),
525 }
526 }
527}