1#![allow(dead_code)]
2
3use crate::{cff::hsurface::Hsurface, graph::Graph};
4use ahash::{HashMap, HashSet, HashSetExt};
5
6use color_eyre::Result;
7use eyre::eyre;
8use itertools::Itertools;
9use linnet::half_edge::{
10 HedgeGraph, NodeIndex,
11 involution::{EdgeIndex, EdgeVec, Flow, HedgePair, Orientation},
12 subgraph::{Inclusion, ModifySubSet, SuBitGraph, SubGraphLike},
13};
14use serde::{Deserialize, Serialize};
15use std::hash::Hash;
16
17use super::{
18 esurface::{Esurface, ExternalShift},
19 surface::{HybridSurface, UnitSurface},
20};
21
22const MAX_VERTEX_COUNT: usize = 64;
23
24#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
25pub struct CFFVertex {
26 pub vertex_set: VertexSet,
27 pub incoming_edges: Vec<CFFEdge>,
28 pub outgoing_edges: Vec<CFFEdge>,
29}
30
31impl CFFVertex {
32 pub fn new(id: usize) -> Self {
33 let vertex_set = VertexSet::from_usize(id);
34
35 CFFVertex {
36 vertex_set,
37 incoming_edges: Vec::new(),
38 outgoing_edges: Vec::new(),
39 }
40 }
41
42 fn get_vertex_type(&self) -> VertexType {
43 let is_sink = self
44 .outgoing_edges
45 .iter()
46 .all(|edge| edge.edge_type != CFFEdgeType::Virtual);
47
48 let is_source = self
49 .incoming_edges
50 .iter()
51 .all(|edge| edge.edge_type != CFFEdgeType::Virtual);
52
53 if is_sink {
54 VertexType::Sink
55 } else if is_source {
56 VertexType::Source
57 } else {
58 VertexType::None
59 }
60 }
61
62 fn generates_esurface(&self) -> bool {
63 let vertex_type = self.get_vertex_type();
64
65 match vertex_type {
66 VertexType::None => false,
67 VertexType::Sink => self
68 .outgoing_edges
69 .iter()
70 .all(|edge| edge.edge_type == CFFEdgeType::External),
71 VertexType::Source => self
72 .incoming_edges
73 .iter()
74 .all(|edge| edge.edge_type == CFFEdgeType::External),
75 }
76 }
77
78 fn contract(&self, other: &Self, remove_single_edge: Option<EdgeIndex>) -> Self {
79 let new_vertex_set = self.vertex_set.join(&other.vertex_set);
80
81 let incoming_edges_of_new = self
82 .incoming_edges
83 .iter()
84 .filter(|edge| {
85 if let Some(edge_to_be_removed) = remove_single_edge {
86 edge.edge_id != edge_to_be_removed
87 } else {
88 !other.outgoing_edges.contains(edge)
89 }
90 })
91 .chain(other.incoming_edges.iter().filter(|edge| {
92 if let Some(edge_to_be_removed) = remove_single_edge {
93 edge.edge_id != edge_to_be_removed
94 } else {
95 !self.outgoing_edges.contains(edge)
96 }
97 }))
98 .copied()
99 .sorted_by(|edge_1, edge_2| edge_1.edge_id.cmp(&edge_2.edge_id))
100 .collect_vec();
101
102 let outgoing_edges_of_new = self
103 .outgoing_edges
104 .iter()
105 .filter(|edge| {
106 if let Some(edge_to_be_removed) = remove_single_edge {
107 edge.edge_id != edge_to_be_removed
108 } else {
109 !other.incoming_edges.contains(edge)
110 }
111 })
112 .chain(other.outgoing_edges.iter().filter(|edge| {
113 if let Some(edge_to_be_removed) = remove_single_edge {
114 edge.edge_id != edge_to_be_removed
115 } else {
116 !self.incoming_edges.contains(edge)
117 }
118 }))
119 .copied()
120 .sorted_by(|edge_1, edge_2| edge_1.edge_id.cmp(&edge_2.edge_id))
121 .collect_vec();
122
123 CFFVertex {
124 vertex_set: new_vertex_set,
125 incoming_edges: incoming_edges_of_new,
126 outgoing_edges: outgoing_edges_of_new,
127 }
128 }
129
130 fn iter_all_edges(&self) -> impl Iterator<Item = &CFFEdge> {
131 self.incoming_edges.iter().chain(self.outgoing_edges.iter())
132 }
133
134 fn iter_all_edges_mut(&mut self) -> impl Iterator<Item = &mut CFFEdge> {
135 self.incoming_edges
136 .iter_mut()
137 .chain(self.outgoing_edges.iter_mut())
138 }
139
140 fn has_impossible_edge(&self) -> bool {
141 let mut dedup_outgoing = self.outgoing_edges.clone();
142 dedup_outgoing.dedup();
143 let mut dedup_incoming = self.incoming_edges.clone();
144 dedup_incoming.dedup();
145
146 dedup_incoming.len() != self.incoming_edges.len()
147 || dedup_outgoing.len() != self.outgoing_edges.len()
148 }
149
150 fn has_edge(&self, edge_id: EdgeIndex) -> bool {
151 self.iter_all_edges().any(|edge| edge.edge_id == edge_id)
152 }
153}
154
155#[derive(
156 Clone,
157 Copy,
158 Debug,
159 PartialEq,
160 Eq,
161 Hash,
162 Serialize,
163 Deserialize,
164 bincode::Encode,
165 bincode::Decode,
166)]
167pub struct VertexSet {
168 vertex_set: u64,
169}
170
171impl VertexSet {
172 pub(crate) fn from_usize(id: usize) -> Self {
173 assert!(id < MAX_VERTEX_COUNT, "Vertex ID out of bounds");
174
175 VertexSet {
176 vertex_set: 1 << id,
177 }
178 }
179
180 pub(crate) fn join(&self, other: &VertexSet) -> VertexSet {
181 VertexSet {
182 vertex_set: self.vertex_set | other.vertex_set,
183 }
184 }
185
186 fn contains_vertices(&self) -> Vec<VertexSet> {
187 (0..MAX_VERTEX_COUNT)
188 .filter(|id| self.vertex_set & (1 << id) != 0)
189 .map(VertexSet::from_usize)
190 .collect()
191 }
192
193 fn get_nodes(&self) -> Vec<NodeIndex> {
194 (0..MAX_VERTEX_COUNT)
195 .filter(|id| self.vertex_set & (1 << id) != 0)
196 .map(NodeIndex::from)
197 .collect()
198 }
199
200 pub(crate) fn subgraph<E, V, H>(&self, graph: &HedgeGraph<E, V, H>) -> SuBitGraph {
201 let mut result: SuBitGraph = graph.empty_subgraph();
202 for hedge in self
203 .get_nodes()
204 .iter()
205 .flat_map(|node_id| graph.iter_crown(*node_id))
206 {
207 result.add(hedge);
208 }
209 result
210 }
211
212 pub(crate) fn dummy() -> Self {
213 VertexSet { vertex_set: 0 }
214 }
215}
216
217#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
218pub struct CFFEdge {
219 pub edge_id: EdgeIndex,
220 pub edge_type: CFFEdgeType,
221}
222
223#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
224pub enum CFFEdgeType {
225 External,
226 Virtual,
227 VirtualExternal,
228}
229
230#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
231enum VertexType {
232 Source,
233 Sink,
234 None,
235}
236
237#[derive(Clone, Debug, Serialize, Deserialize)]
238pub struct CFFGenerationGraph {
239 pub vertices: Vec<CFFVertex>,
240 pub global_orientation: EdgeVec<Orientation>,
241}
242
243impl PartialEq for CFFGenerationGraph {
244 fn eq(&self, other: &Self) -> bool {
245 self.vertices == other.vertices
246 }
247}
248
249impl Eq for CFFGenerationGraph {}
250
251impl Hash for CFFGenerationGraph {
252 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
253 self.vertices.hash(state);
254 }
255}
256
257impl CFFGenerationGraph {
258 pub(crate) fn num_virtual_edges(&self) -> usize {
259 let mut unique_edges = HashSet::default();
260 for vertex in self.vertices.iter() {
261 for edge in vertex.iter_all_edges() {
262 if edge.edge_type == CFFEdgeType::Virtual {
263 unique_edges.insert(edge.edge_id);
264 }
265 }
266 }
267
268 unique_edges.len()
269 }
270 fn has_impossible_edge(&self) -> bool {
271 self.vertices
272 .iter()
273 .any(|vertex| vertex.has_impossible_edge())
274 }
275
276 fn get_vertex(&self, vertex_set: &VertexSet) -> &CFFVertex {
277 self.vertices
278 .iter()
279 .find(|node| node.vertex_set == *vertex_set)
280 .unwrap_or_else(|| panic!("Vertex not found"))
281 }
282
283 fn are_directed_adjacent(&self, left: &VertexSet, right: &VertexSet) -> bool {
284 let left_vertex = self.get_vertex(left);
285 let right_vertex = self.get_vertex(right);
286
287 left_vertex
288 .outgoing_edges
289 .iter()
290 .filter(|edge| edge.edge_type == CFFEdgeType::Virtual)
291 .any(|outgoing_edge| {
292 right_vertex
293 .incoming_edges
294 .iter()
295 .filter(|edge| edge.edge_type == CFFEdgeType::Virtual)
296 .any(|right_incoming| right_incoming.edge_id == outgoing_edge.edge_id)
297 })
298 }
299
300 fn are_adjacent(&self, vertex_1: &VertexSet, vertex_2: &VertexSet) -> bool {
301 self.are_directed_adjacent(vertex_1, vertex_2)
302 || self.are_directed_adjacent(vertex_2, vertex_1)
303 }
304
305 #[cfg(test)]
307 pub(crate) fn from_vec(
308 edges: Vec<(usize, usize)>,
309 incoming_vertices: Vec<(usize, CFFEdgeType)>,
310 orientation: Option<EdgeVec<Orientation>>,
311 ) -> Self {
312 use crate::utils::test_utils;
313
314 let total_num_edges = edges.len() + incoming_vertices.len();
315
316 let edges = edges
317 .into_iter()
318 .map(|(from, to)| (VertexSet::from_usize(from), VertexSet::from_usize(to)))
319 .collect_vec();
320
321 let mut unique_vertex_ids = HashSet::new();
322
323 for edge in edges.iter() {
324 unique_vertex_ids.insert(edge.0);
325 unique_vertex_ids.insert(edge.1);
326 }
327
328 let mut unique_vertices = HashMap::default();
329
330 for vertex in unique_vertex_ids.iter() {
331 let cff_vertex = CFFVertex {
332 vertex_set: *vertex,
333 incoming_edges: Vec::new(),
334 outgoing_edges: Vec::new(),
335 };
336
337 unique_vertices.insert(*vertex, cff_vertex);
338 }
339
340 for (edge_id, (incoming_vertex, edge_type)) in incoming_vertices.iter().enumerate() {
341 assert_ne!(*edge_type, CFFEdgeType::Virtual);
342
343 let vertex_set = VertexSet::from_usize(*incoming_vertex);
344 let cff_vertex = unique_vertices.get_mut(&vertex_set).unwrap();
345 let incoming_edge = CFFEdge {
346 edge_id: EdgeIndex::from(edge_id),
347 edge_type: *edge_type,
348 };
349 cff_vertex.incoming_edges.push(incoming_edge);
350 }
351
352 for (edge_id, (left, right)) in edges.iter().enumerate() {
353 let edge_id = edge_id + incoming_vertices.len();
354 let cff_edge = CFFEdge {
355 edge_id: EdgeIndex::from(edge_id),
356 edge_type: CFFEdgeType::Virtual,
357 };
358
359 let left_vertex = unique_vertices.get_mut(left).unwrap();
360 left_vertex.outgoing_edges.push(cff_edge);
361
362 let right_vertex = unique_vertices.get_mut(right).unwrap();
363 right_vertex.incoming_edges.push(cff_edge);
364 }
365
366 let nodes = unique_vertices.into_values().collect_vec();
367 let global_orientation = match orientation {
368 Some(orientation) => orientation,
369 None => test_utils::dummy_hedge_graph(total_num_edges)
370 .new_edgevec_from_iter(vec![Orientation::Default; total_num_edges])
371 .unwrap(),
372 };
373
374 CFFGenerationGraph {
375 vertices: nodes,
376 global_orientation,
377 }
378 }
379
380 fn get_vertex_that_is_not_v(&self, vertex: &VertexSet) -> &CFFVertex {
381 self.vertices
382 .iter()
383 .find(|node| node.vertex_set != *vertex)
384 .unwrap_or_else(|| panic!("Could not find vertex that is not v"))
385 }
386
387 fn get_directed_neighbours(&self, vertex: &VertexSet) -> Vec<&CFFVertex> {
388 let outgoing_of_vertex = self
389 .get_vertex(vertex)
390 .outgoing_edges
391 .iter()
392 .filter(|edge| edge.edge_type == CFFEdgeType::Virtual);
393
394 outgoing_of_vertex
395 .filter_map(|edge| {
396 self.vertices
397 .iter()
398 .find(|node| node.incoming_edges.contains(edge))
399 })
400 .collect()
401 }
402
403 fn get_undirected_neighbours(&self, vertex: &VertexSet) -> Vec<&CFFVertex> {
404 self.vertices
405 .iter()
406 .filter(|other_vertex| {
407 self.are_adjacent(vertex, &other_vertex.vertex_set)
408 && other_vertex.vertex_set != *vertex
409 })
410 .collect()
411 }
412
413 fn remove_edge(&mut self, edge_id: EdgeIndex) {
414 for vertex in self.vertices.iter_mut() {
415 vertex.incoming_edges.retain(|edge| edge.edge_id != edge_id);
416 vertex.outgoing_edges.retain(|edge| edge.edge_id != edge_id);
417 }
418 }
419
420 pub(crate) fn remove_self_edges(&mut self) {
421 let self_edges = self.get_self_edges();
422
423 for self_edge in self_edges.iter() {
424 self.remove_edge(*self_edge);
425 }
426 }
427
428 pub(crate) fn get_self_edges(&self) -> Vec<EdgeIndex> {
429 let mut self_edges = vec![];
430
431 for vertex in self.vertices.iter() {
432 for edge in vertex.incoming_edges.iter() {
433 if vertex.outgoing_edges.contains(edge) {
434 self_edges.push(edge.edge_id);
435 }
436 }
437 }
438
439 self_edges
440 }
441
442 fn depth_first_search(
443 &self,
444 vertex: &VertexSet,
445 visited: &mut HashSet<VertexSet>,
446 stack: &mut Vec<VertexSet>,
447 ) -> bool {
448 if visited.contains(vertex) {
449 return stack.contains(vertex);
450 }
451
452 visited.insert(*vertex);
453 stack.push(*vertex);
454
455 let neighbours = self.get_directed_neighbours(vertex);
456 for neighbour in neighbours.iter() {
457 if self.depth_first_search(&neighbour.vertex_set, visited, stack) {
458 return true;
459 }
460 }
461
462 stack.pop();
463 false
464 }
465
466 fn has_directed_cycle(&self, seed_vertex: &VertexSet) -> bool {
467 let mut visited = HashSet::new();
468 let mut stack = Vec::new();
469
470 self.depth_first_search(seed_vertex, &mut visited, &mut stack)
471 }
472
473 pub(crate) fn has_directed_cycle_initial(&self) -> bool {
474 self.vertices
475 .iter()
476 .any(|vertex| self.has_directed_cycle(&vertex.vertex_set))
477 }
478
479 fn has_connected_complement(&self, vertex: &VertexSet) -> bool {
480 if self.vertices.len() == 1 {
481 return true;
482 }
483
484 let vertex_that_is_not_v = self.get_vertex_that_is_not_v(vertex);
485
486 let mut current_vertices = HashSet::default();
487 current_vertices.insert(vertex_that_is_not_v.vertex_set);
488
489 let mut visited_vertices = HashSet::default();
490 visited_vertices.insert(&vertex_that_is_not_v.vertex_set);
491
492 let mut vertices_found_in_previous_iteration = HashSet::default();
493 let mut delta = 1;
494
495 while delta > 0 {
496 delta = 0; for current_vertex in current_vertices.iter() {
499 for adjacent_vertex in self
500 .get_undirected_neighbours(current_vertex)
501 .iter()
502 .filter(|v| v.vertex_set != *vertex)
503 {
504 if visited_vertices.insert(&adjacent_vertex.vertex_set) {
505 delta += 1;
506 vertices_found_in_previous_iteration.insert(adjacent_vertex.vertex_set);
507 }
508 }
509 }
510
511 std::mem::swap(
514 &mut current_vertices,
515 &mut vertices_found_in_previous_iteration,
516 );
517 vertices_found_in_previous_iteration.clear();
518 }
519
520 visited_vertices.len() == self.vertices.len() - 1
521 }
522
523 #[cfg(test)]
524 fn get_vertex_type(&self, vertex: &VertexSet) -> VertexType {
525 let vertex = self.get_vertex(vertex);
526 vertex.get_vertex_type()
527 }
528
529 fn is_valid_source_or_sink(&self, vertex: VertexSet) -> bool {
530 let vertex = self.get_vertex(&vertex);
531 let vertex_type = vertex.get_vertex_type();
532 if vertex_type == VertexType::None {
533 return false;
534 }
535
536 self.has_connected_complement(&vertex.vertex_set)
537 }
538
539 #[allow(unused)]
540 fn get_source_sink_candidate_list(&self) -> Vec<&CFFVertex> {
541 self.vertices
542 .iter()
543 .filter(|vertex| {
544 let vertex_type = vertex.get_vertex_type();
545 let has_connected_complement = self.has_connected_complement(&vertex.vertex_set);
546 (vertex_type == VertexType::Sink || vertex_type == VertexType::Source)
547 && has_connected_complement
548 })
549 .collect()
550 }
551
552 #[allow(unused)]
553 fn get_source_sink_greedy(&self) -> Option<&CFFVertex> {
554 self.vertices.iter().find(|vertex| {
555 let vertex_type = vertex.get_vertex_type();
556 if vertex_type != VertexType::Sink && vertex_type != VertexType::Source {
557 false
558 } else {
559 self.has_connected_complement(&vertex.vertex_set)
560 }
561 })
562 }
563
564 fn contract_vertices(&self, vertex_1: &VertexSet, vertex_2: &VertexSet) -> Self {
565 self.contract_vertices_impl(vertex_1, vertex_2, None)
566 }
567
568 pub(crate) fn contract_edge(&self, edge_id: EdgeIndex) -> Self {
569 let (source, sink) = self.get_source_sink_of_edge(edge_id);
570 let vertex_1 = &source.vertex_set;
571 let vertex_2 = &sink.vertex_set;
572
573 if vertex_1 == vertex_2 {
575 let mut new_graph = self.clone();
576 new_graph.remove_edge(edge_id);
577 return new_graph;
578 }
579
580 self.contract_vertices_impl(vertex_1, vertex_2, Some(edge_id))
581 }
582
583 fn contract_vertices_impl(
584 &self,
585 vertex_1: &VertexSet,
586 vertex_2: &VertexSet,
587 remove_single_edge: Option<EdgeIndex>,
588 ) -> Self {
589 let vertex_1 = self.get_vertex(vertex_1);
590 let vertex_2 = self.get_vertex(vertex_2);
591
592 let new_vertex = vertex_1.contract(vertex_2, remove_single_edge);
593
594 let mut new_vertices = self.vertices.clone();
595
596 new_vertices.retain(|vertex| vertex.vertex_set != vertex_1.vertex_set);
597 new_vertices.retain(|vertex| vertex.vertex_set != vertex_2.vertex_set);
598 new_vertices.push(new_vertex);
599 new_vertices.shrink_to_fit();
600 new_vertices.sort_by_key(|vertex| vertex.vertex_set.vertex_set);
601
602 CFFGenerationGraph {
603 vertices: new_vertices,
604 global_orientation: self.global_orientation.clone(),
605 }
606 }
607
608 #[allow(unused)]
609 fn get_source_or_sink_slow(&self) -> &CFFVertex {
610 let mut source_sink_candidates = self.get_source_sink_candidate_list();
611
612 source_sink_candidates.sort_by_key(|a| a.vertex_set.vertex_set);
613
614 if source_sink_candidates.is_empty() {
615 panic!("No source or sink candidates found for graph {:#?}", self);
616 }
617
618 source_sink_candidates[0]
619 }
620
621 #[allow(unused)]
622 fn get_source_or_sink_smart(&self, vertices_used: &mut Vec<VertexSet>) -> &CFFVertex {
623 let mut vertices_checked = vec![];
624
625 for vertex in vertices_used.iter() {
626 if !self.vertices.iter().any(|v| v.vertex_set == *vertex) {
627 continue;
628 }
629
630 let neighbours_of_vertex = self.get_undirected_neighbours(vertex);
631
632 for candidate in neighbours_of_vertex.iter() {
633 if vertices_checked.contains(&candidate.vertex_set) {
634 continue;
635 } else {
636 let is_valid = self.is_valid_source_or_sink(candidate.vertex_set);
637 if is_valid {
638 vertices_used.push(candidate.vertex_set);
639 return candidate;
640 } else {
641 vertices_checked.push(candidate.vertex_set);
642 }
643 }
644 }
645 }
646
647 for vertex in self.vertices.iter() {
648 if vertices_used.contains(&vertex.vertex_set) {
649 continue;
650 }
651
652 let is_valid = self.is_valid_source_or_sink(vertex.vertex_set);
653 if is_valid {
654 return vertex;
655 }
656 }
657
658 panic!("No source or sink candidates found for graph {:#?}", self);
659 }
660
661 #[allow(unused)]
662 fn get_vertex_with_conn_complement(&self) -> &CFFVertex {
663 self.vertices
664 .iter()
665 .find(|vertex| self.has_connected_complement(&vertex.vertex_set))
666 .unwrap_or_else(|| panic!("Could not find vertex with connected complement"))
667 }
668
669 fn get_source_sink_of_edge(&self, edge_id: EdgeIndex) -> (&CFFVertex, &CFFVertex) {
670 let source = self
671 .vertices
672 .iter()
673 .find(|vertex| {
674 vertex
675 .outgoing_edges
676 .iter()
677 .any(|edge| edge.edge_id == edge_id)
678 })
679 .expect("not a virtual edge");
680
681 let sink = self
682 .vertices
683 .iter()
684 .find(|vertex| {
685 vertex
686 .incoming_edges
687 .iter()
688 .any(|edge| edge.edge_id == edge_id)
689 })
690 .expect("not a virtual edge");
691
692 (source, sink)
693 }
694
695 pub(crate) fn generate_children(&self) -> (Option<Vec<Self>>, HybridSurface) {
696 if self.vertices.len() < 2 {
697 return (None, HybridSurface::Unit(UnitSurface {}));
698 }
699
700 let vertex = if let Some(vertex) = self.get_source_sink_greedy() {
701 vertex
702 } else {
703 panic!(
704 "could not find vertex to contract from for graph {:#?}",
705 self
706 );
707 };
708
709 let vertex_type = vertex.get_vertex_type();
710
711 let external_shift: ExternalShift = vertex
712 .incoming_edges
713 .iter()
714 .filter(|edge| edge.edge_type == CFFEdgeType::External)
715 .map(|edge| {
716 let edge_id = edge.edge_id;
717 let shift_sign = match vertex_type {
718 VertexType::Source => -1,
719 VertexType::Sink => 1,
720 VertexType::None => panic!("vertex is not a source or a sink"),
721 };
722 (edge_id, shift_sign)
723 })
724 .chain(
725 vertex
726 .outgoing_edges
727 .iter()
728 .filter(|edge| edge.edge_type == CFFEdgeType::External)
729 .map(|edge| {
730 let edge_id = edge.edge_id;
731 let shift_sign = match vertex_type {
732 VertexType::Source => 1,
733 VertexType::Sink => -1,
734 VertexType::None => panic!("vertex is not a source or a sink"),
735 };
736 (edge_id, shift_sign)
737 }),
738 )
739 .sorted_by(|(edge_1, _), (edge_2, _)| edge_1.cmp(edge_2))
740 .collect_vec();
741
742 let positive_energies = vertex
743 .incoming_edges
744 .iter()
745 .chain(vertex.outgoing_edges.iter())
746 .filter(|edge| edge.edge_type == CFFEdgeType::Virtual)
747 .map(|edge| edge.edge_id)
748 .sorted()
749 .collect_vec();
750
751 let surface = if vertex.generates_esurface() {
752 let mut extra_positive_energies = vertex
753 .iter_all_edges()
754 .filter(|edge| edge.edge_type == CFFEdgeType::VirtualExternal)
755 .map(|edge| edge.edge_id)
756 .collect();
757
758 let mut positive_energies = positive_energies;
759 positive_energies.append(&mut extra_positive_energies);
760 positive_energies.sort();
761
762 let esurface = Esurface {
763 energies: positive_energies,
764 external_shift,
765 vertex_set: vertex.vertex_set,
766 };
768
769 HybridSurface::Esurface(esurface)
770 } else {
771 let (mut extra_positive_energies, mut negative_energies) = match vertex_type {
772 VertexType::Sink => (
773 vertex
774 .incoming_edges
775 .iter()
776 .filter(|edge| edge.edge_type == CFFEdgeType::VirtualExternal)
777 .map(|edge| edge.edge_id)
778 .collect(),
779 vertex
780 .outgoing_edges
781 .iter()
782 .filter(|edge| edge.edge_type == CFFEdgeType::VirtualExternal)
783 .map(|edge| edge.edge_id)
784 .collect_vec(),
785 ),
786 VertexType::Source => (
787 vertex
788 .outgoing_edges
789 .iter()
790 .filter(|edge| edge.edge_type == CFFEdgeType::VirtualExternal)
791 .map(|edge| edge.edge_id)
792 .collect(),
793 vertex
794 .incoming_edges
795 .iter()
796 .filter(|edge| edge.edge_type == CFFEdgeType::VirtualExternal)
797 .map(|edge| edge.edge_id)
798 .collect_vec(),
799 ),
800 VertexType::None => {
801 unreachable!()
802 }
803 };
804
805 let mut positive_energies = positive_energies;
806 positive_energies.append(&mut extra_positive_energies);
807 positive_energies.sort();
808
809 negative_energies.sort();
810
811 let hsurface = Hsurface {
812 positive_energies,
813 negative_energies,
814 external_shift,
815 vertex_set: vertex.vertex_set,
816 };
817
818 HybridSurface::Hsurface(hsurface)
819 };
820
821 if self.vertices.len() > 2 {
822 let adjacent_vertices = self.get_undirected_neighbours(&vertex.vertex_set);
823
824 let children = adjacent_vertices
825 .iter()
826 .map(|adjacent_vertex| {
827 let contracted =
828 self.contract_vertices(&vertex.vertex_set, &adjacent_vertex.vertex_set);
829 let new_vertex_set = vertex.vertex_set.join(&adjacent_vertex.vertex_set);
830 (contracted, new_vertex_set)
831 })
832 .filter(|(graph, new_vertex_set)| !graph.has_directed_cycle(new_vertex_set))
833 .map(|(graph, _)| graph)
834 .collect_vec();
835
836 (Some(children), surface)
837 } else {
838 (None, surface)
839 }
840 }
841
842 pub(crate) fn apply_orientation(&mut self, orientation: EdgeVec<Orientation>) -> Result<()> {
844 for (edge_id, &edge_orientation) in orientation.iter() {
845 if edge_orientation == Orientation::Reversed {
846 for vertex in self.vertices.iter_mut() {
847 if let Some(edge) = vertex
848 .outgoing_edges
849 .iter()
850 .find(|edge| edge.edge_id == edge_id)
851 .cloned()
852 {
853 vertex.outgoing_edges.retain(|e| e.edge_id != edge_id);
854 vertex.incoming_edges.push(edge);
855 } else if let Some(edge) = vertex
856 .incoming_edges
857 .iter()
858 .find(|edge| edge.edge_id == edge_id)
859 .cloned()
860 {
861 vertex.incoming_edges.retain(|e| e.edge_id != edge_id);
862 vertex.outgoing_edges.push(edge);
863 }
864 }
865 }
866 }
867
868 self.global_orientation = orientation;
869 Ok(())
870 }
871
872 pub(crate) fn new_from_graph(graph: &Graph) -> Self {
873 let mut vertices = (0..graph.n_nodes()).map(CFFVertex::new).collect_vec();
874 let global_orientation = graph.new_edgevec(|_, _, _| Orientation::Default);
875
876 for (hedge_pair, edge_id, edge_data) in graph.iter_edges() {
877 if edge_data.data.is_dummy {
878 continue; }
880
881 match hedge_pair {
882 HedgePair::Unpaired { hedge, flow } => {
883 let vertex = Into::<usize>::into(graph.node_id(hedge));
884 let edge_type = CFFEdgeType::External;
885 let edge = CFFEdge { edge_id, edge_type };
886 match flow {
887 Flow::Source => {
888 vertices[vertex].outgoing_edges.push(edge);
889 }
890 Flow::Sink => {
891 vertices[vertex].incoming_edges.push(edge);
892 }
893 }
894 }
895 HedgePair::Paired { source, sink } => {
896 let mut edge_subgraph: SuBitGraph = graph.empty_subgraph();
897 edge_subgraph.add(source);
898 edge_subgraph.add(sink);
899
900 let is_is_cut_edge = graph.initial_state_cut.intersects(&edge_subgraph);
901
902 let source_vertex = Into::<usize>::into(graph.node_id(source));
903 let sink_vertex = Into::<usize>::into(graph.node_id(sink));
904 let edge_type = if is_is_cut_edge {
905 CFFEdgeType::External
906 } else {
907 CFFEdgeType::Virtual
908 };
909 let edge = CFFEdge { edge_id, edge_type };
910
911 vertices[source_vertex].outgoing_edges.push(edge);
912 vertices[sink_vertex].incoming_edges.push(edge);
913 }
914 HedgePair::Split { .. } => unreachable!(),
915 }
916 }
917
918 Self {
919 vertices,
920 global_orientation,
921 }
922 }
923
924 pub(crate) fn new<E, V, H>(
926 graph: &HedgeGraph<E, V, H>,
927 global_orientation: EdgeVec<Orientation>,
928 dummy_edges: &[EdgeIndex],
929 ) -> Self {
930 let mut vertices = (0..graph.n_nodes()).map(CFFVertex::new).collect_vec();
931
932 for (hedge_pair, edge_id, _) in graph.iter_edges() {
933 if dummy_edges.contains(&edge_id) {
934 continue; }
936
937 match hedge_pair {
938 HedgePair::Unpaired { hedge, flow } => {
939 let vertex = Into::<usize>::into(graph.node_id(hedge));
940 let edge_type = CFFEdgeType::External;
941 let edge = CFFEdge { edge_id, edge_type };
942 match flow {
943 Flow::Source => {
944 vertices[vertex].outgoing_edges.push(edge);
945 }
946 Flow::Sink => {
947 vertices[vertex].incoming_edges.push(edge);
948 }
949 }
950 }
951 HedgePair::Paired { source, sink } => {
952 let source_vertex = Into::<usize>::into(graph.node_id(source));
953 let sink_vertex = Into::<usize>::into(graph.node_id(sink));
954 let edge_type = CFFEdgeType::Virtual;
955 let edge = CFFEdge { edge_id, edge_type };
956
957 match global_orientation[edge_id] {
958 Orientation::Default => {
959 vertices[source_vertex].outgoing_edges.push(edge);
960 vertices[sink_vertex].incoming_edges.push(edge);
961 }
962 Orientation::Reversed => {
963 vertices[source_vertex].incoming_edges.push(edge);
964 vertices[sink_vertex].outgoing_edges.push(edge);
965 }
966 Orientation::Undirected => {
967 panic!("Can not generate CFF with undirected edges")
968 }
969 }
970 }
971 HedgePair::Split { .. } => unreachable!(),
972 }
973 }
974
975 Self {
976 vertices,
977 global_orientation,
978 }
979 }
980
981 pub(crate) fn new_from_subgraph<E, V, H, S: SubGraphLike>(
982 graph: &HedgeGraph<E, V, H>,
983 global_orientation: EdgeVec<Orientation>,
984 subgraph: &S,
985 ) -> Result<Self> {
986 let mut vertices = HashMap::default();
987
988 for (node_id, _, _data) in graph.iter_nodes_of(subgraph) {
989 let vertex = CFFVertex::new(node_id.into());
990 vertices.insert(node_id, vertex);
991 }
992
993 for (hedge_pair, edge_index, _data) in graph.iter_edges_of(subgraph) {
994 match hedge_pair {
995 HedgePair::Unpaired { hedge, flow } => {
996 let vertex = graph.node_id(hedge);
997 let edge_type = CFFEdgeType::External;
998 let edge = CFFEdge {
999 edge_id: edge_index,
1000 edge_type,
1001 };
1002 match flow {
1003 Flow::Source => {
1004 vertices.get_mut(&vertex).unwrap().outgoing_edges.push(edge);
1005 }
1006 Flow::Sink => {
1007 vertices.get_mut(&vertex).unwrap().incoming_edges.push(edge);
1008 }
1009 }
1010 }
1011 HedgePair::Paired { source, sink } => {
1012 let source_vertex = graph.node_id(source);
1013 let sink_vertex = graph.node_id(sink);
1014 let edge_type = CFFEdgeType::Virtual;
1015 let edge = CFFEdge {
1016 edge_id: edge_index,
1017 edge_type,
1018 };
1019
1020 match global_orientation[edge_index] {
1021 Orientation::Default => {
1022 vertices
1023 .get_mut(&source_vertex)
1024 .unwrap()
1025 .outgoing_edges
1026 .push(edge);
1027 vertices
1028 .get_mut(&sink_vertex)
1029 .unwrap()
1030 .incoming_edges
1031 .push(edge);
1032 }
1033 Orientation::Reversed => {
1034 vertices
1035 .get_mut(&source_vertex)
1036 .unwrap()
1037 .incoming_edges
1038 .push(edge);
1039 vertices
1040 .get_mut(&sink_vertex)
1041 .unwrap()
1042 .outgoing_edges
1043 .push(edge);
1044 }
1045 Orientation::Undirected => {
1046 return Err(eyre!(
1047 "undirected edge found, edge_id: {}, subgraph: \n {}",
1048 edge_index,
1049 graph.dot(subgraph)
1050 ));
1051 }
1052 }
1053 }
1054 HedgePair::Split {
1055 source,
1056 sink,
1057 split,
1058 } => {
1059 let edge_type = CFFEdgeType::VirtualExternal;
1060 let edge = CFFEdge {
1061 edge_id: edge_index,
1062 edge_type,
1063 };
1064 match split {
1065 Flow::Source => {
1066 let vertex = graph.node_id(source);
1067 match global_orientation[edge_index] {
1068 Orientation::Default => {
1069 vertices.get_mut(&vertex).unwrap().outgoing_edges.push(edge)
1070 }
1071 Orientation::Reversed => {
1072 vertices.get_mut(&vertex).unwrap().incoming_edges.push(edge)
1073 }
1074 Orientation::Undirected => {
1075 return Err(eyre!(
1076 "undirected edge found for source split, edge_id: {}, subgraph: \n {}",
1077 edge_index,
1078 graph.dot(subgraph)
1079 ));
1080 }
1081 }
1082 }
1083 Flow::Sink => {
1084 let vertex = graph.node_id(sink);
1085 match global_orientation[edge_index] {
1086 Orientation::Default => {
1087 vertices.get_mut(&vertex).unwrap().incoming_edges.push(edge)
1088 }
1089 Orientation::Reversed => {
1090 vertices.get_mut(&vertex).unwrap().outgoing_edges.push(edge)
1091 }
1092 Orientation::Undirected => {
1093 return Err(eyre!(
1094 "undirected edge found for sink split, edge_id: {}, subgraph: \n {}",
1095 edge_index,
1096 graph.dot(subgraph)
1097 ));
1098 }
1099 }
1100 }
1101 }
1102 }
1103 }
1104 }
1105
1106 let vertices = vertices
1107 .into_values()
1108 .sorted_by(|a, b| a.vertex_set.vertex_set.cmp(&b.vertex_set.vertex_set))
1109 .collect_vec();
1110
1111 let res = Self {
1112 vertices,
1113 global_orientation,
1114 };
1115
1116 Ok(res)
1117 }
1118
1119 pub(crate) fn generate_cut(&self, circled_vertices: VertexSet) -> (Self, Self) {
1120 let vertices_in_cut = circled_vertices.contains_vertices();
1121 let mut vertices = self.vertices.clone();
1122
1123 let mut left = vec![];
1124
1125 for vertex_in_cut in vertices_in_cut.iter() {
1126 let vertex_position = vertices
1127 .iter()
1128 .position(|vertex| vertex.vertex_set == *vertex_in_cut)
1129 .unwrap();
1130
1131 left.push(vertices.remove(vertex_position));
1132 }
1133
1134 let mut left_graph = CFFGenerationGraph {
1135 vertices: left,
1136 global_orientation: self.global_orientation.clone(),
1137 };
1138
1139 let mut right_graph = CFFGenerationGraph {
1140 vertices,
1141 global_orientation: self.global_orientation.clone(),
1142 };
1143
1144 let edges_of_left_graph = left_graph.get_edges();
1145
1146 let cut_edges = edges_of_left_graph
1147 .iter()
1148 .filter(|&&edge_id| right_graph.has_edge(edge_id))
1149 .copied()
1150 .collect_vec();
1151
1152 left_graph
1153 .iter_all_edges_mut()
1154 .chain(right_graph.iter_all_edges_mut())
1155 .filter(|edge| cut_edges.contains(&edge.edge_id))
1156 .for_each(|edge_to_edit| edge_to_edit.edge_type = CFFEdgeType::VirtualExternal);
1157
1158 (left_graph, right_graph)
1159 }
1160
1161 fn get_edges(&self) -> Vec<EdgeIndex> {
1162 let mut unique_edges = vec![];
1163
1164 for vertex in self.vertices.iter() {
1165 for edge in vertex.iter_all_edges() {
1166 if !unique_edges.contains(&edge.edge_id) {
1167 unique_edges.push(edge.edge_id)
1168 }
1169 }
1170 }
1171
1172 unique_edges.sort();
1174 unique_edges
1175 }
1176
1177 #[cfg(test)]
1178 fn iter_all_edges(&self) -> impl Iterator<Item = &CFFEdge> {
1180 self.vertices
1181 .iter()
1182 .flat_map(|vertex| vertex.iter_all_edges())
1183 }
1184
1185 fn iter_all_edges_mut(&mut self) -> impl Iterator<Item = &mut CFFEdge> {
1186 self.vertices
1187 .iter_mut()
1188 .flat_map(|vertex| vertex.iter_all_edges_mut())
1189 }
1190
1191 fn has_edge(&self, edge_id: EdgeIndex) -> bool {
1192 self.vertices.iter().any(|vertex| vertex.has_edge(edge_id))
1193 }
1194}
1195
1196#[cfg(test)]
1197mod test {
1198 use super::CFFGenerationGraph;
1199 use crate::cff::cff_graph::{CFFEdge, CFFEdgeType, VertexSet};
1200 use itertools::Itertools;
1201 use linnet::half_edge::{
1202 HedgeGraph,
1203 builder::HedgeGraphBuilder,
1204 involution::{EdgeIndex, Flow, Orientation},
1205 nodestore::NodeStorageVec,
1206 subgraph::{SuBitGraph, SubSetOps},
1207 };
1208
1209 #[test]
1210 fn test_graph_struct_triangle() {
1211 let triangle = vec![(0, 1), (1, 2), (2, 0)];
1212 let incoming_vertices = vec![
1213 (0, CFFEdgeType::External),
1214 (1, CFFEdgeType::External),
1215 (2, CFFEdgeType::External),
1216 ];
1217
1218 let vertex_sets = [
1219 VertexSet::from_usize(0),
1220 VertexSet::from_usize(1),
1221 VertexSet::from_usize(2),
1222 ];
1223
1224 let cff_triangle = CFFGenerationGraph::from_vec(triangle, incoming_vertices, None);
1225
1226 assert_eq!(cff_triangle.vertices.len(), 3);
1227 println!("node count test passed");
1228
1229 assert!(cff_triangle.are_adjacent(&vertex_sets[0], &vertex_sets[1]));
1230 assert!(cff_triangle.are_adjacent(&vertex_sets[1], &vertex_sets[2]));
1231 assert!(cff_triangle.are_adjacent(&vertex_sets[2], &vertex_sets[0]));
1232
1233 assert!(cff_triangle.are_adjacent(&vertex_sets[1], &vertex_sets[0]));
1234 assert!(cff_triangle.are_adjacent(&vertex_sets[2], &vertex_sets[1]));
1235 assert!(cff_triangle.are_adjacent(&vertex_sets[0], &vertex_sets[2]));
1236
1237 println!("Adjacency test passed");
1238
1239 assert!(cff_triangle.are_directed_adjacent(&vertex_sets[0], &vertex_sets[1]));
1240 assert!(cff_triangle.are_directed_adjacent(&vertex_sets[1], &vertex_sets[2]));
1241 assert!(cff_triangle.are_directed_adjacent(&vertex_sets[2], &vertex_sets[0]));
1242
1243 assert!(!cff_triangle.are_directed_adjacent(&vertex_sets[1], &vertex_sets[0]));
1244 assert!(!cff_triangle.are_directed_adjacent(&vertex_sets[2], &vertex_sets[1]));
1245 assert!(!cff_triangle.are_directed_adjacent(&vertex_sets[0], &vertex_sets[2]));
1246
1247 println!("Directed adjacency test passed");
1248 }
1249
1250 #[test]
1251 fn test_graph_struct_with_virtext() {
1252 let line = vec![(0, 1)];
1253 let incoming_vertices = vec![
1254 (0, CFFEdgeType::VirtualExternal),
1255 (0, CFFEdgeType::External),
1256 (1, CFFEdgeType::VirtualExternal),
1257 (1, CFFEdgeType::External),
1258 ];
1259
1260 let vertex_sets = [VertexSet::from_usize(0), VertexSet::from_usize(1)];
1261
1262 let cff_line = CFFGenerationGraph::from_vec(line, incoming_vertices, None);
1263 assert_eq!(cff_line.vertices.len(), 2);
1264
1265 assert!(cff_line.are_adjacent(&vertex_sets[0], &vertex_sets[1]));
1266 assert!(cff_line.are_directed_adjacent(&vertex_sets[0], &vertex_sets[1]));
1267 assert!(!cff_line.are_directed_adjacent(&vertex_sets[1], &vertex_sets[0]));
1268
1269 assert_eq!(cff_line.get_edges().len(), 5);
1270 }
1271
1272 #[test]
1273 fn test_graph_struct_double_box() {
1274 let double_box = vec![(0, 1), (4, 5), (2, 3), (0, 4), (4, 2), (1, 5), (5, 3)];
1275 let incoming_vertices = (0..4).map(|i| (i, CFFEdgeType::External)).collect_vec();
1276
1277 let v = (0..=5).map(VertexSet::from_usize).collect::<Vec<_>>();
1278
1279 let cff_double_box = CFFGenerationGraph::from_vec(double_box, incoming_vertices, None);
1280
1281 assert_eq!(cff_double_box.vertices.len(), 6);
1282 println!("node count test passed");
1283
1284 assert!(cff_double_box.are_adjacent(&v[0], &v[1]));
1285 assert!(cff_double_box.are_adjacent(&v[1], &v[0]));
1286 assert!(cff_double_box.are_adjacent(&v[4], &v[5]));
1287 assert!(cff_double_box.are_adjacent(&v[5], &v[4]));
1288 assert!(cff_double_box.are_adjacent(&v[2], &v[3]));
1289 assert!(cff_double_box.are_adjacent(&v[3], &v[2]));
1290 assert!(cff_double_box.are_adjacent(&v[0], &v[4]));
1291 assert!(cff_double_box.are_adjacent(&v[4], &v[0]));
1292 assert!(cff_double_box.are_adjacent(&v[4], &v[2]));
1293 assert!(cff_double_box.are_adjacent(&v[2], &v[4]));
1294 assert!(cff_double_box.are_adjacent(&v[1], &v[5]));
1295 assert!(cff_double_box.are_adjacent(&v[5], &v[1]));
1296 assert!(cff_double_box.are_adjacent(&v[5], &v[3]));
1297 assert!(cff_double_box.are_adjacent(&v[3], &v[5]));
1298
1299 assert!(!cff_double_box.are_adjacent(&v[0], &v[2]));
1300 assert!(!cff_double_box.are_adjacent(&v[0], &v[3]));
1301 assert!(!cff_double_box.are_adjacent(&v[0], &v[5]));
1302 assert!(!cff_double_box.are_adjacent(&v[1], &v[2]));
1303 assert!(!cff_double_box.are_adjacent(&v[1], &v[3]));
1304 assert!(!cff_double_box.are_adjacent(&v[1], &v[4]));
1305 println!("Adjacency test passed");
1308
1309 assert!(cff_double_box.are_directed_adjacent(&v[0], &v[1]));
1310 assert!(cff_double_box.are_directed_adjacent(&v[4], &v[5]));
1311 assert!(cff_double_box.are_directed_adjacent(&v[2], &v[3]));
1312 assert!(cff_double_box.are_directed_adjacent(&v[0], &v[4]));
1313 assert!(cff_double_box.are_directed_adjacent(&v[4], &v[2]));
1314 assert!(cff_double_box.are_directed_adjacent(&v[1], &v[5]));
1315 assert!(cff_double_box.are_directed_adjacent(&v[5], &v[3]));
1316
1317 assert!(!cff_double_box.are_directed_adjacent(&v[1], &v[0]));
1318 assert!(!cff_double_box.are_directed_adjacent(&v[5], &v[4]));
1319 assert!(!cff_double_box.are_directed_adjacent(&v[3], &v[2]));
1320 assert!(!cff_double_box.are_directed_adjacent(&v[4], &v[0]));
1321 assert!(!cff_double_box.are_directed_adjacent(&v[2], &v[4]));
1322 assert!(!cff_double_box.are_directed_adjacent(&v[5], &v[1]));
1323 assert!(!cff_double_box.are_directed_adjacent(&v[3], &v[5]));
1324
1325 println!("Directed adjacency test passed");
1326 }
1327
1328 #[test]
1329 fn test_vertex_that_is_not_v() {
1330 let triangle = vec![(0, 1), (1, 2), (2, 0)];
1331 let incoming_vertices = (0..3).map(|i| (i, CFFEdgeType::External)).collect_vec();
1332
1333 let vertex_sets = [
1334 VertexSet::from_usize(0),
1335 VertexSet::from_usize(1),
1336 VertexSet::from_usize(2),
1337 ];
1338
1339 let cff_triangle = CFFGenerationGraph::from_vec(triangle, incoming_vertices, None);
1340 let other_vertex = cff_triangle.get_vertex_that_is_not_v(&vertex_sets[0]);
1341 assert_ne!(other_vertex.vertex_set, vertex_sets[0]);
1342 }
1343
1344 #[test]
1345 fn test_get_directed_neighbours() {
1346 let triangle = vec![(0, 1), (1, 2), (2, 0)];
1347 let incoming_vertices = (0..3).map(|i| (i, CFFEdgeType::External)).collect_vec();
1348 let vertex_sets = [
1349 VertexSet::from_usize(0),
1350 VertexSet::from_usize(1),
1351 VertexSet::from_usize(2),
1352 ];
1353
1354 let cff_triangle = CFFGenerationGraph::from_vec(triangle, incoming_vertices, None);
1355
1356 let neighbours = cff_triangle.get_directed_neighbours(&vertex_sets[0]);
1357 assert_eq!(neighbours.len(), 1);
1358 assert_eq!(neighbours[0].vertex_set, vertex_sets[1]);
1359 }
1360
1361 #[test]
1362
1363 fn test_has_directed_cycle() {
1364 let triangle = vec![(0, 1), (1, 2), (2, 0)];
1365 let incoming_vertices = (0..3).map(|i| (i, CFFEdgeType::External)).collect_vec();
1366
1367 let vertex_sets = [
1368 VertexSet::from_usize(0),
1369 VertexSet::from_usize(1),
1370 VertexSet::from_usize(2),
1371 ];
1372
1373 let cff_triangle = CFFGenerationGraph::from_vec(triangle, incoming_vertices, None);
1374 assert!(cff_triangle.has_directed_cycle(&vertex_sets[0]));
1375
1376 let triangle = vec![(0, 1), (1, 2), (0, 2)];
1377 let incoming_vertices = (0..3).map(|i| (i, CFFEdgeType::External)).collect_vec();
1378
1379 let vertex_sets = [
1380 VertexSet::from_usize(0),
1381 VertexSet::from_usize(1),
1382 VertexSet::from_usize(2),
1383 ];
1384
1385 let cff_triangle = CFFGenerationGraph::from_vec(triangle, incoming_vertices, None);
1386 assert!(!cff_triangle.has_directed_cycle(&vertex_sets[0]));
1387 }
1388
1389 #[test]
1390 fn test_connected_complement() {
1391 let triangle = vec![(0, 1), (1, 2), (2, 0)];
1392 let incoming_vertices = (0..3).map(|i| (i, CFFEdgeType::External)).collect_vec();
1393
1394 let vertex_sets = [
1395 VertexSet::from_usize(0),
1396 VertexSet::from_usize(1),
1397 VertexSet::from_usize(2),
1398 ];
1399
1400 let cff_triangle = CFFGenerationGraph::from_vec(triangle, incoming_vertices, None);
1401 assert!(cff_triangle.has_connected_complement(&vertex_sets[0]));
1402 assert!(cff_triangle.has_connected_complement(&vertex_sets[1]));
1403 assert!(cff_triangle.has_connected_complement(&vertex_sets[2]));
1404
1405 println!("triangle passed");
1406
1407 let double_bubble = vec![(0, 1), (0, 1), (1, 2), (1, 2)];
1408 let incoming_vertices = [0, 2]
1409 .into_iter()
1410 .map(|i| (i, CFFEdgeType::External))
1411 .collect_vec();
1412
1413 let vertex_sets = [
1414 VertexSet::from_usize(0),
1415 VertexSet::from_usize(1),
1416 VertexSet::from_usize(2),
1417 ];
1418
1419 let cff_double_bubble =
1420 CFFGenerationGraph::from_vec(double_bubble, incoming_vertices, None);
1421
1422 assert!(cff_double_bubble.has_connected_complement(&vertex_sets[0]));
1423 assert!(!cff_double_bubble.has_connected_complement(&vertex_sets[1]));
1424 assert!(cff_double_bubble.has_connected_complement(&vertex_sets[2]));
1425 println!("double bubble passed");
1426
1427 let single_bubble = vec![(0, 1), (0, 1)];
1428 let incoming_vertices = (0..2).map(|i| (i, CFFEdgeType::External)).collect_vec();
1429
1430 let vertex_sets = [VertexSet::from_usize(0), VertexSet::from_usize(1)];
1431
1432 let cff_single_bubble =
1433 CFFGenerationGraph::from_vec(single_bubble, incoming_vertices, None);
1434
1435 assert!(cff_single_bubble.has_connected_complement(&vertex_sets[0]));
1436 assert!(cff_single_bubble.has_connected_complement(&vertex_sets[1]));
1437
1438 println!("single bubble passed");
1439 }
1440
1441 #[test]
1442 fn test_get_vertex_type() {
1443 let triangle = vec![(0, 1), (2, 1), (0, 2)];
1444 let incoming_vertices = (0..3).map(|i| (i, CFFEdgeType::External)).collect_vec();
1445 let vertex_sets = [
1446 VertexSet::from_usize(0),
1447 VertexSet::from_usize(1),
1448 VertexSet::from_usize(2),
1449 ];
1450
1451 let cff_triangle = CFFGenerationGraph::from_vec(triangle, incoming_vertices, None);
1452
1453 assert_eq!(
1454 cff_triangle.get_vertex_type(&vertex_sets[0]),
1455 super::VertexType::Source
1456 );
1457 assert_eq!(
1458 cff_triangle.get_vertex_type(&vertex_sets[1]),
1459 super::VertexType::Sink
1460 );
1461 assert_eq!(
1462 cff_triangle.get_vertex_type(&vertex_sets[2]),
1463 super::VertexType::None
1464 );
1465 }
1466
1467 #[test]
1468 fn test_source_sink_candidate_list() {
1469 let triangle = vec![(0, 1), (2, 1), (0, 2)];
1470 let incoming_vertices = (0..3).map(|i| (i, CFFEdgeType::External)).collect_vec();
1471 let vertex_set = [
1472 VertexSet::from_usize(0),
1473 VertexSet::from_usize(1),
1474 VertexSet::from_usize(2),
1475 ];
1476
1477 let cff_triangle = CFFGenerationGraph::from_vec(triangle, incoming_vertices, None);
1478
1479 let source_sink_candidates = cff_triangle.get_source_sink_candidate_list();
1480 assert_eq!(source_sink_candidates.len(), 2);
1481
1482 let source_sink_candidates = source_sink_candidates
1483 .iter()
1484 .map(|vertex| vertex.vertex_set)
1485 .collect_vec();
1486
1487 assert!(source_sink_candidates.contains(&vertex_set[0]));
1488 assert!(source_sink_candidates.contains(&vertex_set[1]));
1489
1490 println!("triangle passed");
1491
1492 let bubble = vec![(0, 1), (0, 1)];
1493 let incoming_vertices = (0..2).map(|i| (i, CFFEdgeType::External)).collect_vec();
1494 let vertex_set = [VertexSet::from_usize(0), VertexSet::from_usize(1)];
1495
1496 let cff_bubble = CFFGenerationGraph::from_vec(bubble, incoming_vertices, None);
1497
1498 let source_sink_candidates = cff_bubble.get_source_sink_candidate_list();
1499 let source_sink_candidates = source_sink_candidates
1500 .iter()
1501 .map(|vertex| vertex.vertex_set)
1502 .collect_vec();
1503
1504 assert_eq!(source_sink_candidates.len(), 2);
1505 assert!(source_sink_candidates.contains(&vertex_set[0]));
1506 assert!(source_sink_candidates.contains(&vertex_set[1]));
1507
1508 println!("bubble passed");
1509 }
1510
1511 #[test]
1512 fn test_contract_from_vertex() {
1513 let triangle = vec![(0, 1), (2, 1), (0, 2)];
1514 let incoming_vertices = (0..3).map(|i| (i, CFFEdgeType::External)).collect_vec();
1515
1516 let vertex_set = [
1517 VertexSet::from_usize(0),
1518 VertexSet::from_usize(1),
1519 VertexSet::from_usize(2),
1520 ];
1521
1522 let joined_vertex = vertex_set[0].join(&vertex_set[1]);
1523
1524 let cff_triangle = CFFGenerationGraph::from_vec(triangle, incoming_vertices, None);
1525
1526 let contracted_graph = cff_triangle.contract_vertices(&vertex_set[0], &vertex_set[1]);
1527
1528 assert_eq!(contracted_graph.vertices.len(), 2);
1529
1530 let contracted_vertex = contracted_graph.get_vertex(&joined_vertex);
1531 assert_eq!(contracted_vertex.incoming_edges.len(), 3);
1532 assert_eq!(contracted_vertex.outgoing_edges.len(), 1);
1533
1534 let box_like = vec![(1, 0), (3, 0), (1, 2), (2, 3)];
1535 let incoming_vertices = vec![
1536 (0, CFFEdgeType::VirtualExternal),
1537 (1, CFFEdgeType::VirtualExternal),
1538 (2, CFFEdgeType::External),
1539 (3, CFFEdgeType::External),
1540 ];
1541
1542 let vertex_set = [
1543 VertexSet::from_usize(0),
1544 VertexSet::from_usize(1),
1545 VertexSet::from_usize(2),
1546 VertexSet::from_usize(3),
1547 ];
1548
1549 let cff_box = CFFGenerationGraph::from_vec(box_like, incoming_vertices, None);
1550
1551 let joined_vertex = vertex_set[0].join(&vertex_set[1]);
1552 let contracted_box = cff_box.contract_vertices(&vertex_set[0], &vertex_set[1]);
1553
1554 let contracted_vertex = contracted_box.get_vertex(&joined_vertex);
1555
1556 assert_eq!(contracted_vertex.incoming_edges.len(), 3);
1557 assert_eq!(contracted_vertex.outgoing_edges.len(), 1);
1558 }
1559
1560 #[test]
1561 fn test_get_edges() {
1562 let triangle = vec![(0, 1), (2, 1), (0, 2)];
1563 let incoming_vertices = (0..3).map(|i| (i, CFFEdgeType::External)).collect_vec();
1564
1565 let cff_triangle = CFFGenerationGraph::from_vec(triangle, incoming_vertices, None);
1566
1567 let edges = cff_triangle.get_edges();
1568 let comp_edges = (0..6).map(EdgeIndex::from).collect::<Vec<EdgeIndex>>();
1569
1570 assert_eq!(edges, comp_edges);
1572 }
1573
1574 #[test]
1575 fn test_has_edge() {
1576 let triangle = vec![(0, 1), (2, 1), (0, 2)];
1577 let incoming_vertices = (0..3).map(|i| (i, CFFEdgeType::External)).collect_vec();
1578
1579 let cff_triangle = CFFGenerationGraph::from_vec(triangle, incoming_vertices, None);
1580
1581 for edge in (0..6).map(EdgeIndex::from) {
1582 assert!(cff_triangle.has_edge(edge))
1583 }
1584
1585 for edge in (6..12).map(EdgeIndex::from) {
1586 assert!(!cff_triangle.has_edge(edge))
1587 }
1588 }
1589
1590 #[test]
1591 fn test_generate_cut() {
1592 let box_edges = vec![(0, 1), (1, 2), (2, 3), (3, 0)];
1593 let incoming_vertices = (0..4).map(|i| (i, CFFEdgeType::External)).collect_vec();
1594 let incoming_vertices_len = incoming_vertices.len();
1595
1596 let cff_box = CFFGenerationGraph::from_vec(box_edges, incoming_vertices, None);
1597
1598 let vertex_sets = [
1599 VertexSet::from_usize(0),
1600 VertexSet::from_usize(1),
1601 VertexSet::from_usize(2),
1602 VertexSet::from_usize(3),
1603 ];
1604
1605 let circled = vertex_sets[0].join(&vertex_sets[1]);
1606
1607 let (left_cut, right_cut) = cff_box.generate_cut(circled);
1608
1609 assert_eq!(left_cut.vertices.len(), 2);
1610 assert_eq!(right_cut.vertices.len(), 2);
1611
1612 assert!(left_cut.has_edge(EdgeIndex::from(incoming_vertices_len)));
1613 assert!(left_cut.has_edge(EdgeIndex::from(1 + incoming_vertices_len)));
1614 assert!(left_cut.has_edge(EdgeIndex::from(3 + incoming_vertices_len)));
1615 assert!(!left_cut.has_edge(EdgeIndex::from(2 + incoming_vertices_len)));
1616
1617 assert!(right_cut.has_edge(EdgeIndex::from(1 + incoming_vertices_len)));
1618 assert!(right_cut.has_edge(EdgeIndex::from(2 + incoming_vertices_len)));
1619 assert!(right_cut.has_edge(EdgeIndex::from(3 + incoming_vertices_len)));
1620 assert!(!right_cut.has_edge(EdgeIndex::from(incoming_vertices_len)));
1621
1622 #[allow(clippy::if_same_then_else)]
1623 for edge in left_cut.iter_all_edges() {
1624 if edge.edge_id == incoming_vertices_len.into() {
1625 assert_eq!(edge.edge_type, CFFEdgeType::Virtual)
1626 } else if edge.edge_id == (1 + incoming_vertices_len).into() {
1627 assert_eq!(edge.edge_type, CFFEdgeType::VirtualExternal)
1628 } else if edge.edge_id == (3 + incoming_vertices_len).into() {
1629 assert_eq!(edge.edge_type, CFFEdgeType::VirtualExternal)
1630 } else {
1631 assert_eq!(edge.edge_type, CFFEdgeType::External)
1632 }
1633 }
1634
1635 #[allow(clippy::if_same_then_else)]
1636 for edge in right_cut.iter_all_edges() {
1637 if edge.edge_id == (2 + incoming_vertices_len).into() {
1638 assert_eq!(edge.edge_type, CFFEdgeType::Virtual)
1639 } else if edge.edge_id == (1 + incoming_vertices_len).into() {
1640 assert_eq!(edge.edge_type, CFFEdgeType::VirtualExternal)
1641 } else if edge.edge_id == (3 + incoming_vertices_len).into() {
1642 assert_eq!(edge.edge_type, CFFEdgeType::VirtualExternal)
1643 } else {
1644 assert_eq!(edge.edge_type, CFFEdgeType::External)
1645 }
1646 }
1647
1648 }
1651
1652 #[test]
1653 fn test_contract_edge() {
1654 let mut hedge_graph_builder = HedgeGraphBuilder::new();
1655 let nodes = (0..2)
1656 .map(|_| hedge_graph_builder.add_node(()))
1657 .collect_vec();
1658
1659 hedge_graph_builder.add_edge(nodes[0], nodes[1], (), Orientation::Undirected);
1660 hedge_graph_builder.add_edge(nodes[0], nodes[1], (), Orientation::Undirected);
1661 hedge_graph_builder.add_edge(nodes[0], nodes[1], (), Orientation::Undirected);
1662
1663 hedge_graph_builder.add_external_edge(nodes[0], (), Orientation::Undirected, Flow::Sink);
1664 hedge_graph_builder.add_external_edge(nodes[1], (), Orientation::Undirected, Flow::Source);
1665
1666 let hedge_graph: HedgeGraph<_, _, ()> = hedge_graph_builder.build::<NodeStorageVec<_>>();
1667 let global_orientation = hedge_graph.new_edgevec(|_, _, _| Orientation::Default);
1668
1669 let cff_graph = CFFGenerationGraph::new(&hedge_graph, global_orientation, &[]);
1670 let contracted = cff_graph.contract_edge(EdgeIndex::from(0));
1671
1672 assert!(!contracted.has_edge(EdgeIndex::from(0)));
1673 assert!(contracted.has_edge(EdgeIndex::from(1)));
1674 assert!(contracted.has_edge(EdgeIndex::from(2)));
1675 assert!(contracted.has_edge(EdgeIndex::from(3)));
1676 assert!(contracted.has_edge(EdgeIndex::from(4)));
1677
1678 assert_eq!(contracted.vertices.len(), 1);
1679
1680 let vertex = contracted.vertices[0].clone();
1681 assert_eq!(
1682 vertex.incoming_edges,
1683 vec![
1684 CFFEdge {
1685 edge_id: EdgeIndex::from(1),
1686 edge_type: CFFEdgeType::Virtual,
1687 },
1688 CFFEdge {
1689 edge_id: EdgeIndex::from(2),
1690 edge_type: CFFEdgeType::Virtual,
1691 },
1692 CFFEdge {
1693 edge_id: EdgeIndex::from(3),
1694 edge_type: CFFEdgeType::External
1695 }
1696 ]
1697 );
1698
1699 assert_eq!(
1700 vertex.outgoing_edges,
1701 vec![
1702 CFFEdge {
1703 edge_id: EdgeIndex::from(1),
1704 edge_type: CFFEdgeType::Virtual,
1705 },
1706 CFFEdge {
1707 edge_id: EdgeIndex::from(2),
1708 edge_type: CFFEdgeType::Virtual,
1709 },
1710 CFFEdge {
1711 edge_id: EdgeIndex::from(4),
1712 edge_type: CFFEdgeType::External
1713 }
1714 ]
1715 );
1716
1717 let mut tri_box_builder = HedgeGraphBuilder::new();
1718
1719 let nodes = (0..5).map(|_| tri_box_builder.add_node(())).collect_vec();
1720
1721 tri_box_builder.add_edge(nodes[0], nodes[1], (), Orientation::Undirected);
1722 tri_box_builder.add_edge(nodes[1], nodes[2], (), Orientation::Undirected);
1723 tri_box_builder.add_edge(nodes[0], nodes[2], (), Orientation::Undirected);
1724
1725 tri_box_builder.add_edge(nodes[1], nodes[3], (), Orientation::Undirected);
1726 tri_box_builder.add_edge(nodes[2], nodes[4], (), Orientation::Undirected);
1727 tri_box_builder.add_edge(nodes[3], nodes[4], (), Orientation::Undirected);
1728
1729 tri_box_builder.add_external_edge(nodes[0], (), Orientation::Undirected, Flow::Sink);
1730 tri_box_builder.add_external_edge(nodes[3], (), Orientation::Undirected, Flow::Source);
1731 tri_box_builder.add_external_edge(nodes[4], (), Orientation::Undirected, Flow::Source);
1732
1733 let tri_box: HedgeGraph<(), (), ()> = tri_box_builder.build::<NodeStorageVec<_>>();
1734 let global_orientation = tri_box.new_edgevec(|_, _, _| Orientation::Default);
1735 let mut tri_box_cff_graph = CFFGenerationGraph::new(&tri_box, global_orientation, &[]);
1736
1737 assert!(!tri_box_cff_graph.has_impossible_edge());
1738 tri_box_cff_graph = tri_box_cff_graph.contract_edge(EdgeIndex::from(0));
1739 assert!(!tri_box_cff_graph.has_impossible_edge());
1740 tri_box_cff_graph = tri_box_cff_graph.contract_edge(EdgeIndex::from(1));
1741 assert!(!tri_box_cff_graph.has_impossible_edge());
1742 tri_box_cff_graph = tri_box_cff_graph.contract_edge(EdgeIndex::from(2));
1743 assert!(!tri_box_cff_graph.has_impossible_edge());
1744
1745 tri_box_cff_graph.remove_self_edges();
1746 assert!(!tri_box_cff_graph.has_impossible_edge());
1747
1748 for vertex in tri_box_cff_graph.vertices.iter() {
1749 let all_edges = vertex.iter_all_edges().collect_vec();
1750 assert_eq!(all_edges.len(), 3);
1751 let num_external = all_edges
1752 .iter()
1753 .filter(|edge| edge.edge_type == CFFEdgeType::External)
1754 .count();
1755 assert_eq!(num_external, 1);
1756
1757 let num_virtual = all_edges
1758 .iter()
1759 .filter(|edge| edge.edge_type == CFFEdgeType::Virtual)
1760 .count();
1761 assert_eq!(num_virtual, 2);
1762
1763 let num_virtual_external = all_edges
1764 .iter()
1765 .filter(|edge| edge.edge_type == CFFEdgeType::VirtualExternal)
1766 .count();
1767 assert_eq!(num_virtual_external, 0);
1768 }
1769 }
1770
1771 #[test]
1772 fn test_new_from_subgraph() {
1773 let mut hedge_graph_builder = HedgeGraphBuilder::new();
1774
1775 let nodes = (0..4)
1776 .map(|_| hedge_graph_builder.add_node(()))
1777 .collect_vec();
1778
1779 hedge_graph_builder.add_edge(nodes[0], nodes[1], (), Orientation::Undirected);
1780 hedge_graph_builder.add_edge(nodes[0], nodes[2], (), Orientation::Undirected);
1781 hedge_graph_builder.add_edge(nodes[1], nodes[2], (), Orientation::Undirected);
1782 hedge_graph_builder.add_edge(nodes[1], nodes[3], (), Orientation::Undirected);
1783 hedge_graph_builder.add_edge(nodes[2], nodes[3], (), Orientation::Undirected);
1784
1785 hedge_graph_builder.add_external_edge(nodes[0], (), Orientation::Undirected, Flow::Sink);
1786 hedge_graph_builder.add_external_edge(nodes[3], (), Orientation::Undirected, Flow::Source);
1787
1788 let hedge_graph: HedgeGraph<(), (), ()> = hedge_graph_builder.build::<NodeStorageVec<_>>();
1789 let node_0: SuBitGraph = hedge_graph.iter_crown(nodes[0]).into();
1790 let node_1: SuBitGraph = hedge_graph.iter_crown(nodes[1]).into();
1791 let node_2: SuBitGraph = hedge_graph.iter_crown(nodes[2]).into();
1792
1793 let left_triangle = node_0.union(&node_1).union(&node_2);
1794
1795 let global_orientation = hedge_graph.new_edgevec(|_, _, _| Orientation::Default);
1796
1797 let cff_graph =
1798 CFFGenerationGraph::new_from_subgraph(&hedge_graph, global_orientation, &left_triangle)
1799 .unwrap();
1800
1801 assert!(cff_graph.has_edge(EdgeIndex::from(0)));
1802 assert!(cff_graph.has_edge(EdgeIndex::from(1)));
1803 assert!(cff_graph.has_edge(EdgeIndex::from(2)));
1804 assert!(cff_graph.has_edge(EdgeIndex::from(3)));
1805 assert!(cff_graph.has_edge(EdgeIndex::from(4)));
1806 assert!(cff_graph.has_edge(EdgeIndex::from(5)));
1807 assert!(!cff_graph.has_edge(EdgeIndex::from(6)));
1808
1809 for edge in cff_graph.iter_all_edges() {
1810 match edge.edge_id.into() {
1811 0 => assert_eq!(edge.edge_type, CFFEdgeType::Virtual),
1812 1 => assert_eq!(edge.edge_type, CFFEdgeType::Virtual),
1813 2 => assert_eq!(edge.edge_type, CFFEdgeType::Virtual),
1814 3 => assert_eq!(edge.edge_type, CFFEdgeType::VirtualExternal),
1815 4 => assert_eq!(edge.edge_type, CFFEdgeType::VirtualExternal),
1816 5 => assert_eq!(edge.edge_type, CFFEdgeType::External),
1817 _ => unreachable!(),
1818 }
1819 }
1820 }
1821}