1use std::collections::{HashMap, HashSet, VecDeque};
21use crate::graph::{VertexId, Weight};
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.get(&v)
292 .map(|n| n.iter().map(|(&v, &w)| (v, w)).collect())
293 .unwrap_or_default()
294 }
295
296 pub fn degree(&self, v: VertexId) -> usize {
298 self.adjacency.get(&v).map_or(0, |n| n.len())
299 }
300
301 pub fn build(&mut self) {
303 let vertices: HashSet<_> = self.vertices().into_iter().collect();
304 if vertices.is_empty() {
305 return;
306 }
307
308 self.build_expanders(&vertices);
310
311 self.build_preclusters();
313
314 self.build_clusters();
316
317 if self.config.track_mirror_cuts {
319 self.compute_mirror_cuts();
320 }
321
322 self.update_global_min_cut();
324 }
325
326 fn build_expanders(&mut self, vertices: &HashSet<VertexId>) {
328 self.expanders.clear();
329 self.vertex_expander.clear();
330
331 let mut remaining: HashSet<_> = vertices.iter().copied().collect();
332
333 while !remaining.is_empty() {
334 let start = *remaining.iter().next().unwrap();
336
337 let expander_vertices = self.grow_expander(start, &remaining);
339
340 if expander_vertices.is_empty() {
341 remaining.remove(&start);
342 continue;
343 }
344
345 let id = self.next_id;
347 self.next_id += 1;
348
349 let mut expander = Expander::new(id, expander_vertices.clone());
350 self.compute_expander_properties(&mut expander);
351
352 for &v in &expander_vertices {
354 self.vertex_expander.insert(v, id);
355 remaining.remove(&v);
356 }
357
358 self.expanders.insert(id, expander);
359 }
360 }
361
362 fn grow_expander(&self, start: VertexId, available: &HashSet<VertexId>) -> HashSet<VertexId> {
364 let mut expander = HashSet::new();
365 let mut queue = VecDeque::new();
366 let mut volume = 0usize;
367
368 queue.push_back(start);
369 expander.insert(start);
370 volume += self.degree(start);
371
372 while let Some(v) = queue.pop_front() {
373 if expander.len() >= self.config.max_expander_size {
374 break;
375 }
376
377 for (neighbor, _) in self.neighbors(v) {
378 if !available.contains(&neighbor) || expander.contains(&neighbor) {
379 continue;
380 }
381
382 let new_volume = volume + self.degree(neighbor);
384 let boundary_after = self.count_boundary(&expander, &[neighbor]);
385
386 let expansion = if new_volume > 0 {
387 boundary_after as f64 / (new_volume.min(expander.len() * 2)) as f64
388 } else {
389 0.0
390 };
391
392 if expansion >= self.config.phi * 0.5 || expander.len() < self.config.min_expander_size {
394 expander.insert(neighbor);
395 volume = new_volume;
396 queue.push_back(neighbor);
397 }
398 }
399 }
400
401 expander
402 }
403
404 fn count_boundary(&self, vertices: &HashSet<VertexId>, additional: &[VertexId]) -> usize {
406 let mut full_set = vertices.clone();
407 for &v in additional {
408 full_set.insert(v);
409 }
410
411 let mut boundary = 0;
412 for &v in &full_set {
413 for (neighbor, _) in self.neighbors(v) {
414 if !full_set.contains(&neighbor) {
415 boundary += 1;
416 }
417 }
418 }
419 boundary
420 }
421
422 fn compute_expander_properties(&self, expander: &mut Expander) {
424 let mut internal = Vec::new();
425 let mut boundary = Vec::new();
426 let mut volume = 0;
427
428 for &v in &expander.vertices {
429 let neighbors = self.neighbors(v);
430 volume += neighbors.len();
431
432 for (neighbor, _) in neighbors {
433 if expander.vertices.contains(&neighbor) {
434 if v < neighbor {
435 internal.push((v, neighbor));
436 }
437 } else {
438 boundary.push((v, neighbor));
439 }
440 }
441 }
442
443 expander.internal_edges = internal;
444 expander.boundary_edges = boundary;
445 expander.volume = volume;
446
447 let min_vol = expander.volume.min(expander.vertices.len() * 2);
449 expander.expansion_ratio = if min_vol > 0 {
450 expander.boundary_edges.len() as f64 / min_vol as f64
451 } else {
452 0.0
453 };
454 }
455
456 fn build_preclusters(&mut self) {
458 self.preclusters.clear();
459
460 let expander_ids: Vec<_> = self.expanders.keys().copied().collect();
461 let mut assigned = HashSet::new();
462
463 for &exp_id in &expander_ids {
464 if assigned.contains(&exp_id) {
465 continue;
466 }
467
468 let id = self.next_id;
469 self.next_id += 1;
470
471 let mut precluster = Precluster::new(id);
472
473 if let Some(expander) = self.expanders.get_mut(&exp_id) {
475 precluster.add_expander(expander);
476 expander.precluster_id = Some(id);
477 assigned.insert(exp_id);
478 }
479
480 for &other_id in &expander_ids {
482 if assigned.contains(&other_id) {
483 continue;
484 }
485
486 if precluster.size() >= self.config.target_precluster_size {
487 break;
488 }
489
490 if self.expanders_adjacent(exp_id, other_id) {
492 if let Some(expander) = self.expanders.get_mut(&other_id) {
493 precluster.add_expander(expander);
494 expander.precluster_id = Some(id);
495 assigned.insert(other_id);
496 }
497 }
498 }
499
500 self.compute_precluster_boundary(&mut precluster);
502
503 self.preclusters.insert(id, precluster);
504 }
505 }
506
507 fn expanders_adjacent(&self, exp1: u64, exp2: u64) -> bool {
509 let e1 = match self.expanders.get(&exp1) {
510 Some(e) => e,
511 None => return false,
512 };
513 let e2 = match self.expanders.get(&exp2) {
514 Some(e) => e,
515 None => return false,
516 };
517
518 for &v in &e1.vertices {
520 for (neighbor, _) in self.neighbors(v) {
521 if e2.vertices.contains(&neighbor) {
522 return true;
523 }
524 }
525 }
526 false
527 }
528
529 fn compute_precluster_boundary(&self, precluster: &mut Precluster) {
531 precluster.boundary_edges.clear();
532
533 for &v in &precluster.vertices {
534 for (neighbor, _) in self.neighbors(v) {
535 if !precluster.vertices.contains(&neighbor) {
536 precluster.boundary_edges.push((v, neighbor));
537 }
538 }
539 }
540 }
541
542 fn build_clusters(&mut self) {
544 self.clusters.clear();
545
546 let precluster_ids: Vec<_> = self.preclusters.keys().copied().collect();
547 let mut assigned = HashSet::new();
548
549 for &pre_id in &precluster_ids {
550 if assigned.contains(&pre_id) {
551 continue;
552 }
553
554 let id = self.next_id;
555 self.next_id += 1;
556
557 let mut cluster = HierarchyCluster::new(id);
558
559 if let Some(precluster) = self.preclusters.get_mut(&pre_id) {
561 cluster.add_precluster(precluster);
562 precluster.cluster_id = Some(id);
563 assigned.insert(pre_id);
564 }
565
566 for &other_id in &precluster_ids {
568 if assigned.contains(&other_id) {
569 continue;
570 }
571
572 if self.preclusters_adjacent(pre_id, other_id) {
573 if let Some(precluster) = self.preclusters.get_mut(&other_id) {
574 cluster.add_precluster(precluster);
575 precluster.cluster_id = Some(id);
576 assigned.insert(other_id);
577 }
578 }
579 }
580
581 self.compute_cluster_boundary(&mut cluster);
583
584 self.clusters.insert(id, cluster);
585 }
586 }
587
588 fn preclusters_adjacent(&self, pre1: u64, pre2: u64) -> bool {
590 let p1 = match self.preclusters.get(&pre1) {
591 Some(p) => p,
592 None => return false,
593 };
594 let p2 = match self.preclusters.get(&pre2) {
595 Some(p) => p,
596 None => return false,
597 };
598
599 for &v in &p1.vertices {
600 for (neighbor, _) in self.neighbors(v) {
601 if p2.vertices.contains(&neighbor) {
602 return true;
603 }
604 }
605 }
606 false
607 }
608
609 fn compute_cluster_boundary(&self, cluster: &mut HierarchyCluster) {
611 cluster.boundary_edges.clear();
612
613 for &v in &cluster.vertices {
614 for (neighbor, _) in self.neighbors(v) {
615 if !cluster.vertices.contains(&neighbor) {
616 cluster.boundary_edges.push((v, neighbor));
617 }
618 }
619 }
620 }
621
622 fn compute_mirror_cuts(&mut self) {
624 let expander_ids: Vec<_> = self.expanders.keys().copied().collect();
625
626 for cluster in self.clusters.values_mut() {
627 cluster.mirror_cuts.clear();
628 }
629
630 for (i, &exp1) in expander_ids.iter().enumerate() {
632 for &exp2 in expander_ids.iter().skip(i + 1) {
633 if !self.expanders_adjacent(exp1, exp2) {
634 continue;
635 }
636
637 let (cut_value, cut_edges) = self.compute_expander_cut(exp1, exp2);
639
640 let mirror = MirrorCut {
641 source_expander: exp1,
642 target_expander: exp2,
643 cut_value,
644 cut_edges,
645 certified: false,
646 };
647
648 if let Some(pre_id) = self.expanders.get(&exp1).and_then(|e| e.precluster_id) {
650 if let Some(cluster_id) = self.preclusters.get(&pre_id).and_then(|p| p.cluster_id) {
651 if let Some(cluster) = self.clusters.get_mut(&cluster_id) {
652 cluster.mirror_cuts.push(mirror);
653 }
654 }
655 }
656 }
657 }
658
659 for cluster in self.clusters.values_mut() {
661 if let Some(min_mirror) = cluster.mirror_cuts.iter()
662 .map(|m| m.cut_value)
663 .min_by(|a, b| a.partial_cmp(b).unwrap())
664 {
665 cluster.internal_min_cut = cluster.internal_min_cut.min(min_mirror);
666 }
667 }
668 }
669
670 fn compute_expander_cut(&self, exp1: u64, exp2: u64) -> (f64, Vec<(VertexId, VertexId)>) {
672 let e1 = match self.expanders.get(&exp1) {
673 Some(e) => e,
674 None => return (0.0, Vec::new()),
675 };
676 let e2 = match self.expanders.get(&exp2) {
677 Some(e) => e,
678 None => return (0.0, Vec::new()),
679 };
680
681 let mut cut_edges = Vec::new();
682 let mut cut_value = 0.0;
683
684 for &v in &e1.vertices {
685 for (neighbor, weight) in self.neighbors(v) {
686 if e2.vertices.contains(&neighbor) {
687 cut_edges.push((v, neighbor));
688 cut_value += weight;
689 }
690 }
691 }
692
693 (cut_value, cut_edges)
694 }
695
696 fn update_global_min_cut(&mut self) {
698 let mut min_cut = f64::INFINITY;
699
700 for cluster in self.clusters.values() {
702 let boundary_cut: f64 = cluster.boundary_edges.iter()
703 .map(|&(u, v)| {
704 self.adjacency.get(&u)
705 .and_then(|n| n.get(&v))
706 .copied()
707 .unwrap_or(1.0)
708 })
709 .sum();
710
711 min_cut = min_cut.min(boundary_cut);
712 min_cut = min_cut.min(cluster.internal_min_cut);
713 }
714
715 self.global_min_cut = min_cut;
716 }
717
718 pub fn handle_edge_insert(&mut self, u: VertexId, v: VertexId, weight: Weight) {
728 self.insert_edge(u, v, weight);
730
731 if self.expanders.is_empty() {
733 return;
734 }
735
736 let exp_u = self.vertex_expander.get(&u).copied();
738 let exp_v = self.vertex_expander.get(&v).copied();
739
740 match (exp_u, exp_v) {
741 (Some(eu), Some(ev)) if eu == ev => {
742 self.update_expander_edges(eu);
744 }
745 (Some(eu), Some(ev)) => {
746 self.update_expander_edges(eu);
748 self.update_expander_edges(ev);
749
750 self.update_mirror_cut_between(eu, ev);
752 }
753 (Some(eu), None) => {
754 self.try_add_vertex_to_expander(v, eu);
756 self.update_expander_edges(eu);
757 }
758 (None, Some(ev)) => {
759 self.try_add_vertex_to_expander(u, ev);
761 self.update_expander_edges(ev);
762 }
763 (None, None) => {
764 self.create_expander_for_new_vertices(&[u, v]);
766 }
767 }
768
769 self.propagate_updates(&[u, v]);
771
772 self.update_global_min_cut();
774 }
775
776 pub fn handle_edge_delete(&mut self, u: VertexId, v: VertexId) {
778 self.delete_edge(u, v);
780
781 if self.expanders.is_empty() {
783 return;
784 }
785
786 let exp_u = self.vertex_expander.get(&u).copied();
788 let exp_v = self.vertex_expander.get(&v).copied();
789
790 if let (Some(eu), Some(ev)) = (exp_u, exp_v) {
791 if eu == ev {
792 self.check_and_split_expander(eu);
794 } else {
795 self.update_expander_edges(eu);
797 self.update_expander_edges(ev);
798
799 self.update_mirror_cut_between(eu, ev);
801 }
802 }
803
804 self.propagate_updates(&[u, v]);
806
807 self.update_global_min_cut();
809 }
810
811 fn update_expander_edges(&mut self, exp_id: u64) {
813 let vertices = match self.expanders.get(&exp_id) {
815 Some(e) => e.vertices.clone(),
816 None => return,
817 };
818
819 let mut internal = Vec::new();
820 let mut boundary = Vec::new();
821 let mut volume = 0;
822
823 for &v in &vertices {
824 let neighbors = self.neighbors(v);
825 volume += neighbors.len();
826
827 for (neighbor, _) in neighbors {
828 if vertices.contains(&neighbor) {
829 if v < neighbor {
830 internal.push((v, neighbor));
831 }
832 } else {
833 boundary.push((v, neighbor));
834 }
835 }
836 }
837
838 if let Some(expander) = self.expanders.get_mut(&exp_id) {
840 expander.internal_edges = internal;
841 expander.boundary_edges = boundary;
842 expander.volume = volume;
843
844 let min_vol = volume.min(vertices.len() * 2);
845 expander.expansion_ratio = if min_vol > 0 {
846 expander.boundary_edges.len() as f64 / min_vol as f64
847 } else {
848 0.0
849 };
850 }
851 }
852
853 fn try_add_vertex_to_expander(&mut self, v: VertexId, exp_id: u64) {
855 if let Some(expander) = self.expanders.get(&exp_id) {
857 let new_volume = expander.volume + self.degree(v);
858 let new_boundary = self.count_boundary_with_vertex(exp_id, v);
859
860 let expansion = if new_volume > 0 {
861 new_boundary as f64 / new_volume as f64
862 } else {
863 0.0
864 };
865
866 if expansion >= self.config.phi * 0.5 {
867 if let Some(exp) = self.expanders.get_mut(&exp_id) {
869 exp.vertices.insert(v);
870 self.vertex_expander.insert(v, exp_id);
871 }
872 } else {
873 self.create_expander_for_new_vertices(&[v]);
875 }
876 }
877 }
878
879 fn count_boundary_with_vertex(&self, exp_id: u64, v: VertexId) -> usize {
881 let expander = match self.expanders.get(&exp_id) {
882 Some(e) => e,
883 None => return 0,
884 };
885
886 let mut extended = expander.vertices.clone();
887 extended.insert(v);
888
889 let mut boundary = 0;
890 for &u in &extended {
891 for (neighbor, _) in self.neighbors(u) {
892 if !extended.contains(&neighbor) {
893 boundary += 1;
894 }
895 }
896 }
897 boundary
898 }
899
900 fn create_expander_for_new_vertices(&mut self, vertices: &[VertexId]) {
902 let id = self.next_id;
903 self.next_id += 1;
904
905 let vertex_set: HashSet<_> = vertices.iter().copied().collect();
906 let mut expander = Expander::new(id, vertex_set);
907 self.compute_expander_properties(&mut expander);
908
909 for &v in vertices {
910 self.vertex_expander.insert(v, id);
911 }
912
913 self.expanders.insert(id, expander);
914
915 self.assign_expander_to_precluster(id);
917 }
918
919 fn assign_expander_to_precluster(&mut self, exp_id: u64) {
921 for (pre_id, precluster) in &self.preclusters {
923 for &other_exp in &precluster.expanders {
925 if self.expanders_adjacent(exp_id, other_exp) {
926 if let Some(exp) = self.expanders.get_mut(&exp_id) {
927 exp.precluster_id = Some(*pre_id);
928 }
929 return;
930 }
931 }
932 }
933
934 let id = self.next_id;
936 self.next_id += 1;
937
938 let mut precluster = Precluster::new(id);
939 if let Some(expander) = self.expanders.get_mut(&exp_id) {
940 precluster.add_expander(expander);
941 expander.precluster_id = Some(id);
942 }
943 self.compute_precluster_boundary(&mut precluster);
944 self.preclusters.insert(id, precluster);
945
946 self.assign_precluster_to_cluster(id);
948 }
949
950 fn assign_precluster_to_cluster(&mut self, pre_id: u64) {
952 for (cluster_id, cluster) in &self.clusters {
954 for &other_pre in &cluster.preclusters {
955 if self.preclusters_adjacent(pre_id, other_pre) {
956 if let Some(pre) = self.preclusters.get_mut(&pre_id) {
957 pre.cluster_id = Some(*cluster_id);
958 }
959 return;
960 }
961 }
962 }
963
964 let id = self.next_id;
966 self.next_id += 1;
967
968 let mut cluster = HierarchyCluster::new(id);
969 if let Some(precluster) = self.preclusters.get_mut(&pre_id) {
970 cluster.add_precluster(precluster);
971 precluster.cluster_id = Some(id);
972 }
973 self.compute_cluster_boundary(&mut cluster);
974 self.clusters.insert(id, cluster);
975 }
976
977 fn check_and_split_expander(&mut self, exp_id: u64) {
979 if let Some(expander) = self.expanders.get(&exp_id) {
980 if expander.expansion_ratio < self.config.phi * 0.3 {
982 self.update_expander_edges(exp_id);
984 }
985 }
986 }
987
988 fn update_mirror_cut_between(&mut self, exp1: u64, exp2: u64) {
990 let (cut_value, cut_edges) = self.compute_expander_cut(exp1, exp2);
991
992 let cluster_id = self.expanders.get(&exp1)
994 .and_then(|e| e.precluster_id)
995 .and_then(|pid| self.preclusters.get(&pid))
996 .and_then(|p| p.cluster_id);
997
998 if let Some(cid) = cluster_id {
999 if let Some(cluster) = self.clusters.get_mut(&cid) {
1000 let found = cluster.mirror_cuts.iter_mut()
1002 .find(|m| {
1003 (m.source_expander == exp1 && m.target_expander == exp2) ||
1004 (m.source_expander == exp2 && m.target_expander == exp1)
1005 });
1006
1007 if let Some(mirror) = found {
1008 mirror.cut_value = cut_value;
1009 mirror.cut_edges = cut_edges;
1010 } else if !cut_edges.is_empty() {
1011 cluster.mirror_cuts.push(MirrorCut {
1012 source_expander: exp1,
1013 target_expander: exp2,
1014 cut_value,
1015 cut_edges,
1016 certified: false,
1017 });
1018 }
1019
1020 if let Some(min_mirror) = cluster.mirror_cuts.iter()
1022 .map(|m| m.cut_value)
1023 .min_by(|a, b| a.partial_cmp(b).unwrap())
1024 {
1025 cluster.internal_min_cut = min_mirror;
1026 }
1027 }
1028 }
1029 }
1030
1031 fn propagate_updates(&mut self, vertices: &[VertexId]) {
1033 let mut affected_expanders = HashSet::new();
1035 for &v in vertices {
1036 if let Some(&exp_id) = self.vertex_expander.get(&v) {
1037 affected_expanders.insert(exp_id);
1038 }
1039 }
1040
1041 let mut affected_preclusters = HashSet::new();
1043 for &exp_id in &affected_expanders {
1044 if let Some(expander) = self.expanders.get(&exp_id) {
1045 if let Some(pre_id) = expander.precluster_id {
1046 affected_preclusters.insert(pre_id);
1047 }
1048 }
1049 }
1050
1051 for &pre_id in &affected_preclusters {
1053 if let Some(precluster) = self.preclusters.get_mut(&pre_id) {
1054 precluster.vertices.clear();
1056 precluster.volume = 0;
1057
1058 for &exp_id in &precluster.expanders {
1059 if let Some(expander) = self.expanders.get(&exp_id) {
1060 precluster.vertices.extend(&expander.vertices);
1061 precluster.volume += expander.volume;
1062 }
1063 }
1064 }
1065
1066 let precluster = self.preclusters.get(&pre_id).cloned();
1068 if let Some(mut pre) = precluster {
1069 self.compute_precluster_boundary(&mut pre);
1070 self.preclusters.insert(pre_id, pre);
1071 }
1072 }
1073
1074 let mut affected_clusters = HashSet::new();
1076 for &pre_id in &affected_preclusters {
1077 if let Some(precluster) = self.preclusters.get(&pre_id) {
1078 if let Some(cluster_id) = precluster.cluster_id {
1079 affected_clusters.insert(cluster_id);
1080 }
1081 }
1082 }
1083
1084 for &cluster_id in &affected_clusters {
1086 if let Some(cluster) = self.clusters.get_mut(&cluster_id) {
1087 cluster.vertices.clear();
1089
1090 for &pre_id in &cluster.preclusters {
1091 if let Some(precluster) = self.preclusters.get(&pre_id) {
1092 cluster.vertices.extend(&precluster.vertices);
1093 }
1094 }
1095 }
1096
1097 let cluster = self.clusters.get(&cluster_id).cloned();
1099 if let Some(mut c) = cluster {
1100 self.compute_cluster_boundary(&mut c);
1101 self.clusters.insert(cluster_id, c);
1102 }
1103 }
1104 }
1105
1106 pub fn certify_mirror_cuts(&mut self) {
1113 use crate::localkcut::deterministic::DeterministicLocalKCut;
1114
1115 let mut certifications: Vec<(u64, usize, bool)> = Vec::new();
1117
1118 for (cluster_id, cluster) in &self.clusters {
1119 for (mirror_idx, mirror) in cluster.mirror_cuts.iter().enumerate() {
1120 let exp1 = match self.expanders.get(&mirror.source_expander) {
1122 Some(e) => e.vertices.clone(),
1123 None => continue,
1124 };
1125 let exp2 = match self.expanders.get(&mirror.target_expander) {
1126 Some(e) => e.vertices.clone(),
1127 None => continue,
1128 };
1129
1130 let combined: HashSet<_> = exp1.union(&exp2).copied().collect();
1132 let lambda_max = (mirror.cut_value.ceil() as u64).max(1) * 2;
1133 let volume = combined.len() * 10; let mut lkc = DeterministicLocalKCut::new(lambda_max, volume, 2);
1136
1137 for &u in &combined {
1139 for (v, w) in self.neighbors(u) {
1140 if combined.contains(&v) && u < v {
1141 lkc.insert_edge(u, v, w);
1142 }
1143 }
1144 }
1145
1146 let mut min_verified_cut = f64::INFINITY;
1148 let boundary_verts: Vec<_> = mirror.cut_edges.iter().map(|(u, _)| *u).collect();
1149
1150 for v in boundary_verts {
1151 let cuts = lkc.query(v);
1152 for cut in cuts {
1153 let cut_separates = {
1155 let in_exp1 = cut.vertices.iter().any(|&u| exp1.contains(&u));
1156 let in_exp2 = cut.vertices.iter().any(|&u| exp2.contains(&u));
1157 let not_in_exp1 = exp1.iter().any(|&u| !cut.vertices.contains(&u));
1158 let not_in_exp2 = exp2.iter().any(|&u| !cut.vertices.contains(&u));
1159 (in_exp1 && not_in_exp2) || (in_exp2 && not_in_exp1)
1160 };
1161
1162 if cut_separates {
1163 min_verified_cut = min_verified_cut.min(cut.cut_value);
1164 }
1165 }
1166 }
1167
1168 let certified = if min_verified_cut < f64::INFINITY {
1170 let diff = (mirror.cut_value - min_verified_cut).abs();
1172 diff < 0.001 || min_verified_cut <= mirror.cut_value
1173 } else {
1174 true
1176 };
1177
1178 certifications.push((*cluster_id, mirror_idx, certified));
1179 }
1180 }
1181
1182 for (cluster_id, mirror_idx, certified) in certifications {
1184 if let Some(cluster) = self.clusters.get_mut(&cluster_id) {
1185 if let Some(mirror) = cluster.mirror_cuts.get_mut(mirror_idx) {
1186 mirror.certified = certified;
1187 }
1188 }
1189 }
1190 }
1191
1192 pub fn num_certified_mirror_cuts(&self) -> usize {
1194 self.clusters.values()
1195 .flat_map(|c| &c.mirror_cuts)
1196 .filter(|m| m.certified)
1197 .count()
1198 }
1199
1200 pub fn num_mirror_cuts(&self) -> usize {
1202 self.clusters.values()
1203 .map(|c| c.mirror_cuts.len())
1204 .sum()
1205 }
1206
1207 pub fn get_vertex_expander(&self, v: VertexId) -> Option<&Expander> {
1211 self.vertex_expander.get(&v)
1212 .and_then(|&id| self.expanders.get(&id))
1213 }
1214
1215 pub fn get_expanders(&self) -> &HashMap<u64, Expander> {
1217 &self.expanders
1218 }
1219
1220 pub fn get_preclusters(&self) -> &HashMap<u64, Precluster> {
1222 &self.preclusters
1223 }
1224
1225 pub fn get_clusters(&self) -> &HashMap<u64, HierarchyCluster> {
1227 &self.clusters
1228 }
1229
1230 pub fn stats(&self) -> HierarchyStats {
1232 HierarchyStats {
1233 num_expanders: self.expanders.len(),
1234 num_preclusters: self.preclusters.len(),
1235 num_clusters: self.clusters.len(),
1236 num_vertices: self.adjacency.len(),
1237 num_edges: self.adjacency.values()
1238 .map(|n| n.len())
1239 .sum::<usize>() / 2,
1240 global_min_cut: self.global_min_cut,
1241 avg_expander_size: if self.expanders.is_empty() {
1242 0.0
1243 } else {
1244 self.expanders.values()
1245 .map(|e| e.size())
1246 .sum::<usize>() as f64 / self.expanders.len() as f64
1247 },
1248 }
1249 }
1250}
1251
1252impl Default for ThreeLevelHierarchy {
1253 fn default() -> Self {
1254 Self::with_defaults()
1255 }
1256}
1257
1258#[derive(Debug, Clone)]
1260pub struct HierarchyStats {
1261 pub num_expanders: usize,
1263 pub num_preclusters: usize,
1265 pub num_clusters: usize,
1267 pub num_vertices: usize,
1269 pub num_edges: usize,
1271 pub global_min_cut: f64,
1273 pub avg_expander_size: f64,
1275}
1276
1277#[cfg(test)]
1278mod tests {
1279 use super::*;
1280
1281 fn build_path(h: &mut ThreeLevelHierarchy, n: usize) {
1282 for i in 0..n-1 {
1283 h.insert_edge(i as u64, (i + 1) as u64, 1.0);
1284 }
1285 }
1286
1287 fn build_clique(h: &mut ThreeLevelHierarchy, vertices: &[u64]) {
1288 for i in 0..vertices.len() {
1289 for j in i+1..vertices.len() {
1290 h.insert_edge(vertices[i], vertices[j], 1.0);
1291 }
1292 }
1293 }
1294
1295 #[test]
1296 fn test_hierarchy_empty() {
1297 let mut h = ThreeLevelHierarchy::with_defaults();
1298 h.build();
1299 assert_eq!(h.expanders.len(), 0);
1300 assert_eq!(h.preclusters.len(), 0);
1301 assert_eq!(h.clusters.len(), 0);
1302 }
1303
1304 #[test]
1305 fn test_hierarchy_path() {
1306 let mut h = ThreeLevelHierarchy::new(HierarchyConfig {
1307 min_expander_size: 2,
1308 max_expander_size: 5,
1309 ..Default::default()
1310 });
1311 build_path(&mut h, 10);
1312 h.build();
1313
1314 assert!(h.expanders.len() >= 1);
1315 assert!(h.preclusters.len() >= 1);
1316 assert!(h.clusters.len() >= 1);
1317
1318 let stats = h.stats();
1319 assert_eq!(stats.num_vertices, 10);
1320 assert_eq!(stats.num_edges, 9);
1321 }
1322
1323 #[test]
1324 fn test_hierarchy_clique() {
1325 let mut h = ThreeLevelHierarchy::with_defaults();
1326 build_clique(&mut h, &[1, 2, 3, 4, 5]);
1327 h.build();
1328
1329 assert!(h.expanders.len() >= 1);
1331
1332 for v in 1..=5 {
1334 assert!(h.get_vertex_expander(v).is_some());
1335 }
1336 }
1337
1338 #[test]
1339 fn test_hierarchy_two_cliques() {
1340 let mut h = ThreeLevelHierarchy::new(HierarchyConfig {
1341 min_expander_size: 2,
1342 ..Default::default()
1343 });
1344
1345 build_clique(&mut h, &[1, 2, 3, 4]);
1347 build_clique(&mut h, &[5, 6, 7, 8]);
1348 h.insert_edge(4, 5, 1.0); h.build();
1351
1352 assert!(h.expanders.len() >= 1);
1354
1355 assert!(h.global_min_cut <= 2.0);
1357 }
1358
1359 #[test]
1360 fn test_mirror_cuts() {
1361 let mut h = ThreeLevelHierarchy::new(HierarchyConfig {
1362 track_mirror_cuts: true,
1363 min_expander_size: 2,
1364 ..Default::default()
1365 });
1366
1367 build_clique(&mut h, &[1, 2, 3]);
1368 build_clique(&mut h, &[4, 5, 6]);
1369 h.insert_edge(3, 4, 2.0);
1370 h.insert_edge(2, 5, 1.0);
1371
1372 h.build();
1373
1374 let stats = h.stats();
1376 assert!(stats.num_expanders >= 1);
1377 }
1378
1379 #[test]
1380 fn test_expander_properties() {
1381 let mut h = ThreeLevelHierarchy::with_defaults();
1382 build_clique(&mut h, &[1, 2, 3, 4]);
1383 h.build();
1384
1385 for expander in h.expanders.values() {
1386 assert!(expander.size() > 0);
1388 assert!(expander.volume > 0);
1389 }
1390 }
1391
1392 #[test]
1393 fn test_stats() {
1394 let mut h = ThreeLevelHierarchy::with_defaults();
1395 build_path(&mut h, 5);
1396 h.build();
1397
1398 let stats = h.stats();
1399 assert_eq!(stats.num_vertices, 5);
1400 assert_eq!(stats.num_edges, 4);
1401 assert!(stats.avg_expander_size > 0.0);
1402 }
1403
1404 #[test]
1405 fn test_incremental_insert() {
1406 let mut h = ThreeLevelHierarchy::with_defaults();
1407 build_clique(&mut h, &[1, 2, 3, 4]);
1408 h.build();
1409
1410 let initial_expanders = h.expanders.len();
1411
1412 h.handle_edge_insert(4, 5, 1.0);
1414
1415 assert!(h.expanders.len() >= initial_expanders);
1417
1418 let stats = h.stats();
1419 assert!(stats.num_vertices >= 5);
1420 assert!(stats.num_edges >= 7);
1421 }
1422
1423 #[test]
1424 fn test_incremental_delete() {
1425 let mut h = ThreeLevelHierarchy::new(HierarchyConfig {
1426 min_expander_size: 2,
1427 ..Default::default()
1428 });
1429
1430 build_clique(&mut h, &[1, 2, 3]);
1431 build_clique(&mut h, &[4, 5, 6]);
1432 h.insert_edge(3, 4, 1.0); h.build();
1434
1435 let initial_min_cut = h.global_min_cut;
1436
1437 h.handle_edge_delete(3, 4);
1439
1440 assert!(h.global_min_cut <= initial_min_cut || h.global_min_cut.is_infinite());
1442 }
1443
1444 #[test]
1445 fn test_incremental_within_expander() {
1446 let mut h = ThreeLevelHierarchy::with_defaults();
1447 build_clique(&mut h, &[1, 2, 3, 4]);
1448 h.build();
1449
1450 let initial_expanders = h.expanders.len();
1451
1452 h.handle_edge_insert(1, 4, 2.0);
1454
1455 assert_eq!(h.expanders.len(), initial_expanders);
1457 }
1458
1459 #[test]
1460 fn test_propagate_updates() {
1461 let mut h = ThreeLevelHierarchy::new(HierarchyConfig {
1462 min_expander_size: 2,
1463 ..Default::default()
1464 });
1465
1466 build_clique(&mut h, &[1, 2, 3]);
1467 h.build();
1468
1469 h.handle_edge_insert(3, 4, 1.0);
1471 h.handle_edge_insert(4, 5, 1.0);
1472
1473 assert!(h.expanders.len() >= 1);
1475 assert!(h.preclusters.len() >= 1);
1476 assert!(h.clusters.len() >= 1);
1477 }
1478}