1use std::{
2 collections::BTreeMap,
3 hash::Hash,
4 ops::{Mul, Neg},
5};
6
7use crate::{
8 GammaLoopContext, cff::CutCFFIndex, numerator::aind::Aind, utils::GS, uv::approx::Rooted,
9};
10use bincode_trait_derive::{Decode, Encode};
11use color_eyre::Result;
12use eyre::eyre;
13use itertools::{EitherOrBoth, Itertools};
14use spenso::{
15 network::parsing::ShadowedStructure,
16 structure::{
17 NamedStructure, ToSymbolic,
18 dimension::Dimension,
19 representation::{Minkowski, RepName},
20 },
21};
22use symbolica::atom::Atom;
23
24use linnet::half_edge::involution::HedgePair;
25
26pub(crate) fn spenso_lor(
29 tag: i32,
30 ind: impl Into<Aind>,
31 dim: impl Into<Dimension>,
32) -> ShadowedStructure<Aind> {
33 let mink = Minkowski {}.new_slot(dim, ind);
34 NamedStructure::from_iter([mink], GS.emr_mom, Some(vec![Atom::num(tag)])).structure
35}
36
37pub(crate) fn spenso_lor_atom(tag: i32, ind: impl Into<Aind>, dim: impl Into<Dimension>) -> Atom {
38 spenso_lor(tag, ind, dim).to_symbolic(None).unwrap()
39}
40
41#[derive(Clone, Debug, PartialEq, Eq, Hash)]
42pub struct IntegrandExpr {
43 integrands: BTreeMap<CutCFFIndex, Atom>,
44 }
46
47#[derive(Clone, Debug, PartialEq, Eq, Hash, Encode, Decode)]
48#[trait_decode(trait = GammaLoopContext)]
49pub struct Integrands(BTreeMap<CutCFFIndex, Atom>);
50
51impl Integrands {
52 pub fn map<F: FnMut(&Atom) -> Atom>(&self, mut f: F) -> Self {
53 Integrands(self.0.iter().map(|(k, v)| (*k, f(v))).collect())
54 }
55
56 pub fn fallible_map<F: FnMut(&Atom) -> Result<Atom>>(&self, mut f: F) -> Result<Self> {
57 self.0.iter().map(|(k, v)| Ok((*k, f(v)?))).collect()
58 }
59
60 pub fn iter(&self) -> impl Iterator<Item = (&CutCFFIndex, &Atom)> {
61 self.0.iter()
62 }
63
64 pub fn checked_zip(
65 &self,
66 other: &Integrands,
67 mut map: impl FnMut(&CutCFFIndex, &Atom, &Atom) -> Result<Atom>,
68 ) -> Result<Integrands> {
69 self.0
70 .iter()
71 .merge_join_by(&other.0, |(left_key, _), (right_key, _)| {
72 left_key.cmp(right_key)
73 })
74 .map(|pair| match pair {
75 EitherOrBoth::Both((key, left), (_, right)) => Ok((*key, map(key, left, right)?)),
76 EitherOrBoth::Left((key, _)) => {
77 Err(eyre!("right integrands are missing key {key:?}"))
78 }
79 EitherOrBoth::Right((key, _)) => {
80 Err(eyre!("left integrands are missing key {key:?}"))
81 }
82 })
83 .collect()
84 }
85
86 pub fn zip_mul(&self, other: &Integrands) -> Result<Integrands> {
87 self.checked_zip(other, |_, v1, v2| Ok(v1 * v2))
88 }
89 pub fn zip_add(&self, other: &Integrands) -> Result<Integrands> {
90 self.checked_zip(other, |_, v1, v2| Ok(v1 + v2))
91 }
92}
93
94impl FromIterator<(CutCFFIndex, Atom)> for Integrands {
95 fn from_iter<I: IntoIterator<Item = (CutCFFIndex, Atom)>>(iter: I) -> Self {
96 Integrands(BTreeMap::from_iter(iter))
97 }
98}
99
100impl Mul<Atom> for Integrands {
101 type Output = Self;
102
103 fn mul(self, rhs: Atom) -> Self::Output {
104 self.map(|a| a * &rhs)
105 }
106}
107
108impl Neg for Integrands {
109 type Output = Self;
110
111 fn neg(self) -> Self::Output {
112 self.map(|a| a.neg())
113 }
114}
115
116impl Mul<&Atom> for Integrands {
117 type Output = Self;
118
119 fn mul(self, rhs: &Atom) -> Self::Output {
120 self.map(|a| a * rhs)
121 }
122}
123
124impl Rooted for Integrands {
125 fn root() -> Self {
126 Integrands(BTreeMap::from([(
127 CutCFFIndex::new_all_none(),
128 Atom::num(1),
129 )]))
130 }
131}
132#[allow(dead_code)]
133pub(crate) fn is_not_paired(pair: &HedgePair) -> bool {
134 !pair.is_paired()
135}
136
137pub mod hedge_poset;
138mod marker;
139mod orchestrator;
140pub mod renormalization;
141pub use renormalization::{RenormalizationPart, RenormalizationStats};
142pub mod settings;
143pub use settings::{
144 ApproximationType, CTIdentifier, CTRenormalizationRule, RenormalizationPrescriptionSettings,
145 UVOrchestrator, UVgenerationSettings,
146};
147pub mod uv_graph;
148pub use uv_graph::UltravioletGraph;
149
150pub mod spinney;
151pub use spinney::Spinney;
152
153pub mod poset;
154pub use poset::Poset;
155
156pub mod wood;
157pub use wood::Wood;
158
159pub mod approx;
160pub use approx::ApproxOp;
161
162pub mod export;
163
164pub mod forest;
165pub use forest::Forest;
166
167pub mod profile;
168pub use profile::{UVProfile, UVProfileAnalysis, UVProfilePassFail};
169
170#[cfg(test)]
171mod tests;