1use crate::graph::{VertexId, Weight};
21use std::collections::{HashMap, HashSet, VecDeque};
22
23pub type Phi = f64;
25
26#[derive(Debug, Clone)]
28pub struct HierarchyConfig {
29 pub phi: Phi,
31 pub max_expander_size: usize,
33 pub min_expander_size: usize,
35 pub target_precluster_size: usize,
37 pub max_boundary_ratio: f64,
39 pub track_mirror_cuts: bool,
41}
42
43impl Default for HierarchyConfig {
44 fn default() -> Self {
45 Self {
46 phi: 0.1,
47 max_expander_size: 500,
48 min_expander_size: 5,
49 target_precluster_size: 100,
50 max_boundary_ratio: 0.3,
51 track_mirror_cuts: true,
52 }
53 }
54}
55
56#[derive(Debug, Clone, Copy, PartialEq, Eq)]
58pub enum HierarchyLevel {
59 Expander,
61 Precluster,
63 Cluster,
65}
66
67#[derive(Debug, Clone)]
69pub struct Expander {
70 pub id: u64,
72 pub vertices: HashSet<VertexId>,
74 pub internal_edges: Vec<(VertexId, VertexId)>,
76 pub boundary_edges: Vec<(VertexId, VertexId)>,
78 pub volume: usize,
80 pub expansion_ratio: f64,
82 pub precluster_id: Option<u64>,
84}
85
86impl Expander {
87 pub fn new(id: u64, vertices: HashSet<VertexId>) -> Self {
89 Self {
90 id,
91 vertices,
92 internal_edges: Vec::new(),
93 boundary_edges: Vec::new(),
94 volume: 0,
95 expansion_ratio: 0.0,
96 precluster_id: None,
97 }
98 }
99
100 pub fn size(&self) -> usize {
102 self.vertices.len()
103 }
104
105 pub fn contains(&self, v: VertexId) -> bool {
107 self.vertices.contains(&v)
108 }
109
110 pub fn boundary_sparsity(&self) -> f64 {
112 if self.volume == 0 {
113 return 0.0;
114 }
115 self.boundary_edges.len() as f64 / self.volume as f64
116 }
117}
118
119#[derive(Debug, Clone)]
121pub struct Precluster {
122 pub id: u64,
124 pub expanders: Vec<u64>,
126 pub vertices: HashSet<VertexId>,
128 pub boundary_edges: Vec<(VertexId, VertexId)>,
130 pub volume: usize,
132 pub cluster_id: Option<u64>,
134}
135
136impl Precluster {
137 pub fn new(id: u64) -> Self {
139 Self {
140 id,
141 expanders: Vec::new(),
142 vertices: HashSet::new(),
143 boundary_edges: Vec::new(),
144 volume: 0,
145 cluster_id: None,
146 }
147 }
148
149 pub fn add_expander(&mut self, expander: &Expander) {
151 self.expanders.push(expander.id);
152 self.vertices.extend(&expander.vertices);
153 self.volume += expander.volume;
154 }
155
156 pub fn size(&self) -> usize {
158 self.vertices.len()
159 }
160
161 pub fn boundary_ratio(&self) -> f64 {
163 if self.volume == 0 {
164 return 0.0;
165 }
166 self.boundary_edges.len() as f64 / self.volume as f64
167 }
168}
169
170#[derive(Debug, Clone)]
172pub struct MirrorCut {
173 pub source_expander: u64,
175 pub target_expander: u64,
177 pub cut_value: f64,
179 pub cut_edges: Vec<(VertexId, VertexId)>,
181 pub certified: bool,
183}
184
185#[derive(Debug, Clone)]
187pub struct HierarchyCluster {
188 pub id: u64,
190 pub preclusters: Vec<u64>,
192 pub vertices: HashSet<VertexId>,
194 pub boundary_edges: Vec<(VertexId, VertexId)>,
196 pub mirror_cuts: Vec<MirrorCut>,
198 pub internal_min_cut: f64,
200}
201
202impl HierarchyCluster {
203 pub fn new(id: u64) -> Self {
205 Self {
206 id,
207 preclusters: Vec::new(),
208 vertices: HashSet::new(),
209 boundary_edges: Vec::new(),
210 mirror_cuts: Vec::new(),
211 internal_min_cut: f64::INFINITY,
212 }
213 }
214
215 pub fn add_precluster(&mut self, precluster: &Precluster) {
217 self.preclusters.push(precluster.id);
218 self.vertices.extend(&precluster.vertices);
219 }
220
221 pub fn size(&self) -> usize {
223 self.vertices.len()
224 }
225}
226
227#[derive(Debug)]
229pub struct ThreeLevelHierarchy {
230 config: HierarchyConfig,
232 expanders: HashMap<u64, Expander>,
234 preclusters: HashMap<u64, Precluster>,
236 clusters: HashMap<u64, HierarchyCluster>,
238 vertex_expander: HashMap<VertexId, u64>,
240 next_id: u64,
242 adjacency: HashMap<VertexId, HashMap<VertexId, Weight>>,
244 pub global_min_cut: f64,
246}
247
248impl ThreeLevelHierarchy {
249 pub fn new(config: HierarchyConfig) -> Self {
251 Self {
252 config,
253 expanders: HashMap::new(),
254 preclusters: HashMap::new(),
255 clusters: HashMap::new(),
256 vertex_expander: HashMap::new(),
257 next_id: 1,
258 adjacency: HashMap::new(),
259 global_min_cut: f64::INFINITY,
260 }
261 }
262
263 pub fn with_defaults() -> Self {
265 Self::new(HierarchyConfig::default())
266 }
267
268 pub fn insert_edge(&mut self, u: VertexId, v: VertexId, weight: Weight) {
270 self.adjacency.entry(u).or_default().insert(v, weight);
271 self.adjacency.entry(v).or_default().insert(u, weight);
272 }
273
274 pub fn delete_edge(&mut self, u: VertexId, v: VertexId) {
276 if let Some(neighbors) = self.adjacency.get_mut(&u) {
277 neighbors.remove(&v);
278 }
279 if let Some(neighbors) = self.adjacency.get_mut(&v) {
280 neighbors.remove(&u);
281 }
282 }
283
284 pub fn vertices(&self) -> Vec<VertexId> {
286 self.adjacency.keys().copied().collect()
287 }
288
289 pub fn neighbors(&self, v: VertexId) -> Vec<(VertexId, Weight)> {
291 self.adjacency
292 .get(&v)
293 .map(|n| n.iter().map(|(&v, &w)| (v, w)).collect())
294 .unwrap_or_default()
295 }
296
297 pub fn degree(&self, v: VertexId) -> usize {
299 self.adjacency.get(&v).map_or(0, |n| n.len())
300 }
301
302 pub fn build(&mut self) {
304 let vertices: HashSet<_> = self.vertices().into_iter().collect();
305 if vertices.is_empty() {
306 return;
307 }
308
309 self.build_expanders(&vertices);
311
312 self.build_preclusters();
314
315 self.build_clusters();
317
318 if self.config.track_mirror_cuts {
320 self.compute_mirror_cuts();
321 }
322
323 self.update_global_min_cut();
325 }
326
327 fn build_expanders(&mut self, vertices: &HashSet<VertexId>) {
329 self.expanders.clear();
330 self.vertex_expander.clear();
331
332 let mut remaining: HashSet<_> = vertices.iter().copied().collect();
333
334 while !remaining.is_empty() {
335 let start = *remaining.iter().next().unwrap();
337
338 let expander_vertices = self.grow_expander(start, &remaining);
340
341 if expander_vertices.is_empty() {
342 remaining.remove(&start);
343 continue;
344 }
345
346 let id = self.next_id;
348 self.next_id += 1;
349
350 let mut expander = Expander::new(id, expander_vertices.clone());
351 self.compute_expander_properties(&mut expander);
352
353 for &v in &expander_vertices {
355 self.vertex_expander.insert(v, id);
356 remaining.remove(&v);
357 }
358
359 self.expanders.insert(id, expander);
360 }
361 }
362
363 fn grow_expander(&self, start: VertexId, available: &HashSet<VertexId>) -> HashSet<VertexId> {
365 let mut expander = HashSet::new();
366 let mut queue = VecDeque::new();
367 let mut volume = 0usize;
368
369 queue.push_back(start);
370 expander.insert(start);
371 volume += self.degree(start);
372
373 while let Some(v) = queue.pop_front() {
374 if expander.len() >= self.config.max_expander_size {
375 break;
376 }
377
378 for (neighbor, _) in self.neighbors(v) {
379 if !available.contains(&neighbor) || expander.contains(&neighbor) {
380 continue;
381 }
382
383 let new_volume = volume + self.degree(neighbor);
385 let boundary_after = self.count_boundary(&expander, &[neighbor]);
386
387 let expansion = if new_volume > 0 {
388 boundary_after as f64 / (new_volume.min(expander.len() * 2)) as f64
389 } else {
390 0.0
391 };
392
393 if expansion >= self.config.phi * 0.5
395 || expander.len() < self.config.min_expander_size
396 {
397 expander.insert(neighbor);
398 volume = new_volume;
399 queue.push_back(neighbor);
400 }
401 }
402 }
403
404 expander
405 }
406
407 fn count_boundary(&self, vertices: &HashSet<VertexId>, additional: &[VertexId]) -> usize {
409 let mut full_set = vertices.clone();
410 for &v in additional {
411 full_set.insert(v);
412 }
413
414 let mut boundary = 0;
415 for &v in &full_set {
416 for (neighbor, _) in self.neighbors(v) {
417 if !full_set.contains(&neighbor) {
418 boundary += 1;
419 }
420 }
421 }
422 boundary
423 }
424
425 fn compute_expander_properties(&self, expander: &mut Expander) {
427 let mut internal = Vec::new();
428 let mut boundary = Vec::new();
429 let mut volume = 0;
430
431 for &v in &expander.vertices {
432 let neighbors = self.neighbors(v);
433 volume += neighbors.len();
434
435 for (neighbor, _) in neighbors {
436 if expander.vertices.contains(&neighbor) {
437 if v < neighbor {
438 internal.push((v, neighbor));
439 }
440 } else {
441 boundary.push((v, neighbor));
442 }
443 }
444 }
445
446 expander.internal_edges = internal;
447 expander.boundary_edges = boundary;
448 expander.volume = volume;
449
450 let min_vol = expander.volume.min(expander.vertices.len() * 2);
452 expander.expansion_ratio = if min_vol > 0 {
453 expander.boundary_edges.len() as f64 / min_vol as f64
454 } else {
455 0.0
456 };
457 }
458
459 fn build_preclusters(&mut self) {
461 self.preclusters.clear();
462
463 let expander_ids: Vec<_> = self.expanders.keys().copied().collect();
464 let mut assigned = HashSet::new();
465
466 for &exp_id in &expander_ids {
467 if assigned.contains(&exp_id) {
468 continue;
469 }
470
471 let id = self.next_id;
472 self.next_id += 1;
473
474 let mut precluster = Precluster::new(id);
475
476 if let Some(expander) = self.expanders.get_mut(&exp_id) {
478 precluster.add_expander(expander);
479 expander.precluster_id = Some(id);
480 assigned.insert(exp_id);
481 }
482
483 for &other_id in &expander_ids {
485 if assigned.contains(&other_id) {
486 continue;
487 }
488
489 if precluster.size() >= self.config.target_precluster_size {
490 break;
491 }
492
493 if self.expanders_adjacent(exp_id, other_id) {
495 if let Some(expander) = self.expanders.get_mut(&other_id) {
496 precluster.add_expander(expander);
497 expander.precluster_id = Some(id);
498 assigned.insert(other_id);
499 }
500 }
501 }
502
503 self.compute_precluster_boundary(&mut precluster);
505
506 self.preclusters.insert(id, precluster);
507 }
508 }
509
510 fn expanders_adjacent(&self, exp1: u64, exp2: u64) -> bool {
512 let e1 = match self.expanders.get(&exp1) {
513 Some(e) => e,
514 None => return false,
515 };
516 let e2 = match self.expanders.get(&exp2) {
517 Some(e) => e,
518 None => return false,
519 };
520
521 for &v in &e1.vertices {
523 for (neighbor, _) in self.neighbors(v) {
524 if e2.vertices.contains(&neighbor) {
525 return true;
526 }
527 }
528 }
529 false
530 }
531
532 fn compute_precluster_boundary(&self, precluster: &mut Precluster) {
534 precluster.boundary_edges.clear();
535
536 for &v in &precluster.vertices {
537 for (neighbor, _) in self.neighbors(v) {
538 if !precluster.vertices.contains(&neighbor) {
539 precluster.boundary_edges.push((v, neighbor));
540 }
541 }
542 }
543 }
544
545 fn build_clusters(&mut self) {
547 self.clusters.clear();
548
549 let precluster_ids: Vec<_> = self.preclusters.keys().copied().collect();
550 let mut assigned = HashSet::new();
551
552 for &pre_id in &precluster_ids {
553 if assigned.contains(&pre_id) {
554 continue;
555 }
556
557 let id = self.next_id;
558 self.next_id += 1;
559
560 let mut cluster = HierarchyCluster::new(id);
561
562 if let Some(precluster) = self.preclusters.get_mut(&pre_id) {
564 cluster.add_precluster(precluster);
565 precluster.cluster_id = Some(id);
566 assigned.insert(pre_id);
567 }
568
569 for &other_id in &precluster_ids {
571 if assigned.contains(&other_id) {
572 continue;
573 }
574
575 if self.preclusters_adjacent(pre_id, other_id) {
576 if let Some(precluster) = self.preclusters.get_mut(&other_id) {
577 cluster.add_precluster(precluster);
578 precluster.cluster_id = Some(id);
579 assigned.insert(other_id);
580 }
581 }
582 }
583
584 self.compute_cluster_boundary(&mut cluster);
586
587 self.clusters.insert(id, cluster);
588 }
589 }
590
591 fn preclusters_adjacent(&self, pre1: u64, pre2: u64) -> bool {
593 let p1 = match self.preclusters.get(&pre1) {
594 Some(p) => p,
595 None => return false,
596 };
597 let p2 = match self.preclusters.get(&pre2) {
598 Some(p) => p,
599 None => return false,
600 };
601
602 for &v in &p1.vertices {
603 for (neighbor, _) in self.neighbors(v) {
604 if p2.vertices.contains(&neighbor) {
605 return true;
606 }
607 }
608 }
609 false
610 }
611
612 fn compute_cluster_boundary(&self, cluster: &mut HierarchyCluster) {
614 cluster.boundary_edges.clear();
615
616 for &v in &cluster.vertices {
617 for (neighbor, _) in self.neighbors(v) {
618 if !cluster.vertices.contains(&neighbor) {
619 cluster.boundary_edges.push((v, neighbor));
620 }
621 }
622 }
623 }
624
625 fn compute_mirror_cuts(&mut self) {
627 let expander_ids: Vec<_> = self.expanders.keys().copied().collect();
628
629 for cluster in self.clusters.values_mut() {
630 cluster.mirror_cuts.clear();
631 }
632
633 for (i, &exp1) in expander_ids.iter().enumerate() {
635 for &exp2 in expander_ids.iter().skip(i + 1) {
636 if !self.expanders_adjacent(exp1, exp2) {
637 continue;
638 }
639
640 let (cut_value, cut_edges) = self.compute_expander_cut(exp1, exp2);
642
643 let mirror = MirrorCut {
644 source_expander: exp1,
645 target_expander: exp2,
646 cut_value,
647 cut_edges,
648 certified: false,
649 };
650
651 if let Some(pre_id) = self.expanders.get(&exp1).and_then(|e| e.precluster_id) {
653 if let Some(cluster_id) =
654 self.preclusters.get(&pre_id).and_then(|p| p.cluster_id)
655 {
656 if let Some(cluster) = self.clusters.get_mut(&cluster_id) {
657 cluster.mirror_cuts.push(mirror);
658 }
659 }
660 }
661 }
662 }
663
664 for cluster in self.clusters.values_mut() {
666 if let Some(min_mirror) = cluster
667 .mirror_cuts
668 .iter()
669 .map(|m| m.cut_value)
670 .min_by(|a, b| a.partial_cmp(b).unwrap())
671 {
672 cluster.internal_min_cut = cluster.internal_min_cut.min(min_mirror);
673 }
674 }
675 }
676
677 fn compute_expander_cut(&self, exp1: u64, exp2: u64) -> (f64, Vec<(VertexId, VertexId)>) {
679 let e1 = match self.expanders.get(&exp1) {
680 Some(e) => e,
681 None => return (0.0, Vec::new()),
682 };
683 let e2 = match self.expanders.get(&exp2) {
684 Some(e) => e,
685 None => return (0.0, Vec::new()),
686 };
687
688 let mut cut_edges = Vec::new();
689 let mut cut_value = 0.0;
690
691 for &v in &e1.vertices {
692 for (neighbor, weight) in self.neighbors(v) {
693 if e2.vertices.contains(&neighbor) {
694 cut_edges.push((v, neighbor));
695 cut_value += weight;
696 }
697 }
698 }
699
700 (cut_value, cut_edges)
701 }
702
703 fn update_global_min_cut(&mut self) {
705 let mut min_cut = f64::INFINITY;
706
707 for cluster in self.clusters.values() {
709 let boundary_cut: f64 = cluster
710 .boundary_edges
711 .iter()
712 .map(|&(u, v)| {
713 self.adjacency
714 .get(&u)
715 .and_then(|n| n.get(&v))
716 .copied()
717 .unwrap_or(1.0)
718 })
719 .sum();
720
721 min_cut = min_cut.min(boundary_cut);
722 min_cut = min_cut.min(cluster.internal_min_cut);
723 }
724
725 self.global_min_cut = min_cut;
726 }
727
728 pub fn handle_edge_insert(&mut self, u: VertexId, v: VertexId, weight: Weight) {
738 self.insert_edge(u, v, weight);
740
741 if self.expanders.is_empty() {
743 return;
744 }
745
746 let exp_u = self.vertex_expander.get(&u).copied();
748 let exp_v = self.vertex_expander.get(&v).copied();
749
750 match (exp_u, exp_v) {
751 (Some(eu), Some(ev)) if eu == ev => {
752 self.update_expander_edges(eu);
754 }
755 (Some(eu), Some(ev)) => {
756 self.update_expander_edges(eu);
758 self.update_expander_edges(ev);
759
760 self.update_mirror_cut_between(eu, ev);
762 }
763 (Some(eu), None) => {
764 self.try_add_vertex_to_expander(v, eu);
766 self.update_expander_edges(eu);
767 }
768 (None, Some(ev)) => {
769 self.try_add_vertex_to_expander(u, ev);
771 self.update_expander_edges(ev);
772 }
773 (None, None) => {
774 self.create_expander_for_new_vertices(&[u, v]);
776 }
777 }
778
779 self.propagate_updates(&[u, v]);
781
782 self.update_global_min_cut();
784 }
785
786 pub fn handle_edge_delete(&mut self, u: VertexId, v: VertexId) {
788 self.delete_edge(u, v);
790
791 if self.expanders.is_empty() {
793 return;
794 }
795
796 let exp_u = self.vertex_expander.get(&u).copied();
798 let exp_v = self.vertex_expander.get(&v).copied();
799
800 if let (Some(eu), Some(ev)) = (exp_u, exp_v) {
801 if eu == ev {
802 self.check_and_split_expander(eu);
804 } else {
805 self.update_expander_edges(eu);
807 self.update_expander_edges(ev);
808
809 self.update_mirror_cut_between(eu, ev);
811 }
812 }
813
814 self.propagate_updates(&[u, v]);
816
817 self.update_global_min_cut();
819 }
820
821 fn update_expander_edges(&mut self, exp_id: u64) {
823 let vertices = match self.expanders.get(&exp_id) {
825 Some(e) => e.vertices.clone(),
826 None => return,
827 };
828
829 let mut internal = Vec::new();
830 let mut boundary = Vec::new();
831 let mut volume = 0;
832
833 for &v in &vertices {
834 let neighbors = self.neighbors(v);
835 volume += neighbors.len();
836
837 for (neighbor, _) in neighbors {
838 if vertices.contains(&neighbor) {
839 if v < neighbor {
840 internal.push((v, neighbor));
841 }
842 } else {
843 boundary.push((v, neighbor));
844 }
845 }
846 }
847
848 if let Some(expander) = self.expanders.get_mut(&exp_id) {
850 expander.internal_edges = internal;
851 expander.boundary_edges = boundary;
852 expander.volume = volume;
853
854 let min_vol = volume.min(vertices.len() * 2);
855 expander.expansion_ratio = if min_vol > 0 {
856 expander.boundary_edges.len() as f64 / min_vol as f64
857 } else {
858 0.0
859 };
860 }
861 }
862
863 fn try_add_vertex_to_expander(&mut self, v: VertexId, exp_id: u64) {
865 if let Some(expander) = self.expanders.get(&exp_id) {
867 let new_volume = expander.volume + self.degree(v);
868 let new_boundary = self.count_boundary_with_vertex(exp_id, v);
869
870 let expansion = if new_volume > 0 {
871 new_boundary as f64 / new_volume as f64
872 } else {
873 0.0
874 };
875
876 if expansion >= self.config.phi * 0.5 {
877 if let Some(exp) = self.expanders.get_mut(&exp_id) {
879 exp.vertices.insert(v);
880 self.vertex_expander.insert(v, exp_id);
881 }
882 } else {
883 self.create_expander_for_new_vertices(&[v]);
885 }
886 }
887 }
888
889 fn count_boundary_with_vertex(&self, exp_id: u64, v: VertexId) -> usize {
891 let expander = match self.expanders.get(&exp_id) {
892 Some(e) => e,
893 None => return 0,
894 };
895
896 let mut extended = expander.vertices.clone();
897 extended.insert(v);
898
899 let mut boundary = 0;
900 for &u in &extended {
901 for (neighbor, _) in self.neighbors(u) {
902 if !extended.contains(&neighbor) {
903 boundary += 1;
904 }
905 }
906 }
907 boundary
908 }
909
910 fn create_expander_for_new_vertices(&mut self, vertices: &[VertexId]) {
912 let id = self.next_id;
913 self.next_id += 1;
914
915 let vertex_set: HashSet<_> = vertices.iter().copied().collect();
916 let mut expander = Expander::new(id, vertex_set);
917 self.compute_expander_properties(&mut expander);
918
919 for &v in vertices {
920 self.vertex_expander.insert(v, id);
921 }
922
923 self.expanders.insert(id, expander);
924
925 self.assign_expander_to_precluster(id);
927 }
928
929 fn assign_expander_to_precluster(&mut self, exp_id: u64) {
931 for (pre_id, precluster) in &self.preclusters {
933 for &other_exp in &precluster.expanders {
935 if self.expanders_adjacent(exp_id, other_exp) {
936 if let Some(exp) = self.expanders.get_mut(&exp_id) {
937 exp.precluster_id = Some(*pre_id);
938 }
939 return;
940 }
941 }
942 }
943
944 let id = self.next_id;
946 self.next_id += 1;
947
948 let mut precluster = Precluster::new(id);
949 if let Some(expander) = self.expanders.get_mut(&exp_id) {
950 precluster.add_expander(expander);
951 expander.precluster_id = Some(id);
952 }
953 self.compute_precluster_boundary(&mut precluster);
954 self.preclusters.insert(id, precluster);
955
956 self.assign_precluster_to_cluster(id);
958 }
959
960 fn assign_precluster_to_cluster(&mut self, pre_id: u64) {
962 for (cluster_id, cluster) in &self.clusters {
964 for &other_pre in &cluster.preclusters {
965 if self.preclusters_adjacent(pre_id, other_pre) {
966 if let Some(pre) = self.preclusters.get_mut(&pre_id) {
967 pre.cluster_id = Some(*cluster_id);
968 }
969 return;
970 }
971 }
972 }
973
974 let id = self.next_id;
976 self.next_id += 1;
977
978 let mut cluster = HierarchyCluster::new(id);
979 if let Some(precluster) = self.preclusters.get_mut(&pre_id) {
980 cluster.add_precluster(precluster);
981 precluster.cluster_id = Some(id);
982 }
983 self.compute_cluster_boundary(&mut cluster);
984 self.clusters.insert(id, cluster);
985 }
986
987 fn check_and_split_expander(&mut self, exp_id: u64) {
989 if let Some(expander) = self.expanders.get(&exp_id) {
990 if expander.expansion_ratio < self.config.phi * 0.3 {
992 self.update_expander_edges(exp_id);
994 }
995 }
996 }
997
998 fn update_mirror_cut_between(&mut self, exp1: u64, exp2: u64) {
1000 let (cut_value, cut_edges) = self.compute_expander_cut(exp1, exp2);
1001
1002 let cluster_id = self
1004 .expanders
1005 .get(&exp1)
1006 .and_then(|e| e.precluster_id)
1007 .and_then(|pid| self.preclusters.get(&pid))
1008 .and_then(|p| p.cluster_id);
1009
1010 if let Some(cid) = cluster_id {
1011 if let Some(cluster) = self.clusters.get_mut(&cid) {
1012 let found = cluster.mirror_cuts.iter_mut().find(|m| {
1014 (m.source_expander == exp1 && m.target_expander == exp2)
1015 || (m.source_expander == exp2 && m.target_expander == exp1)
1016 });
1017
1018 if let Some(mirror) = found {
1019 mirror.cut_value = cut_value;
1020 mirror.cut_edges = cut_edges;
1021 } else if !cut_edges.is_empty() {
1022 cluster.mirror_cuts.push(MirrorCut {
1023 source_expander: exp1,
1024 target_expander: exp2,
1025 cut_value,
1026 cut_edges,
1027 certified: false,
1028 });
1029 }
1030
1031 if let Some(min_mirror) = cluster
1033 .mirror_cuts
1034 .iter()
1035 .map(|m| m.cut_value)
1036 .min_by(|a, b| a.partial_cmp(b).unwrap())
1037 {
1038 cluster.internal_min_cut = min_mirror;
1039 }
1040 }
1041 }
1042 }
1043
1044 fn propagate_updates(&mut self, vertices: &[VertexId]) {
1046 let mut affected_expanders = HashSet::new();
1048 for &v in vertices {
1049 if let Some(&exp_id) = self.vertex_expander.get(&v) {
1050 affected_expanders.insert(exp_id);
1051 }
1052 }
1053
1054 let mut affected_preclusters = HashSet::new();
1056 for &exp_id in &affected_expanders {
1057 if let Some(expander) = self.expanders.get(&exp_id) {
1058 if let Some(pre_id) = expander.precluster_id {
1059 affected_preclusters.insert(pre_id);
1060 }
1061 }
1062 }
1063
1064 for &pre_id in &affected_preclusters {
1066 if let Some(precluster) = self.preclusters.get_mut(&pre_id) {
1067 precluster.vertices.clear();
1069 precluster.volume = 0;
1070
1071 for &exp_id in &precluster.expanders {
1072 if let Some(expander) = self.expanders.get(&exp_id) {
1073 precluster.vertices.extend(&expander.vertices);
1074 precluster.volume += expander.volume;
1075 }
1076 }
1077 }
1078
1079 let precluster = self.preclusters.get(&pre_id).cloned();
1081 if let Some(mut pre) = precluster {
1082 self.compute_precluster_boundary(&mut pre);
1083 self.preclusters.insert(pre_id, pre);
1084 }
1085 }
1086
1087 let mut affected_clusters = HashSet::new();
1089 for &pre_id in &affected_preclusters {
1090 if let Some(precluster) = self.preclusters.get(&pre_id) {
1091 if let Some(cluster_id) = precluster.cluster_id {
1092 affected_clusters.insert(cluster_id);
1093 }
1094 }
1095 }
1096
1097 for &cluster_id in &affected_clusters {
1099 if let Some(cluster) = self.clusters.get_mut(&cluster_id) {
1100 cluster.vertices.clear();
1102
1103 for &pre_id in &cluster.preclusters {
1104 if let Some(precluster) = self.preclusters.get(&pre_id) {
1105 cluster.vertices.extend(&precluster.vertices);
1106 }
1107 }
1108 }
1109
1110 let cluster = self.clusters.get(&cluster_id).cloned();
1112 if let Some(mut c) = cluster {
1113 self.compute_cluster_boundary(&mut c);
1114 self.clusters.insert(cluster_id, c);
1115 }
1116 }
1117 }
1118
1119 pub fn certify_mirror_cuts(&mut self) {
1126 use crate::localkcut::deterministic::DeterministicLocalKCut;
1127
1128 let mut certifications: Vec<(u64, usize, bool)> = Vec::new();
1130
1131 for (cluster_id, cluster) in &self.clusters {
1132 for (mirror_idx, mirror) in cluster.mirror_cuts.iter().enumerate() {
1133 let exp1 = match self.expanders.get(&mirror.source_expander) {
1135 Some(e) => e.vertices.clone(),
1136 None => continue,
1137 };
1138 let exp2 = match self.expanders.get(&mirror.target_expander) {
1139 Some(e) => e.vertices.clone(),
1140 None => continue,
1141 };
1142
1143 let combined: HashSet<_> = exp1.union(&exp2).copied().collect();
1145 let lambda_max = (mirror.cut_value.ceil() as u64).max(1) * 2;
1146 let volume = combined.len() * 10; let mut lkc = DeterministicLocalKCut::new(lambda_max, volume, 2);
1149
1150 for &u in &combined {
1152 for (v, w) in self.neighbors(u) {
1153 if combined.contains(&v) && u < v {
1154 lkc.insert_edge(u, v, w);
1155 }
1156 }
1157 }
1158
1159 let mut min_verified_cut = f64::INFINITY;
1161 let boundary_verts: Vec<_> = mirror.cut_edges.iter().map(|(u, _)| *u).collect();
1162
1163 for v in boundary_verts {
1164 let cuts = lkc.query(v);
1165 for cut in cuts {
1166 let cut_separates = {
1168 let in_exp1 = cut.vertices.iter().any(|&u| exp1.contains(&u));
1169 let in_exp2 = cut.vertices.iter().any(|&u| exp2.contains(&u));
1170 let not_in_exp1 = exp1.iter().any(|&u| !cut.vertices.contains(&u));
1171 let not_in_exp2 = exp2.iter().any(|&u| !cut.vertices.contains(&u));
1172 (in_exp1 && not_in_exp2) || (in_exp2 && not_in_exp1)
1173 };
1174
1175 if cut_separates {
1176 min_verified_cut = min_verified_cut.min(cut.cut_value);
1177 }
1178 }
1179 }
1180
1181 let certified = if min_verified_cut < f64::INFINITY {
1183 let diff = (mirror.cut_value - min_verified_cut).abs();
1185 diff < 0.001 || min_verified_cut <= mirror.cut_value
1186 } else {
1187 true
1189 };
1190
1191 certifications.push((*cluster_id, mirror_idx, certified));
1192 }
1193 }
1194
1195 for (cluster_id, mirror_idx, certified) in certifications {
1197 if let Some(cluster) = self.clusters.get_mut(&cluster_id) {
1198 if let Some(mirror) = cluster.mirror_cuts.get_mut(mirror_idx) {
1199 mirror.certified = certified;
1200 }
1201 }
1202 }
1203 }
1204
1205 pub fn num_certified_mirror_cuts(&self) -> usize {
1207 self.clusters
1208 .values()
1209 .flat_map(|c| &c.mirror_cuts)
1210 .filter(|m| m.certified)
1211 .count()
1212 }
1213
1214 pub fn num_mirror_cuts(&self) -> usize {
1216 self.clusters.values().map(|c| c.mirror_cuts.len()).sum()
1217 }
1218
1219 pub fn get_vertex_expander(&self, v: VertexId) -> Option<&Expander> {
1223 self.vertex_expander
1224 .get(&v)
1225 .and_then(|&id| self.expanders.get(&id))
1226 }
1227
1228 pub fn get_expanders(&self) -> &HashMap<u64, Expander> {
1230 &self.expanders
1231 }
1232
1233 pub fn get_preclusters(&self) -> &HashMap<u64, Precluster> {
1235 &self.preclusters
1236 }
1237
1238 pub fn get_clusters(&self) -> &HashMap<u64, HierarchyCluster> {
1240 &self.clusters
1241 }
1242
1243 pub fn stats(&self) -> HierarchyStats {
1245 HierarchyStats {
1246 num_expanders: self.expanders.len(),
1247 num_preclusters: self.preclusters.len(),
1248 num_clusters: self.clusters.len(),
1249 num_vertices: self.adjacency.len(),
1250 num_edges: self.adjacency.values().map(|n| n.len()).sum::<usize>() / 2,
1251 global_min_cut: self.global_min_cut,
1252 avg_expander_size: if self.expanders.is_empty() {
1253 0.0
1254 } else {
1255 self.expanders.values().map(|e| e.size()).sum::<usize>() as f64
1256 / self.expanders.len() as f64
1257 },
1258 }
1259 }
1260}
1261
1262impl Default for ThreeLevelHierarchy {
1263 fn default() -> Self {
1264 Self::with_defaults()
1265 }
1266}
1267
1268#[derive(Debug, Clone)]
1270pub struct HierarchyStats {
1271 pub num_expanders: usize,
1273 pub num_preclusters: usize,
1275 pub num_clusters: usize,
1277 pub num_vertices: usize,
1279 pub num_edges: usize,
1281 pub global_min_cut: f64,
1283 pub avg_expander_size: f64,
1285}
1286
1287#[cfg(test)]
1288mod tests {
1289 use super::*;
1290
1291 fn build_path(h: &mut ThreeLevelHierarchy, n: usize) {
1292 for i in 0..n - 1 {
1293 h.insert_edge(i as u64, (i + 1) as u64, 1.0);
1294 }
1295 }
1296
1297 fn build_clique(h: &mut ThreeLevelHierarchy, vertices: &[u64]) {
1298 for i in 0..vertices.len() {
1299 for j in i + 1..vertices.len() {
1300 h.insert_edge(vertices[i], vertices[j], 1.0);
1301 }
1302 }
1303 }
1304
1305 #[test]
1306 fn test_hierarchy_empty() {
1307 let mut h = ThreeLevelHierarchy::with_defaults();
1308 h.build();
1309 assert_eq!(h.expanders.len(), 0);
1310 assert_eq!(h.preclusters.len(), 0);
1311 assert_eq!(h.clusters.len(), 0);
1312 }
1313
1314 #[test]
1315 fn test_hierarchy_path() {
1316 let mut h = ThreeLevelHierarchy::new(HierarchyConfig {
1317 min_expander_size: 2,
1318 max_expander_size: 5,
1319 ..Default::default()
1320 });
1321 build_path(&mut h, 10);
1322 h.build();
1323
1324 assert!(h.expanders.len() >= 1);
1325 assert!(h.preclusters.len() >= 1);
1326 assert!(h.clusters.len() >= 1);
1327
1328 let stats = h.stats();
1329 assert_eq!(stats.num_vertices, 10);
1330 assert_eq!(stats.num_edges, 9);
1331 }
1332
1333 #[test]
1334 fn test_hierarchy_clique() {
1335 let mut h = ThreeLevelHierarchy::with_defaults();
1336 build_clique(&mut h, &[1, 2, 3, 4, 5]);
1337 h.build();
1338
1339 assert!(h.expanders.len() >= 1);
1341
1342 for v in 1..=5 {
1344 assert!(h.get_vertex_expander(v).is_some());
1345 }
1346 }
1347
1348 #[test]
1349 fn test_hierarchy_two_cliques() {
1350 let mut h = ThreeLevelHierarchy::new(HierarchyConfig {
1351 min_expander_size: 2,
1352 ..Default::default()
1353 });
1354
1355 build_clique(&mut h, &[1, 2, 3, 4]);
1357 build_clique(&mut h, &[5, 6, 7, 8]);
1358 h.insert_edge(4, 5, 1.0); h.build();
1361
1362 assert!(h.expanders.len() >= 1);
1364
1365 assert!(h.global_min_cut <= 2.0);
1367 }
1368
1369 #[test]
1370 fn test_mirror_cuts() {
1371 let mut h = ThreeLevelHierarchy::new(HierarchyConfig {
1372 track_mirror_cuts: true,
1373 min_expander_size: 2,
1374 ..Default::default()
1375 });
1376
1377 build_clique(&mut h, &[1, 2, 3]);
1378 build_clique(&mut h, &[4, 5, 6]);
1379 h.insert_edge(3, 4, 2.0);
1380 h.insert_edge(2, 5, 1.0);
1381
1382 h.build();
1383
1384 let stats = h.stats();
1386 assert!(stats.num_expanders >= 1);
1387 }
1388
1389 #[test]
1390 fn test_expander_properties() {
1391 let mut h = ThreeLevelHierarchy::with_defaults();
1392 build_clique(&mut h, &[1, 2, 3, 4]);
1393 h.build();
1394
1395 for expander in h.expanders.values() {
1396 assert!(expander.size() > 0);
1398 assert!(expander.volume > 0);
1399 }
1400 }
1401
1402 #[test]
1403 fn test_stats() {
1404 let mut h = ThreeLevelHierarchy::with_defaults();
1405 build_path(&mut h, 5);
1406 h.build();
1407
1408 let stats = h.stats();
1409 assert_eq!(stats.num_vertices, 5);
1410 assert_eq!(stats.num_edges, 4);
1411 assert!(stats.avg_expander_size > 0.0);
1412 }
1413
1414 #[test]
1415 fn test_incremental_insert() {
1416 let mut h = ThreeLevelHierarchy::with_defaults();
1417 build_clique(&mut h, &[1, 2, 3, 4]);
1418 h.build();
1419
1420 let initial_expanders = h.expanders.len();
1421
1422 h.handle_edge_insert(4, 5, 1.0);
1424
1425 assert!(h.expanders.len() >= initial_expanders);
1427
1428 let stats = h.stats();
1429 assert!(stats.num_vertices >= 5);
1430 assert!(stats.num_edges >= 7);
1431 }
1432
1433 #[test]
1434 fn test_incremental_delete() {
1435 let mut h = ThreeLevelHierarchy::new(HierarchyConfig {
1436 min_expander_size: 2,
1437 ..Default::default()
1438 });
1439
1440 build_clique(&mut h, &[1, 2, 3]);
1441 build_clique(&mut h, &[4, 5, 6]);
1442 h.insert_edge(3, 4, 1.0); h.build();
1444
1445 let initial_min_cut = h.global_min_cut;
1446
1447 h.handle_edge_delete(3, 4);
1449
1450 assert!(h.global_min_cut <= initial_min_cut || h.global_min_cut.is_infinite());
1452 }
1453
1454 #[test]
1455 fn test_incremental_within_expander() {
1456 let mut h = ThreeLevelHierarchy::with_defaults();
1457 build_clique(&mut h, &[1, 2, 3, 4]);
1458 h.build();
1459
1460 let initial_expanders = h.expanders.len();
1461
1462 h.handle_edge_insert(1, 4, 2.0);
1464
1465 assert_eq!(h.expanders.len(), initial_expanders);
1467 }
1468
1469 #[test]
1470 fn test_propagate_updates() {
1471 let mut h = ThreeLevelHierarchy::new(HierarchyConfig {
1472 min_expander_size: 2,
1473 ..Default::default()
1474 });
1475
1476 build_clique(&mut h, &[1, 2, 3]);
1477 h.build();
1478
1479 h.handle_edge_insert(3, 4, 1.0);
1481 h.handle_edge_insert(4, 5, 1.0);
1482
1483 assert!(h.expanders.len() >= 1);
1485 assert!(h.preclusters.len() >= 1);
1486 assert!(h.clusters.len() >= 1);
1487 }
1488}