Skip to main content

gammalooprs/graph/
cuts.rs

1use bincode_trait_derive::{Decode, Encode};
2use gammaloop_tracing_filter::LogMessage;
3use itertools::Itertools;
4use linnet::half_edge::{
5    involution::EdgeIndex,
6    subgraph::{SuBitGraph, SubSetLike},
7};
8
9use crate::cff::{CutCFFIndex, esurface::RaisedEsurfaceGroup};
10
11#[derive(Debug, Clone, Encode, Decode, PartialEq, Hash, Eq, PartialOrd, Ord)]
12pub struct CutSet {
13    pub residue_selector: ResidueSelector,
14    pub union: SuBitGraph,
15    pub canonicalize_external_shifts: bool,
16}
17
18impl LogMessage for CutSet {
19    fn log_display(&self) -> String {
20        format!("CutSet: union={}", self.union.string_label())
21    }
22}
23
24#[derive(Debug, Clone, Encode, Decode, PartialEq, Hash, Eq, PartialOrd, Ord)]
25pub struct LuCutSelection {
26    pub raised_group: RaisedEsurfaceGroup,
27    /// Normalized physical edge support for each actual Cutkosky cut in this
28    /// raised group. Alternative order remains the physical-cut order so a
29    /// future LTD policy can attach representation-specific data without
30    /// reconstructing alternatives from the lossy union subgraph.
31    pub cut_edge_alternatives: Vec<Vec<EdgeIndex>>,
32}
33
34#[derive(Debug, Clone, Encode, Decode, PartialEq, Hash, Eq, PartialOrd, Ord)]
35pub struct ResidueSelector {
36    pub lu: Option<LuCutSelection>,
37    pub left_th_cut: Option<RaisedEsurfaceGroup>,
38    pub right_th_cut: Option<RaisedEsurfaceGroup>,
39}
40
41impl ResidueSelector {
42    pub fn generate_allowed_keys(&self) -> Vec<CutCFFIndex> {
43        let allowed_keys = vec![CutCFFIndex::new_all_none()];
44        allowed_keys
45            .into_iter()
46            .flat_map(|index| {
47                if let Some(lu) = &self.lu {
48                    (1..=lu.raised_group.max_occurence)
49                        .map(|lu_cut_index| {
50                            let mut new_index = index;
51                            new_index.lu_cut_order = Some(lu_cut_index);
52                            new_index
53                        })
54                        .collect_vec()
55                } else {
56                    vec![index]
57                }
58            })
59            .flat_map(|index| {
60                if let Some(left_th_cut) = &self.left_th_cut {
61                    (1..=left_th_cut.max_occurence)
62                        .map(|left_th_cut_index| {
63                            let mut new_index = index;
64                            new_index.left_threshold_order = Some(left_th_cut_index);
65                            new_index
66                        })
67                        .collect_vec()
68                } else {
69                    vec![index]
70                }
71            })
72            .flat_map(|index| {
73                if let Some(right_th_cut) = &self.right_th_cut {
74                    (1..=right_th_cut.max_occurence)
75                        .map(|right_th_cut_index| {
76                            let mut new_index = index;
77                            new_index.right_threshold_order = Some(right_th_cut_index);
78                            new_index
79                        })
80                        .collect_vec()
81                } else {
82                    vec![index]
83                }
84            })
85            .collect()
86    }
87}
88
89impl CutSet {
90    pub fn empty(size: usize) -> Self {
91        CutSet {
92            residue_selector: ResidueSelector {
93                lu: None,
94                left_th_cut: None,
95                right_th_cut: None,
96            },
97            union: SuBitGraph::empty(size),
98            canonicalize_external_shifts: false,
99        }
100    }
101}