1use std::collections::{HashMap, HashSet, VecDeque};
13use crate::graph::{VertexId, Weight};
14
15#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
18pub enum EdgeColor {
19 Red,
21 Blue,
23 Green,
25 Yellow,
27}
28
29#[derive(Debug, Clone)]
32pub struct EdgeColoring {
33 colors: HashMap<(VertexId, VertexId), EdgeColor>,
35 pub a: usize,
37 pub b: usize,
39}
40
41impl EdgeColoring {
42 pub fn new(a: usize, b: usize) -> Self {
44 Self {
45 colors: HashMap::new(),
46 a,
47 b,
48 }
49 }
50
51 pub fn get(&self, u: VertexId, v: VertexId) -> Option<EdgeColor> {
53 let key = if u < v { (u, v) } else { (v, u) };
54 self.colors.get(&key).copied()
55 }
56
57 pub fn set(&mut self, u: VertexId, v: VertexId, color: EdgeColor) {
59 let key = if u < v { (u, v) } else { (v, u) };
60 self.colors.insert(key, color);
61 }
62
63 pub fn has_color(&self, u: VertexId, v: VertexId, color: EdgeColor) -> bool {
65 self.get(u, v) == Some(color)
66 }
67}
68
69pub fn generate_coloring_family(
72 a: usize,
73 b: usize,
74 num_edges: usize,
75) -> Vec<EdgeColoring> {
76 let log_n = (num_edges.max(2) as f64).log2().ceil() as usize;
80 let family_size = (1 << (a.min(b) * (a + b).max(1).ilog2() as usize + 1)) * log_n;
81 let family_size = family_size.min(100); let mut family = Vec::with_capacity(family_size);
84
85 for seed in 0..family_size {
86 let coloring = EdgeColoring::new(a, b);
87 family.push(coloring);
90 }
91
92 family
93}
94
95#[derive(Debug, Clone)]
97pub struct GreedyForestPacking {
98 pub num_forests: usize,
100 edge_forest: HashMap<(VertexId, VertexId), usize>,
102 forests: Vec<HashSet<(VertexId, VertexId)>>,
104 forest_parents: Vec<HashMap<VertexId, VertexId>>,
106}
107
108impl GreedyForestPacking {
109 pub fn new(num_forests: usize) -> Self {
112 Self {
113 num_forests,
114 edge_forest: HashMap::new(),
115 forests: vec![HashSet::new(); num_forests],
116 forest_parents: vec![HashMap::new(); num_forests],
117 }
118 }
119
120 fn find_root(&mut self, forest_id: usize, v: VertexId) -> VertexId {
122 if !self.forest_parents[forest_id].contains_key(&v) {
123 self.forest_parents[forest_id].insert(v, v);
124 return v;
125 }
126
127 let parent = self.forest_parents[forest_id][&v];
128 if parent == v {
129 return v;
130 }
131
132 let root = self.find_root(forest_id, parent);
133 self.forest_parents[forest_id].insert(v, root);
134 root
135 }
136
137 fn union(&mut self, forest_id: usize, u: VertexId, v: VertexId) {
139 let root_u = self.find_root(forest_id, u);
140 let root_v = self.find_root(forest_id, v);
141 if root_u != root_v {
142 self.forest_parents[forest_id].insert(root_u, root_v);
143 }
144 }
145
146 fn would_create_cycle(&mut self, forest_id: usize, u: VertexId, v: VertexId) -> bool {
148 self.find_root(forest_id, u) == self.find_root(forest_id, v)
149 }
150
151 pub fn insert_edge(&mut self, u: VertexId, v: VertexId) -> Option<usize> {
153 let key = if u < v { (u, v) } else { (v, u) };
154
155 if self.edge_forest.contains_key(&key) {
157 return self.edge_forest.get(&key).copied();
158 }
159
160 for forest_id in 0..self.num_forests {
162 if !self.would_create_cycle(forest_id, u, v) {
163 self.forests[forest_id].insert(key);
164 self.edge_forest.insert(key, forest_id);
165 self.union(forest_id, u, v);
166 return Some(forest_id);
167 }
168 }
169
170 None
172 }
173
174 pub fn delete_edge(&mut self, u: VertexId, v: VertexId) -> Option<usize> {
176 let key = if u < v { (u, v) } else { (v, u) };
177
178 if let Some(forest_id) = self.edge_forest.remove(&key) {
179 self.forests[forest_id].remove(&key);
180 self.rebuild_forest_connectivity(forest_id);
182 return Some(forest_id);
183 }
184 None
185 }
186
187 fn rebuild_forest_connectivity(&mut self, forest_id: usize) {
189 self.forest_parents[forest_id].clear();
190 let edges: Vec<_> = self.forests[forest_id].iter().copied().collect();
192 for (u, v) in edges {
193 self.union(forest_id, u, v);
194 }
195 }
196
197 pub fn is_tree_edge(&self, u: VertexId, v: VertexId) -> bool {
199 let key = if u < v { (u, v) } else { (v, u) };
200 self.edge_forest.contains_key(&key)
201 }
202
203 pub fn get_forest(&self, u: VertexId, v: VertexId) -> Option<usize> {
205 let key = if u < v { (u, v) } else { (v, u) };
206 self.edge_forest.get(&key).copied()
207 }
208
209 pub fn forest_edges(&self, forest_id: usize) -> &HashSet<(VertexId, VertexId)> {
211 &self.forests[forest_id]
212 }
213}
214
215#[derive(Debug, Clone)]
217pub struct LocalCut {
218 pub vertices: HashSet<VertexId>,
220 pub boundary: Vec<(VertexId, VertexId)>,
222 pub cut_value: f64,
224 pub volume: usize,
226}
227
228#[derive(Debug)]
231pub struct DeterministicLocalKCut {
232 lambda_max: u64,
234 nu: usize,
236 beta: usize,
238 forests: GreedyForestPacking,
240 red_blue_colorings: Vec<EdgeColoring>,
242 green_yellow_colorings: Vec<EdgeColoring>,
244 adjacency: HashMap<VertexId, HashMap<VertexId, Weight>>,
246 edges: HashSet<(VertexId, VertexId)>,
248}
249
250impl DeterministicLocalKCut {
251 pub fn new(lambda_max: u64, nu: usize, beta: usize) -> Self {
253 let num_forests = ((6 * lambda_max) as usize).max(10);
255
256 let a_rb = 2 * beta;
258 let b_rb = nu;
259 let a_gy = 2 * beta - 1;
260 let b_gy = lambda_max as usize;
261
262 Self {
263 lambda_max,
264 nu,
265 beta,
266 forests: GreedyForestPacking::new(num_forests),
267 red_blue_colorings: generate_coloring_family(a_rb, b_rb, 1000),
268 green_yellow_colorings: generate_coloring_family(a_gy, b_gy, 1000),
269 adjacency: HashMap::new(),
270 edges: HashSet::new(),
271 }
272 }
273
274 pub fn insert_edge(&mut self, u: VertexId, v: VertexId, weight: Weight) {
276 let key = if u < v { (u, v) } else { (v, u) };
277
278 if self.edges.contains(&key) {
279 return;
280 }
281
282 self.edges.insert(key);
283 self.adjacency.entry(u).or_default().insert(v, weight);
284 self.adjacency.entry(v).or_default().insert(u, weight);
285
286 if let Some(forest_id) = self.forests.insert_edge(u, v) {
288 for coloring in &mut self.red_blue_colorings {
290 let color = if (u + v + forest_id as u64) % 2 == 0 {
291 EdgeColor::Blue
292 } else {
293 EdgeColor::Red
294 };
295 coloring.set(u, v, color);
296 }
297 } else {
298 for coloring in &mut self.green_yellow_colorings {
300 let color = if (u * v) % 2 == 0 {
301 EdgeColor::Green
302 } else {
303 EdgeColor::Yellow
304 };
305 coloring.set(u, v, color);
306 }
307 }
308 }
309
310 pub fn delete_edge(&mut self, u: VertexId, v: VertexId) {
312 let key = if u < v { (u, v) } else { (v, u) };
313
314 if !self.edges.remove(&key) {
315 return;
316 }
317
318 if let Some(neighbors) = self.adjacency.get_mut(&u) {
319 neighbors.remove(&v);
320 }
321 if let Some(neighbors) = self.adjacency.get_mut(&v) {
322 neighbors.remove(&u);
323 }
324
325 self.forests.delete_edge(u, v);
326 }
327
328 pub fn query(&self, v: VertexId) -> Vec<LocalCut> {
331 let mut results = Vec::new();
332 let mut seen_cuts: HashSet<Vec<VertexId>> = HashSet::new();
333
334 for forest_id in 0..self.forests.num_forests {
336 for rb_coloring in &self.red_blue_colorings {
337 for gy_coloring in &self.green_yellow_colorings {
338 if let Some(cut) = self.color_coded_dfs(
340 v,
341 forest_id,
342 rb_coloring,
343 gy_coloring,
344 ) {
345 let mut sorted_vertices: Vec<_> = cut.vertices.iter().copied().collect();
347 sorted_vertices.sort();
348
349 if !seen_cuts.contains(&sorted_vertices) && cut.cut_value <= self.lambda_max as f64 {
350 seen_cuts.insert(sorted_vertices);
351 results.push(cut);
352 }
353 }
354 }
355 }
356 }
357
358 results
359 }
360
361 fn color_coded_dfs(
365 &self,
366 start: VertexId,
367 _forest_id: usize,
368 rb_coloring: &EdgeColoring,
369 gy_coloring: &EdgeColoring,
370 ) -> Option<LocalCut> {
371 let mut visited = HashSet::new();
372 let mut stack = vec![start];
373 let mut volume = 0usize;
374 let mut boundary = Vec::new();
375
376 while let Some(u) = stack.pop() {
377 if visited.contains(&u) {
378 continue;
379 }
380 visited.insert(u);
381
382 if let Some(neighbors) = self.adjacency.get(&u) {
384 volume += neighbors.len();
385
386 if volume > self.nu {
387 return None;
389 }
390
391 for (&v, &_weight) in neighbors {
392 let is_tree_edge = self.forests.is_tree_edge(u, v);
393
394 if is_tree_edge {
395 if rb_coloring.has_color(u, v, EdgeColor::Blue) {
397 if !visited.contains(&v) {
398 stack.push(v);
399 }
400 } else {
401 boundary.push((u, v));
403 }
404 } else {
405 if gy_coloring.has_color(u, v, EdgeColor::Green) {
407 if !visited.contains(&v) {
408 stack.push(v);
409 }
410 } else {
411 if !visited.contains(&v) {
413 boundary.push((u, v));
414 }
415 }
416 }
417 }
418 }
419 }
420
421 let cut_value: f64 = boundary.iter()
423 .map(|&(u, v)| {
424 self.adjacency.get(&u)
425 .and_then(|n| n.get(&v))
426 .copied()
427 .unwrap_or(1.0)
428 })
429 .sum();
430
431 Some(LocalCut {
432 vertices: visited,
433 boundary,
434 cut_value,
435 volume,
436 })
437 }
438
439 pub fn vertices(&self) -> Vec<VertexId> {
441 self.adjacency.keys().copied().collect()
442 }
443
444 pub fn neighbors(&self, v: VertexId) -> Vec<(VertexId, Weight)> {
446 self.adjacency.get(&v)
447 .map(|n| n.iter().map(|(&v, &w)| (v, w)).collect())
448 .unwrap_or_default()
449 }
450}
451
452#[cfg(test)]
453mod tests {
454 use super::*;
455
456 #[test]
457 fn test_forest_packing_basic() {
458 let mut packing = GreedyForestPacking::new(3);
459
460 assert!(packing.insert_edge(1, 2).is_some());
462 assert!(packing.insert_edge(2, 3).is_some());
463 assert!(packing.insert_edge(3, 4).is_some());
464
465 assert!(packing.is_tree_edge(1, 2));
466 assert!(packing.is_tree_edge(2, 3));
467 }
468
469 #[test]
470 fn test_forest_packing_cycle() {
471 let mut packing = GreedyForestPacking::new(3);
472
473 packing.insert_edge(1, 2);
475 packing.insert_edge(2, 3);
476 let forest = packing.insert_edge(1, 3);
478
479 assert!(forest.is_some());
481 }
482
483 #[test]
484 fn test_localkcut_query() {
485 let mut lkc = DeterministicLocalKCut::new(10, 100, 2);
486
487 lkc.insert_edge(1, 2, 1.0);
489 lkc.insert_edge(2, 3, 1.0);
490 lkc.insert_edge(3, 4, 1.0);
491
492 let cuts = lkc.query(1);
493
494 assert!(!cuts.is_empty());
496 assert!(cuts.iter().any(|c| c.vertices.contains(&1)));
497 }
498
499 #[test]
500 fn test_coloring_family() {
501 let family = generate_coloring_family(2, 5, 100);
502 assert!(!family.is_empty());
503 }
504
505 #[test]
506 fn test_edge_deletion() {
507 let mut lkc = DeterministicLocalKCut::new(10, 100, 2);
508
509 lkc.insert_edge(1, 2, 1.0);
510 lkc.insert_edge(2, 3, 1.0);
511
512 lkc.delete_edge(1, 2);
513
514 assert!(!lkc.forests.is_tree_edge(1, 2));
516 }
517}