1use super::witness::WitnessHandle;
8use super::{InstanceResult, ProperCutInstance};
9use crate::graph::{DynamicGraph, EdgeId, VertexId};
10use roaring::RoaringBitmap;
11use std::collections::{HashMap, HashSet, VecDeque};
12
13pub struct StubInstance {
31 lambda_min: u64,
33 lambda_max: u64,
34 edges: Vec<(VertexId, VertexId, EdgeId)>,
36 vertices: HashSet<VertexId>,
38 adjacency: HashMap<VertexId, Vec<(VertexId, EdgeId)>>,
40}
41
42impl StubInstance {
43 pub fn new(graph: &DynamicGraph, lambda_min: u64, lambda_max: u64) -> Self {
47 let mut instance = Self {
48 lambda_min,
49 lambda_max,
50 edges: Vec::new(),
51 vertices: HashSet::new(),
52 adjacency: HashMap::new(),
53 };
54
55 for edge in graph.edges() {
57 instance.vertices.insert(edge.source);
58 instance.vertices.insert(edge.target);
59 instance.edges.push((edge.source, edge.target, edge.id));
60 }
61
62 instance.rebuild_adjacency();
63 instance
64 }
65
66 pub fn new_empty(lambda_min: u64, lambda_max: u64) -> Self {
70 Self {
71 lambda_min,
72 lambda_max,
73 edges: Vec::new(),
74 vertices: HashSet::new(),
75 adjacency: HashMap::new(),
76 }
77 }
78
79 fn compute_min_cut(&self) -> Option<(u64, WitnessHandle)> {
88 if self.vertices.is_empty() {
89 return None;
90 }
91
92 let n = self.vertices.len();
93 if n == 1 {
94 return None;
96 }
97
98 if n >= 20 {
101 return None;
103 }
104
105 if !self.is_connected() {
107 let membership =
109 RoaringBitmap::from_iter(self.vertices.iter().take(1).map(|&v| v as u32));
110 let seed = *self.vertices.iter().next().unwrap();
111 let witness = WitnessHandle::new(seed, membership, 0);
112 return Some((0, witness));
113 }
114
115 let vertex_vec: Vec<VertexId> = self.vertices.iter().copied().collect();
116 let mut min_cut = u64::MAX;
117 let mut best_set = HashSet::new();
118
119 let max_mask = 1u64 << n;
122
123 for mask in 1..max_mask - 1 {
124 let mut subset = HashSet::new();
126 for (i, &vertex) in vertex_vec.iter().enumerate() {
127 if mask & (1 << i) != 0 {
128 subset.insert(vertex);
129 }
130 }
131
132 if !self.is_connected_set(&subset) {
134 continue;
135 }
136
137 let (boundary_value, _boundary_edges) = self.compute_boundary(&subset);
139
140 if boundary_value < min_cut {
141 min_cut = boundary_value;
142 best_set = subset.clone();
143 }
144 }
145
146 if min_cut == u64::MAX {
147 return None;
149 }
150
151 let membership: RoaringBitmap = best_set.iter().map(|&v| v as u32).collect();
154
155 let seed = *best_set.iter().next().unwrap();
157
158 let witness = WitnessHandle::new(seed, membership, min_cut);
159
160 Some((min_cut, witness))
161 }
162
163 fn is_connected_set(&self, vertices: &HashSet<VertexId>) -> bool {
167 if vertices.is_empty() {
168 return true;
169 }
170
171 let start = *vertices.iter().next().unwrap();
173 let mut visited = HashSet::new();
174 let mut queue = VecDeque::new();
175
176 queue.push_back(start);
177 visited.insert(start);
178
179 while let Some(current) = queue.pop_front() {
180 if let Some(neighbors) = self.adjacency.get(¤t) {
181 for &(neighbor, _edge_id) in neighbors {
182 if vertices.contains(&neighbor) && visited.insert(neighbor) {
184 queue.push_back(neighbor);
185 }
186 }
187 }
188 }
189
190 visited.len() == vertices.len()
192 }
193
194 fn compute_boundary(&self, set: &HashSet<VertexId>) -> (u64, Vec<EdgeId>) {
199 let mut boundary_value = 0u64;
200 let mut boundary_edges = Vec::new();
201
202 for &(u, v, edge_id) in &self.edges {
203 let u_in_set = set.contains(&u);
204 let v_in_set = set.contains(&v);
205
206 if u_in_set != v_in_set {
208 boundary_value += 1;
209 boundary_edges.push(edge_id);
210 }
211 }
212
213 (boundary_value, boundary_edges)
214 }
215
216 fn is_connected(&self) -> bool {
218 self.is_connected_set(&self.vertices)
219 }
220
221 fn rebuild_adjacency(&mut self) {
223 self.adjacency.clear();
224
225 for &(u, v, edge_id) in &self.edges {
226 self.adjacency
227 .entry(u)
228 .or_insert_with(Vec::new)
229 .push((v, edge_id));
230
231 self.adjacency
232 .entry(v)
233 .or_insert_with(Vec::new)
234 .push((u, edge_id));
235 }
236 }
237
238 fn insert(&mut self, edge_id: EdgeId, u: VertexId, v: VertexId) {
239 self.vertices.insert(u);
241 self.vertices.insert(v);
242 self.edges.push((u, v, edge_id));
243 self.rebuild_adjacency();
244 }
245
246 fn delete(&mut self, edge_id: EdgeId, _u: VertexId, _v: VertexId) {
247 self.edges.retain(|(_, _, eid)| *eid != edge_id);
249 self.rebuild_adjacency();
250 }
251}
252
253impl ProperCutInstance for StubInstance {
254 fn init(_graph: &DynamicGraph, lambda_min: u64, lambda_max: u64) -> Self {
255 Self::new_empty(lambda_min, lambda_max)
257 }
258
259 fn apply_inserts(&mut self, edges: &[(EdgeId, VertexId, VertexId)]) {
260 for &(edge_id, u, v) in edges {
261 self.insert(edge_id, u, v);
262 }
263 }
264
265 fn apply_deletes(&mut self, edges: &[(EdgeId, VertexId, VertexId)]) {
266 for &(edge_id, u, v) in edges {
267 self.delete(edge_id, u, v);
268 }
269 }
270
271 fn query(&mut self) -> InstanceResult {
272 match self.compute_min_cut() {
273 Some((value, witness)) if value <= self.lambda_max => {
274 InstanceResult::ValueInRange { value, witness }
275 }
276 _ => InstanceResult::AboveRange,
277 }
278 }
279
280 fn bounds(&self) -> (u64, u64) {
281 (self.lambda_min, self.lambda_max)
282 }
283}
284
285#[cfg(test)]
286mod tests {
287 use super::*;
288 use crate::graph::DynamicGraph;
289
290 #[test]
291 fn test_empty_graph() {
292 let graph = DynamicGraph::new();
293 let mut instance = StubInstance::new(&graph, 0, 10);
294
295 let result = instance.query();
296 assert!(matches!(result, InstanceResult::AboveRange));
297 }
298
299 #[test]
300 fn test_single_vertex() {
301 let graph = DynamicGraph::new();
302 graph.add_vertex(1);
303
304 let mut instance = StubInstance::new(&graph, 0, 10);
305 let result = instance.query();
306 assert!(matches!(result, InstanceResult::AboveRange));
307 }
308
309 #[test]
310 fn test_path_graph() {
311 let graph = DynamicGraph::new();
313 graph.insert_edge(1, 2, 1.0).unwrap();
314 graph.insert_edge(2, 3, 1.0).unwrap();
315
316 let mut instance = StubInstance::new(&graph, 0, 10);
317
318 let result = instance.query();
319 match result {
320 InstanceResult::ValueInRange { value, .. } => {
321 assert_eq!(value, 1);
323 }
324 _ => panic!("Expected ValueInRange result"),
325 }
326 }
327
328 #[test]
329 fn test_cycle_graph() {
330 let graph = DynamicGraph::new();
332 graph.insert_edge(1, 2, 1.0).unwrap();
333 graph.insert_edge(2, 3, 1.0).unwrap();
334 graph.insert_edge(3, 1, 1.0).unwrap();
335
336 let mut instance = StubInstance::new(&graph, 0, 10);
337
338 let result = instance.query();
339 match result {
340 InstanceResult::ValueInRange { value, .. } => {
341 assert_eq!(value, 2);
343 }
344 _ => panic!("Expected ValueInRange result"),
345 }
346 }
347
348 #[test]
349 fn test_complete_graph_k4() {
350 let graph = DynamicGraph::new();
352 for i in 1..=4 {
353 for j in i + 1..=4 {
354 graph.insert_edge(i, j, 1.0).unwrap();
355 }
356 }
357
358 let mut instance = StubInstance::new(&graph, 0, 10);
359
360 let result = instance.query();
361 match result {
362 InstanceResult::ValueInRange { value, .. } => {
363 assert_eq!(value, 3);
365 }
366 _ => panic!("Expected ValueInRange result"),
367 }
368 }
369
370 #[test]
371 fn test_disconnected_graph() {
372 let graph = DynamicGraph::new();
374 graph.insert_edge(1, 2, 1.0).unwrap();
375 graph.insert_edge(3, 4, 1.0).unwrap();
376
377 let mut instance = StubInstance::new(&graph, 0, 10);
378
379 let result = instance.query();
380 match result {
381 InstanceResult::ValueInRange { value, .. } => {
382 assert_eq!(value, 0);
384 }
385 _ => panic!("Expected ValueInRange with value 0"),
386 }
387 }
388
389 #[test]
390 fn test_bridge_graph() {
391 let graph = DynamicGraph::new();
393 graph.insert_edge(1, 2, 1.0).unwrap();
394 graph.insert_edge(2, 3, 1.0).unwrap();
395 graph.insert_edge(3, 1, 1.0).unwrap();
396 graph.insert_edge(3, 4, 1.0).unwrap(); graph.insert_edge(4, 5, 1.0).unwrap();
398 graph.insert_edge(5, 6, 1.0).unwrap();
399 graph.insert_edge(6, 4, 1.0).unwrap();
400
401 let mut instance = StubInstance::new(&graph, 0, 10);
402
403 let result = instance.query();
404 match result {
405 InstanceResult::ValueInRange { value, .. } => {
406 assert_eq!(value, 1);
408 }
409 _ => panic!("Expected ValueInRange result"),
410 }
411 }
412
413 #[test]
414 fn test_is_connected_set() {
415 let graph = DynamicGraph::new();
416 graph.insert_edge(1, 2, 1.0).unwrap();
417 graph.insert_edge(2, 3, 1.0).unwrap();
418 graph.insert_edge(3, 4, 1.0).unwrap();
419
420 let instance = StubInstance::new(&graph, 0, 10);
421
422 let mut subset = HashSet::new();
424 subset.insert(1);
425 subset.insert(2);
426 subset.insert(3);
427 assert!(instance.is_connected_set(&subset));
428
429 let mut subset = HashSet::new();
431 subset.insert(1);
432 subset.insert(4);
433 assert!(!instance.is_connected_set(&subset));
434
435 let mut subset = HashSet::new();
437 subset.insert(1);
438 assert!(instance.is_connected_set(&subset));
439 }
440
441 #[test]
442 fn test_compute_boundary() {
443 let graph = DynamicGraph::new();
444 let e1 = graph.insert_edge(1, 2, 1.0).unwrap();
445 let e2 = graph.insert_edge(2, 3, 1.0).unwrap();
446 let _e3 = graph.insert_edge(3, 4, 1.0).unwrap();
447
448 let instance = StubInstance::new(&graph, 0, 10);
449
450 let mut set = HashSet::new();
452 set.insert(1);
453 set.insert(2);
454 let (value, edges) = instance.compute_boundary(&set);
455 assert_eq!(value, 1); assert_eq!(edges.len(), 1);
457 assert!(edges.contains(&e2));
458
459 let mut set = HashSet::new();
461 set.insert(2);
462 let (value, edges) = instance.compute_boundary(&set);
463 assert_eq!(value, 2); assert_eq!(edges.len(), 2);
465 assert!(edges.contains(&e1));
466 assert!(edges.contains(&e2));
467 }
468
469 #[test]
470 fn test_dynamic_updates() {
471 let graph = DynamicGraph::new();
472 graph.insert_edge(1, 2, 1.0).unwrap();
473 graph.insert_edge(2, 3, 1.0).unwrap();
474
475 let mut instance = StubInstance::new(&graph, 0, 10);
476
477 let result = instance.query();
479 match result {
480 InstanceResult::ValueInRange { value, .. } => assert_eq!(value, 1),
481 _ => panic!("Expected ValueInRange"),
482 }
483
484 let e3_id = 100; instance.apply_inserts(&[(e3_id, 3, 1)]);
487
488 let result = instance.query();
490 match result {
491 InstanceResult::ValueInRange { value, .. } => assert_eq!(value, 2),
492 _ => panic!("Expected ValueInRange"),
493 }
494
495 instance.apply_deletes(&[(e3_id, 3, 1)]);
497
498 let result = instance.query();
500 match result {
501 InstanceResult::ValueInRange { value, .. } => assert_eq!(value, 1),
502 _ => panic!("Expected ValueInRange"),
503 }
504 }
505
506 #[test]
507 fn test_range_bounds() {
508 let graph = DynamicGraph::new();
509 graph.insert_edge(1, 2, 1.0).unwrap();
510 graph.insert_edge(2, 3, 1.0).unwrap();
511
512 let mut instance = StubInstance::new(&graph, 2, 5);
514
515 let result = instance.query();
518 let mut instance = StubInstance::new(&graph, 0, 1);
522
523 let result = instance.query();
525 match result {
526 InstanceResult::ValueInRange { value, .. } => assert_eq!(value, 1),
527 _ => panic!("Expected ValueInRange"),
528 }
529
530 let mut instance = StubInstance::new(&graph, 0, 0);
532
533 let result = instance.query();
535 assert!(matches!(result, InstanceResult::AboveRange));
536 }
537
538 #[test]
539 fn test_witness_information() {
540 let graph = DynamicGraph::new();
541 graph.insert_edge(1, 2, 1.0).unwrap();
542 graph.insert_edge(2, 3, 1.0).unwrap();
543
544 let mut instance = StubInstance::new(&graph, 0, 10);
545
546 let result = instance.query();
547 match result {
548 InstanceResult::ValueInRange { value, witness } => {
549 assert_eq!(value, 1);
550 assert_eq!(witness.boundary_size(), 1);
551 assert!(witness.cardinality() > 0);
552 assert!(witness.cardinality() < 3); }
554 _ => panic!("Expected ValueInRange with witness"),
555 }
556 }
557}