Skip to main content

gammalooprs/cff/
expression.rs

1#![allow(dead_code)]
2
3use std::{borrow::Borrow, collections::HashMap, fmt::Display};
4
5use crate::{
6    cff::{
7        esurface::{EsurfaceID, RaisedEsurfaceData, RaisedEsurfaceGroup},
8        orientations::GraphOrientation,
9    },
10    settings::global::OrientationPattern,
11    utils::{W_, ose_atom_from_index},
12};
13use bincode_trait_derive::{Decode, Encode};
14use derive_more::{From, Into};
15use linnet::half_edge::{
16    GVEdgeAttrs, HedgeGraph,
17    involution::{EdgeVec, Orientation, SignOrZero},
18    nodestore::NodeStorageOps,
19};
20use serde::{Deserialize, Serialize};
21use symbolica::{
22    atom::{Atom, AtomCore, AtomOrView, Symbol},
23    function,
24    id::{Pattern, Replacement},
25    symbol,
26};
27use tabled::{builder::Builder, settings::Style};
28use typed_index_collections::TiVec;
29
30use super::{generation::SurfaceCache, surface::HybridSurfaceID, tree::Tree};
31
32#[derive(
33    Debug,
34    Clone,
35    Serialize,
36    Deserialize,
37    From,
38    Into,
39    Hash,
40    PartialEq,
41    Eq,
42    Copy,
43    Encode,
44    Decode,
45    PartialOrd,
46    Ord,
47)]
48pub struct OrientationID(pub usize);
49
50impl GraphOrientation for EdgeVec<Orientation> {
51    fn orientation(&self) -> &EdgeVec<Orientation> {
52        self
53    }
54}
55
56impl OrientationID {
57    pub fn symbol() -> Symbol {
58        symbol!("sigma")
59    }
60
61    pub fn atom(self) -> Atom {
62        let id: usize = self.into();
63        function!(Self::symbol(), id as i64)
64    }
65
66    pub fn select<'a>(self, atom: impl Into<AtomOrView<'a>>) -> Atom {
67        atom.into()
68            .as_view()
69            .replace(self.atom())
70            .with(Atom::num(1))
71            .replace(function!(Self::symbol(), W_.x_))
72            .with(Atom::Zero)
73    }
74}
75
76#[derive(
77    Clone, Debug, PartialOrd, Ord, Hash, PartialEq, Eq, Serialize, Deserialize, Encode, Decode,
78)]
79pub struct OrientationData {
80    pub orientation: EdgeVec<Orientation>,
81}
82
83impl GraphOrientation for OrientationData {
84    fn orientation(&self) -> &EdgeVec<Orientation> {
85        &self.orientation
86    }
87}
88
89impl Display for OrientationData {
90    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
91        let mut table = Builder::new();
92
93        for (i, item) in self.orientation.iter() {
94            table.push_column(&[i.to_string(), SignOrZero::from(*item).to_string()]);
95        }
96        table.build().with(Style::rounded()).fmt(f)
97    }
98}
99
100impl OrientationData {
101    pub(crate) fn dot<E, V, N: NodeStorageOps<NodeData = V>>(&self, graph: &HedgeGraph<E, V, N>) {
102        let mut writer = String::new();
103        writer.push_str("digraph {{");
104
105        writer.push_str(
106            "  node [shape=circle,height=0.1,label=\"\"];  overlap=\"scale\"; layout=\"neato\";",
107        );
108
109        for (hedge_pair, id, _) in graph.iter_edges() {
110            let attr = GVEdgeAttrs {
111                color: None,
112                label: None,
113                other: None,
114            };
115            writer.push_str("  ");
116
117            let attr = hedge_pair.fill_color(attr);
118            hedge_pair
119                .add_data(graph)
120                .dot_fmt(
121                    &mut writer,
122                    graph,
123                    id,
124                    |_| None,
125                    |a| a.to_string(),
126                    self.orientation[id],
127                    attr,
128                )
129                .unwrap();
130        }
131        writer.push_str("}}");
132    }
133
134    pub(crate) fn get_ose_replacements(&self) -> Vec<Replacement> {
135        self.orientation
136            .borrow()
137            .into_iter()
138            .filter_map(|(edge_index, orientation)| {
139                if matches!(orientation, Orientation::Reversed) {
140                    let energy_atom = ose_atom_from_index(edge_index);
141
142                    let neg_energy_atom = -&energy_atom;
143
144                    Some(Replacement::new(
145                        Pattern::from(energy_atom),
146                        Pattern::from(neg_energy_atom),
147                    ))
148                } else {
149                    None
150                }
151            })
152            .collect()
153    }
154}
155
156#[derive(Clone, Debug, Serialize, Deserialize, Encode, Decode)]
157pub struct OrientationExpression {
158    pub data: OrientationData,
159    pub expression: Tree<HybridSurfaceID>,
160}
161#[derive(Clone, Debug, Serialize, Deserialize, Encode, Decode)]
162pub struct CFFExpression<O>
163where
164    O: From<usize> + Into<usize>,
165{
166    pub orientations: TiVec<O, OrientationExpression>,
167    pub surfaces: SurfaceCache,
168}
169
170impl GraphOrientation for OrientationExpression {
171    fn orientation(&self) -> &EdgeVec<Orientation> {
172        &self.data.orientation
173    }
174}
175
176impl<O: Clone + From<usize> + Into<usize>> CFFExpression<O>
177where
178    usize: From<O>,
179{
180    pub(crate) fn new_empty() -> Self {
181        Self {
182            orientations: TiVec::new(),
183            surfaces: SurfaceCache {
184                esurface_cache: TiVec::new(),
185                hsurface_cache: TiVec::new(),
186            },
187        }
188    }
189
190    pub fn to_atom(&self, pattern: OrientationPattern) -> Atom {
191        self.orientations
192            .iter()
193            .filter_map(|orientation| {
194                if pattern.filter(orientation.orientation()) {
195                    Some(orientation.expression.to_atom_inv())
196                } else {
197                    None
198                }
199            })
200            .reduce(|a, b| a + b)
201            .unwrap_or_default()
202    }
203
204    pub(crate) fn get_orientation_atoms(
205        &self,
206        pattern: OrientationPattern,
207    ) -> TiVec<OrientationID, Atom> {
208        self.orientations
209            .iter()
210            .map(|orientation| {
211                if pattern.filter(orientation.orientation()) {
212                    orientation.expression.to_atom_inv()
213                } else {
214                    Atom::new()
215                }
216            })
217            .collect()
218    }
219
220    pub fn get_orientation_atoms_with_data(
221        &self,
222        pattern: OrientationPattern,
223    ) -> TiVec<OrientationID, (Atom, OrientationData)> {
224        self.orientations
225            .iter()
226            .map(|orientation| {
227                let atom = if pattern.filter(orientation.orientation()) {
228                    orientation.expression.to_atom_inv()
229                } else {
230                    Atom::new()
231                };
232                let data = orientation.data.clone();
233                (atom, data)
234            })
235            .collect()
236    }
237
238    pub(crate) fn get_orientation_atom(&self, orientation_id: O) -> Atom {
239        self.orientations[orientation_id].expression.to_atom_inv()
240    }
241
242    pub(crate) fn num_unfolded_terms(&self) -> usize {
243        self.orientations
244            .iter()
245            .map(|o| o.expression.get_bottom_layer().len())
246            .sum()
247    }
248
249    pub(crate) fn get_orientations_with_esurface(&self, esurface_id: EsurfaceID) -> Vec<O> {
250        self.orientations
251            .iter_enumerated()
252            .filter_map(|(id, orientation)| {
253                if orientation
254                    .expression
255                    .iter_nodes()
256                    .any(|node| node.data == HybridSurfaceID::Esurface(esurface_id))
257                {
258                    Some(id)
259                } else {
260                    None
261                }
262            })
263            .collect()
264    }
265
266    pub(crate) fn select_esurface_residue(
267        mut self,
268        raised_esurface_group: &RaisedEsurfaceGroup,
269    ) -> Vec<CFFExpression<O>> {
270        self.normalize_single_raising(raised_esurface_group);
271
272        let reprentative_esurface_id = raised_esurface_group.esurface_ids[0];
273
274        let mut result = vec![];
275        for occurence in 1..=raised_esurface_group.max_occurence {
276            let mut new_expression = self.clone();
277
278            for orientation in new_expression.orientations.iter_mut() {
279                orientation.expression.keep_branches_with_value_count_mut(
280                    &HybridSurfaceID::Esurface(reprentative_esurface_id),
281                    occurence,
282                );
283
284                orientation
285                    .expression
286                    .map_mut(|hybrid_surface_id| match hybrid_surface_id {
287                        HybridSurfaceID::Esurface(esurface_id)
288                            if *esurface_id == reprentative_esurface_id =>
289                        {
290                            *hybrid_surface_id = HybridSurfaceID::Unit;
291                        }
292                        _ => (),
293                    });
294            }
295
296            result.push(new_expression);
297        }
298
299        result
300    }
301
302    pub(crate) fn normalize_single_raising(&mut self, raised_esurface_group: &RaisedEsurfaceGroup) {
303        let reprentative_esurface_id = raised_esurface_group.esurface_ids[0];
304
305        for orientation in self.orientations.iter_mut() {
306            orientation
307                .expression
308                .map_mut(|hybrid_surface_id| match hybrid_surface_id {
309                    HybridSurfaceID::Esurface(esurface_id)
310                        if raised_esurface_group.esurface_ids.contains(esurface_id) =>
311                    {
312                        *hybrid_surface_id = HybridSurfaceID::Esurface(reprentative_esurface_id);
313                    }
314                    _ => (),
315                });
316        }
317    }
318
319    pub(crate) fn normalize_wrt_all_raisings(&mut self, raised_data: &RaisedEsurfaceData) {
320        let mut esurface_mappings = HashMap::new();
321
322        for cut_group in raised_data.raised_groups.iter() {
323            let esurface_id_of_first = cut_group.esurface_ids[0];
324
325            for esurface_id in cut_group.esurface_ids.iter() {
326                esurface_mappings.insert(*esurface_id, esurface_id_of_first);
327            }
328        }
329
330        for orientation in self.orientations.iter_mut() {
331            orientation.expression.map_mut(|hybrid_surface_id| {
332                if let HybridSurfaceID::Esurface(esurface_id) = hybrid_surface_id
333                    && let Some(normalized_esurface_id) = esurface_mappings.get(esurface_id)
334                {
335                    *esurface_id = *normalized_esurface_id;
336                }
337            });
338        }
339    }
340}