Skip to main content

gammalooprs/cff/
cff_graph.rs

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    // helper function for tests
306    #[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; // reset delta
497
498            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            // current_vertices = vertices_found_in_previous_iteration.clone();
512            // vertices_found_in_previous_iteration.clear();
513            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        // self edges need a special treatment
574        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                //subspace_graph: unsafe { InternalSubGraph::new_unchecked(SuBitGraph::new()) },
767            };
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    // this function is used to set the orientation. Note that if called twice the edges may also be flipped twice, so the caller needs to be careful to only call this function once per graph
843    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; // skip dummy edges
879            }
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    /// for now only non-cut graphs are supported
925    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; // skip dummy edges
935            }
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        // sort is always good
1173        unique_edges.sort();
1174        unique_edges
1175    }
1176
1177    #[cfg(test)]
1178    /// has duplicates
1179    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        // etc.
1306
1307        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, vec![0, 1, 2, 3, 4, 5]);
1571        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        //println!("left {:#?}", left_cut);
1649        //println!("right {:#?}", right_cut);
1650    }
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}