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}