1use super::{ProperCutInstance, InstanceResult};
8use super::witness::WitnessHandle;
9use crate::graph::{VertexId, EdgeId, DynamicGraph};
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 = RoaringBitmap::from_iter(self.vertices.iter().take(1).map(|&v| v as u32));
109 let seed = *self.vertices.iter().next().unwrap();
110 let witness = WitnessHandle::new(seed, membership, 0);
111 return Some((0, witness));
112 }
113
114 let vertex_vec: Vec<VertexId> = self.vertices.iter().copied().collect();
115 let mut min_cut = u64::MAX;
116 let mut best_set = HashSet::new();
117
118 let max_mask = 1u64 << n;
121
122 for mask in 1..max_mask - 1 {
123 let mut subset = HashSet::new();
125 for (i, &vertex) in vertex_vec.iter().enumerate() {
126 if mask & (1 << i) != 0 {
127 subset.insert(vertex);
128 }
129 }
130
131 if !self.is_connected_set(&subset) {
133 continue;
134 }
135
136 let (boundary_value, _boundary_edges) = self.compute_boundary(&subset);
138
139 if boundary_value < min_cut {
140 min_cut = boundary_value;
141 best_set = subset.clone();
142 }
143 }
144
145 if min_cut == u64::MAX {
146 return None;
148 }
149
150 let membership: RoaringBitmap = best_set.iter().map(|&v| v as u32).collect();
153
154 let seed = *best_set.iter().next().unwrap();
156
157 let witness = WitnessHandle::new(seed, membership, min_cut);
158
159 Some((min_cut, witness))
160 }
161
162 fn is_connected_set(&self, vertices: &HashSet<VertexId>) -> bool {
166 if vertices.is_empty() {
167 return true;
168 }
169
170 let start = *vertices.iter().next().unwrap();
172 let mut visited = HashSet::new();
173 let mut queue = VecDeque::new();
174
175 queue.push_back(start);
176 visited.insert(start);
177
178 while let Some(current) = queue.pop_front() {
179 if let Some(neighbors) = self.adjacency.get(¤t) {
180 for &(neighbor, _edge_id) in neighbors {
181 if vertices.contains(&neighbor) && visited.insert(neighbor) {
183 queue.push_back(neighbor);
184 }
185 }
186 }
187 }
188
189 visited.len() == vertices.len()
191 }
192
193 fn compute_boundary(&self, set: &HashSet<VertexId>) -> (u64, Vec<EdgeId>) {
198 let mut boundary_value = 0u64;
199 let mut boundary_edges = Vec::new();
200
201 for &(u, v, edge_id) in &self.edges {
202 let u_in_set = set.contains(&u);
203 let v_in_set = set.contains(&v);
204
205 if u_in_set != v_in_set {
207 boundary_value += 1;
208 boundary_edges.push(edge_id);
209 }
210 }
211
212 (boundary_value, boundary_edges)
213 }
214
215 fn is_connected(&self) -> bool {
217 self.is_connected_set(&self.vertices)
218 }
219
220 fn rebuild_adjacency(&mut self) {
222 self.adjacency.clear();
223
224 for &(u, v, edge_id) in &self.edges {
225 self.adjacency
226 .entry(u)
227 .or_insert_with(Vec::new)
228 .push((v, edge_id));
229
230 self.adjacency
231 .entry(v)
232 .or_insert_with(Vec::new)
233 .push((u, edge_id));
234 }
235 }
236
237 fn insert(&mut self, edge_id: EdgeId, u: VertexId, v: VertexId) {
238 self.vertices.insert(u);
240 self.vertices.insert(v);
241 self.edges.push((u, v, edge_id));
242 self.rebuild_adjacency();
243 }
244
245 fn delete(&mut self, edge_id: EdgeId, _u: VertexId, _v: VertexId) {
246 self.edges.retain(|(_, _, eid)| *eid != edge_id);
248 self.rebuild_adjacency();
249 }
250}
251
252impl ProperCutInstance for StubInstance {
253 fn init(_graph: &DynamicGraph, lambda_min: u64, lambda_max: u64) -> Self {
254 Self::new_empty(lambda_min, lambda_max)
256 }
257
258 fn apply_inserts(&mut self, edges: &[(EdgeId, VertexId, VertexId)]) {
259 for &(edge_id, u, v) in edges {
260 self.insert(edge_id, u, v);
261 }
262 }
263
264 fn apply_deletes(&mut self, edges: &[(EdgeId, VertexId, VertexId)]) {
265 for &(edge_id, u, v) in edges {
266 self.delete(edge_id, u, v);
267 }
268 }
269
270 fn query(&mut self) -> InstanceResult {
271 match self.compute_min_cut() {
272 Some((value, witness)) if value <= self.lambda_max => {
273 InstanceResult::ValueInRange { value, witness }
274 }
275 _ => InstanceResult::AboveRange,
276 }
277 }
278
279 fn bounds(&self) -> (u64, u64) {
280 (self.lambda_min, self.lambda_max)
281 }
282}
283
284#[cfg(test)]
285mod tests {
286 use super::*;
287 use crate::graph::DynamicGraph;
288
289 #[test]
290 fn test_empty_graph() {
291 let graph = DynamicGraph::new();
292 let mut instance = StubInstance::new(&graph, 0, 10);
293
294 let result = instance.query();
295 assert!(matches!(result, InstanceResult::AboveRange));
296 }
297
298 #[test]
299 fn test_single_vertex() {
300 let graph = DynamicGraph::new();
301 graph.add_vertex(1);
302
303 let mut instance = StubInstance::new(&graph, 0, 10);
304 let result = instance.query();
305 assert!(matches!(result, InstanceResult::AboveRange));
306 }
307
308 #[test]
309 fn test_path_graph() {
310 let graph = DynamicGraph::new();
312 graph.insert_edge(1, 2, 1.0).unwrap();
313 graph.insert_edge(2, 3, 1.0).unwrap();
314
315 let mut instance = StubInstance::new(&graph, 0, 10);
316
317 let result = instance.query();
318 match result {
319 InstanceResult::ValueInRange { value, .. } => {
320 assert_eq!(value, 1);
322 }
323 _ => panic!("Expected ValueInRange result"),
324 }
325 }
326
327 #[test]
328 fn test_cycle_graph() {
329 let graph = DynamicGraph::new();
331 graph.insert_edge(1, 2, 1.0).unwrap();
332 graph.insert_edge(2, 3, 1.0).unwrap();
333 graph.insert_edge(3, 1, 1.0).unwrap();
334
335 let mut instance = StubInstance::new(&graph, 0, 10);
336
337 let result = instance.query();
338 match result {
339 InstanceResult::ValueInRange { value, .. } => {
340 assert_eq!(value, 2);
342 }
343 _ => panic!("Expected ValueInRange result"),
344 }
345 }
346
347 #[test]
348 fn test_complete_graph_k4() {
349 let graph = DynamicGraph::new();
351 for i in 1..=4 {
352 for j in i + 1..=4 {
353 graph.insert_edge(i, j, 1.0).unwrap();
354 }
355 }
356
357 let mut instance = StubInstance::new(&graph, 0, 10);
358
359 let result = instance.query();
360 match result {
361 InstanceResult::ValueInRange { value, .. } => {
362 assert_eq!(value, 3);
364 }
365 _ => panic!("Expected ValueInRange result"),
366 }
367 }
368
369 #[test]
370 fn test_disconnected_graph() {
371 let graph = DynamicGraph::new();
373 graph.insert_edge(1, 2, 1.0).unwrap();
374 graph.insert_edge(3, 4, 1.0).unwrap();
375
376 let mut instance = StubInstance::new(&graph, 0, 10);
377
378 let result = instance.query();
379 match result {
380 InstanceResult::ValueInRange { value, .. } => {
381 assert_eq!(value, 0);
383 }
384 _ => panic!("Expected ValueInRange with value 0"),
385 }
386 }
387
388 #[test]
389 fn test_bridge_graph() {
390 let graph = DynamicGraph::new();
392 graph.insert_edge(1, 2, 1.0).unwrap();
393 graph.insert_edge(2, 3, 1.0).unwrap();
394 graph.insert_edge(3, 1, 1.0).unwrap();
395 graph.insert_edge(3, 4, 1.0).unwrap(); graph.insert_edge(4, 5, 1.0).unwrap();
397 graph.insert_edge(5, 6, 1.0).unwrap();
398 graph.insert_edge(6, 4, 1.0).unwrap();
399
400 let mut instance = StubInstance::new(&graph, 0, 10);
401
402 let result = instance.query();
403 match result {
404 InstanceResult::ValueInRange { value, .. } => {
405 assert_eq!(value, 1);
407 }
408 _ => panic!("Expected ValueInRange result"),
409 }
410 }
411
412 #[test]
413 fn test_is_connected_set() {
414 let graph = DynamicGraph::new();
415 graph.insert_edge(1, 2, 1.0).unwrap();
416 graph.insert_edge(2, 3, 1.0).unwrap();
417 graph.insert_edge(3, 4, 1.0).unwrap();
418
419 let instance = StubInstance::new(&graph, 0, 10);
420
421 let mut subset = HashSet::new();
423 subset.insert(1);
424 subset.insert(2);
425 subset.insert(3);
426 assert!(instance.is_connected_set(&subset));
427
428 let mut subset = HashSet::new();
430 subset.insert(1);
431 subset.insert(4);
432 assert!(!instance.is_connected_set(&subset));
433
434 let mut subset = HashSet::new();
436 subset.insert(1);
437 assert!(instance.is_connected_set(&subset));
438 }
439
440 #[test]
441 fn test_compute_boundary() {
442 let graph = DynamicGraph::new();
443 let e1 = graph.insert_edge(1, 2, 1.0).unwrap();
444 let e2 = graph.insert_edge(2, 3, 1.0).unwrap();
445 let _e3 = graph.insert_edge(3, 4, 1.0).unwrap();
446
447 let instance = StubInstance::new(&graph, 0, 10);
448
449 let mut set = HashSet::new();
451 set.insert(1);
452 set.insert(2);
453 let (value, edges) = instance.compute_boundary(&set);
454 assert_eq!(value, 1); assert_eq!(edges.len(), 1);
456 assert!(edges.contains(&e2));
457
458 let mut set = HashSet::new();
460 set.insert(2);
461 let (value, edges) = instance.compute_boundary(&set);
462 assert_eq!(value, 2); assert_eq!(edges.len(), 2);
464 assert!(edges.contains(&e1));
465 assert!(edges.contains(&e2));
466 }
467
468 #[test]
469 fn test_dynamic_updates() {
470 let graph = DynamicGraph::new();
471 graph.insert_edge(1, 2, 1.0).unwrap();
472 graph.insert_edge(2, 3, 1.0).unwrap();
473
474 let mut instance = StubInstance::new(&graph, 0, 10);
475
476 let result = instance.query();
478 match result {
479 InstanceResult::ValueInRange { value, .. } => assert_eq!(value, 1),
480 _ => panic!("Expected ValueInRange"),
481 }
482
483 let e3_id = 100; instance.apply_inserts(&[(e3_id, 3, 1)]);
486
487 let result = instance.query();
489 match result {
490 InstanceResult::ValueInRange { value, .. } => assert_eq!(value, 2),
491 _ => panic!("Expected ValueInRange"),
492 }
493
494 instance.apply_deletes(&[(e3_id, 3, 1)]);
496
497 let result = instance.query();
499 match result {
500 InstanceResult::ValueInRange { value, .. } => assert_eq!(value, 1),
501 _ => panic!("Expected ValueInRange"),
502 }
503 }
504
505 #[test]
506 fn test_range_bounds() {
507 let graph = DynamicGraph::new();
508 graph.insert_edge(1, 2, 1.0).unwrap();
509 graph.insert_edge(2, 3, 1.0).unwrap();
510
511 let mut instance = StubInstance::new(&graph, 2, 5);
513
514 let result = instance.query();
517 let mut instance = StubInstance::new(&graph, 0, 1);
521
522 let result = instance.query();
524 match result {
525 InstanceResult::ValueInRange { value, .. } => assert_eq!(value, 1),
526 _ => panic!("Expected ValueInRange"),
527 }
528
529 let mut instance = StubInstance::new(&graph, 0, 0);
531
532 let result = instance.query();
534 assert!(matches!(result, InstanceResult::AboveRange));
535 }
536
537 #[test]
538 fn test_witness_information() {
539 let graph = DynamicGraph::new();
540 graph.insert_edge(1, 2, 1.0).unwrap();
541 graph.insert_edge(2, 3, 1.0).unwrap();
542
543 let mut instance = StubInstance::new(&graph, 0, 10);
544
545 let result = instance.query();
546 match result {
547 InstanceResult::ValueInRange { value, witness } => {
548 assert_eq!(value, 1);
549 assert_eq!(witness.boundary_size(), 1);
550 assert!(witness.cardinality() > 0);
551 assert!(witness.cardinality() < 3); }
553 _ => panic!("Expected ValueInRange with witness"),
554 }
555 }
556}