Skip to main content

gammalooprs/numerator/
mod.rs

1#![allow(dead_code)]
2
3use aind::Aind;
4use idenso::color::ColorSimplifier;
5use idenso::dirac::GammaSimplifier;
6use idenso::representations::Bispinor;
7use linnet::half_edge::involution::EdgeIndex;
8use schemars::JsonSchema;
9use tracing::warn;
10
11use spenso::network::library::DummyLibrary;
12use spenso::network::parsing::{ParseSettings, ShadowedStructure};
13use spenso::network::store::NetworkStore;
14use spenso::network::{ContractScalars, MinResultRank, Sequential, SingleSmallestDegree, Steps};
15use symbolica_utils::SerializableSymbol;
16
17use spenso::tensors::data::DataTensor;
18use spenso::tensors::data::GetTensorData;
19use spenso::tensors::data::StorageTensor;
20use spenso::tensors::parametric::atomcore::TensorAtomMaps;
21
22use spenso::tensors::parametric::ParamTensor;
23use spenso::tensors::parametric::TensorSet;
24use std::fmt::Debug;
25use std::ops::Deref;
26use std::sync::{Arc, Mutex};
27use symbolica_ext::NumeratorAtomExt;
28use thiserror::Error;
29use tracing::{debug, instrument};
30// use crate::feyngen::dis::{DisEdge, DisVertex};
31
32use crate::graph::parse::string_utils::ToOrderedSimple;
33use crate::momentum::{PolDef, PolType};
34use crate::utils::{FUN_LIB, GS, TENSORLIB, W_};
35use crate::{model::Model, utils::serde_utils::IsDefault};
36
37use crate::{GammaLoopContextContainer, disable};
38use ahash::AHashMap;
39use bincode::{Decode, Encode};
40use color_eyre::{Report, Result};
41use eyre::eyre;
42// use gxhash::GxBuildHasher;
43use itertools::Itertools;
44
45use serde::de::DeserializeOwned;
46use serde::ser::SerializeStruct;
47use serde::{Deserialize, Serialize};
48
49use spenso::contraction::Contract;
50
51use spenso::network::library::symbolic::{ETS, ExplicitKey};
52
53use spenso::structure::concrete_index::{ExpandedIndex, FlatIndex};
54
55use spenso::structure::representation::{LibraryRep, Minkowski};
56use spenso::structure::{HasStructure, ScalarTensor, SmartShadowStructure};
57
58use spenso::{
59    shadowing::Shadowable,
60    structure::{
61        NamedStructure, TensorStructure,
62        representation::{Lorentz, RepName},
63    },
64};
65
66use symbolica::state::Workspace;
67
68use crate::numerator::ufo::UFO;
69use symbolica::prelude::*;
70
71pub mod symbolica_ext;
72
73#[cfg(test)]
74pub(crate) mod exact_soft_jet;
75#[cfg(test)]
76pub(crate) mod pole_certificate;
77#[cfg(test)]
78pub(crate) mod soft_energy_certificate;
79
80#[cfg(test)]
81mod spensotests;
82
83pub mod aind;
84pub mod energy_degree;
85pub mod ufo;
86#[derive(Debug, Clone, Serialize, Deserialize, Encode, Decode, PartialEq)]
87/// Settings for the numerator
88pub struct NumeratorSettings {
89    #[serde(default, skip_serializing_if = "IsDefault::is_default")]
90    pub eval_settings: NumeratorEvaluatorOptions,
91    /// Parse mode for the numerator, once all processing is done. `Polynomial` turns it into a polynomial in the energies, while `Direct` keeps it as is
92    pub parse_mode: NumeratorParseMode,
93    /// If set, dump the expression the expression at each step in this format
94    pub dump_expression: Option<ExpressionFormat>,
95    /// If set, instead of deriving the numerator from feynman rules, use this as the numerator
96    /// Will be parsed to a symbolica expression
97    // pub global_numerator: Option<String>,
98    /// If set, multiply the numerator by this prefactor
99    // pub global_prefactor: GlobalPrefactor,
100    /// Type of Gamma algebra to use, either symbolic (replacement rules) or concrete (replace by value using spenso)
101    pub gamma_algebra: GammaAlgebraMode,
102}
103
104#[derive(Debug, Clone, Copy, Serialize, Deserialize, Default, Encode, Decode, PartialEq)]
105pub enum ExpressionFormat {
106    Mathematica,
107    #[default]
108    Symbolica,
109}
110
111impl From<ExpressionFormat> for PrintOptions {
112    fn from(value: ExpressionFormat) -> Self {
113        match value {
114            ExpressionFormat::Symbolica => PrintOptions::file(),
115            ExpressionFormat::Mathematica => PrintOptions::mathematica(),
116        }
117    }
118}
119
120impl Default for NumeratorSettings {
121    fn default() -> Self {
122        NumeratorSettings {
123            eval_settings: Default::default(),
124            // global_numerator: None,
125            // global_prefactor: GlobalPrefactor::default(),
126            dump_expression: None,
127            gamma_algebra: GammaAlgebraMode::Symbolic,
128            parse_mode: NumeratorParseMode::Polynomial,
129        }
130    }
131}
132
133#[derive(Debug, Clone, Serialize, Deserialize, Encode, Decode, PartialEq)]
134pub enum GammaAlgebraMode {
135    Symbolic,
136    Concrete,
137}
138
139pub type AtomStructure = SmartShadowStructure<SerializableSymbol, Vec<Atom>>;
140
141pub struct RepeatingIterator<T> {
142    elements: Vec<T>,
143    positions: std::vec::IntoIter<usize>,
144}
145
146pub enum RepeatingIteratorTensorOrScalar<T: HasStructure> {
147    Tensors(RepeatingIterator<T>),
148    Scalars(RepeatingIterator<T::Scalar>),
149}
150
151impl<T> RepeatingIterator<T> {
152    pub(crate) fn new(positions: Vec<usize>, elements: Vec<T>) -> Self {
153        RepeatingIterator {
154            elements,
155            positions: positions.into_iter(),
156        }
157    }
158
159    pub(crate) fn new_not_repeating(elements: Vec<T>) -> Self {
160        let positions: Vec<usize> = (0..elements.len()).collect();
161        RepeatingIterator {
162            elements,
163            positions: positions.into_iter(),
164        }
165    }
166}
167
168// #[test]
169// fn rep_iter(){
170//     let mut r= RepeatingIterator::new_not_repeating(vec![1,2,3,4,5]);
171//     while let Some(s) =r.next()  {
172//         println!("{}",s);
173//     }
174// }
175
176impl<T: HasStructure> From<(TensorSet<T>, Vec<usize>)> for RepeatingIteratorTensorOrScalar<T> {
177    fn from(value: (TensorSet<T>, Vec<usize>)) -> Self {
178        match value.0 {
179            TensorSet::Tensors(t) => {
180                RepeatingIteratorTensorOrScalar::Tensors(RepeatingIterator::new(value.1, t))
181            }
182            TensorSet::Scalars(s) => {
183                RepeatingIteratorTensorOrScalar::Scalars(RepeatingIterator::new(value.1, s))
184            }
185        }
186    }
187}
188
189impl<T: HasStructure> From<TensorSet<T>> for RepeatingIteratorTensorOrScalar<T> {
190    fn from(value: TensorSet<T>) -> Self {
191        match value {
192            TensorSet::Tensors(t) => {
193                RepeatingIteratorTensorOrScalar::Tensors(RepeatingIterator::new_not_repeating(t))
194            }
195            TensorSet::Scalars(s) => {
196                RepeatingIteratorTensorOrScalar::Scalars(RepeatingIterator::new_not_repeating(s))
197            }
198        }
199    }
200}
201
202#[derive(Debug, Clone, Serialize, Deserialize, Encode, Decode)]
203pub struct Numerator<State> {
204    pub state: State,
205}
206
207impl<S: NumeratorState> Numerator<S> {
208    pub(crate) fn export(&self) -> String {
209        self.state.export()
210    }
211
212    pub(crate) fn forget_type(self) -> Numerator<PythonState> {
213        Numerator {
214            state: self.state.forget_type(),
215        }
216    }
217
218    pub(crate) fn update_model(&mut self, model: &Model) -> Result<()> {
219        self.state.update_model(model)
220    }
221
222    fn add_consts_to_fn_map(fn_map: &mut FunctionMap) {
223        fn_map
224            .add_aliases([(parse!("Nc"), Atom::num(Rational::from(3)))])
225            .unwrap();
226
227        fn_map
228            .add_aliases([(parse!("TR"), Atom::num(Rational::from((1, 2))))])
229            .unwrap();
230    }
231}
232
233impl<S: GetSingleAtom> Numerator<S> {
234    pub(crate) fn get_single_atom(&self) -> Result<Atom, NumeratorStateError> {
235        self.state.get_single_atom()
236    }
237}
238
239pub trait TypedNumeratorState:
240    NumeratorState + TryFrom<PythonState, Error: std::error::Error + Send + Sync + 'static>
241{
242    fn apply<F, S: TypedNumeratorState>(
243        state: &mut Numerator<PythonState>,
244        f: F,
245    ) -> Result<(), NumeratorStateError>
246    where
247        F: FnMut(Numerator<Self>) -> Numerator<S>;
248}
249
250impl Numerator<PythonState> {
251    pub(crate) fn try_from<S: TypedNumeratorState>(self) -> Result<Numerator<S>, Report> {
252        Ok(Numerator {
253            state: self.state.try_into()?,
254        })
255    }
256
257    pub(crate) fn apply<F, S: TypedNumeratorState, T: TypedNumeratorState>(
258        &mut self,
259        f: F,
260    ) -> Result<(), NumeratorStateError>
261    where
262        F: FnMut(Numerator<S>) -> Numerator<T>,
263    {
264        S::apply(self, f)
265    }
266}
267pub trait NumeratorState:
268    Clone + Debug + Encode + for<'a> Decode<GammaLoopContextContainer<'a>>
269{
270    fn export(&self) -> String;
271
272    fn forget_type(self) -> PythonState;
273
274    fn update_model(&mut self, model: &Model) -> Result<()>;
275    // fn try_from(state: PythonState) -> Result<Self>;
276}
277
278#[derive(Debug, Clone, Serialize, Deserialize, Encode, Decode)]
279pub struct UnInit;
280
281impl Default for UnInit {
282    fn default() -> Self {
283        let _ = *UFO;
284        let _ = *ETS;
285        UnInit
286    }
287}
288
289impl TryFrom<PythonState> for UnInit {
290    type Error = NumeratorStateError;
291
292    fn try_from(value: PythonState) -> std::result::Result<Self, Self::Error> {
293        match value {
294            PythonState::UnInit(s) => {
295                if let Some(s) = s {
296                    Ok(s)
297                } else {
298                    Err(NumeratorStateError::NoneVariant)
299                }
300            }
301            _ => Err(NumeratorStateError::NotUnit),
302        }
303    }
304}
305
306impl NumeratorState for UnInit {
307    fn export(&self) -> String {
308        "Uninitialized".to_string()
309    }
310
311    fn forget_type(self) -> PythonState {
312        PythonState::UnInit(Some(self))
313    }
314
315    fn update_model(&mut self, _model: &Model) -> Result<()> {
316        Err(eyre!("Uninitialized, nothing to update"))
317    }
318}
319
320impl TypedNumeratorState for UnInit {
321    fn apply<F, S: TypedNumeratorState>(
322        num: &mut Numerator<PythonState>,
323        mut f: F,
324    ) -> Result<(), NumeratorStateError>
325    where
326        F: FnMut(Numerator<Self>) -> Numerator<S>,
327    {
328        if let PythonState::UnInit(s) = &mut num.state {
329            if let Some(s) = s.take() {
330                *num = f(Numerator { state: s }).forget_type();
331                return Ok(());
332            } else {
333                return Err(NumeratorStateError::NoneVariant);
334            }
335        }
336        Err(NumeratorStateError::NotUnit)
337    }
338}
339
340#[allow(dead_code)]
341#[derive(JsonSchema)]
342struct _GlobalPrefactorAny {
343    projector: serde_json::Value,
344    num: serde_json::Value,
345}
346
347#[derive(Debug, Clone, bincode_trait_derive::Encode, bincode_trait_derive::Decode, PartialEq)]
348#[trait_decode(trait = crate::GammaLoopContext)]
349pub struct GlobalPrefactor {
350    pub projector: Atom,
351    pub num: Atom,
352}
353
354impl JsonSchema for GlobalPrefactor {
355    fn json_schema(generated: &mut schemars::SchemaGenerator) -> schemars::Schema {
356        generated.subschema_for::<_GlobalPrefactorAny>()
357    }
358    fn schema_name() -> std::borrow::Cow<'static, str> {
359        "GlobalPrefactor".into()
360    }
361}
362
363impl GlobalPrefactor {
364    pub fn polarizations(&self) -> Vec<(PolDef, Atom)> {
365        let mut pols = Vec::new();
366        let full_prefactor = &self.projector * &self.num;
367        let pat = function!(GS.epsilon, W_.e_, W_.i_).to_pattern();
368        for m in full_prefactor.pattern_match(&pat, None, None) {
369            let Some(e) = m.get(&W_.e_) else {
370                continue;
371            };
372            let Ok(e) = i64::try_from(e) else {
373                continue;
374            };
375
376            pols.push((
377                PolDef {
378                    pol_type: PolType::Epsilon,
379                    eid: EdgeIndex(e as usize),
380                },
381                pat.replace_wildcards(&m).unwrap(),
382            ));
383        }
384
385        let pat = function!(GS.epsilonbar, W_.e_, W_.i_).to_pattern();
386        for m in full_prefactor.pattern_match(&pat, None, None) {
387            let Some(e) = m.get(&W_.e_) else {
388                continue;
389            };
390            let Ok(e) = i64::try_from(e) else {
391                continue;
392            };
393
394            pols.push((
395                PolDef {
396                    pol_type: PolType::EpsilonBar,
397                    eid: EdgeIndex(e as usize),
398                },
399                pat.replace_wildcards(&m).unwrap(),
400            ));
401        }
402
403        let pat = function!(GS.u, W_.e_, W_.i_).to_pattern();
404        for m in full_prefactor.pattern_match(&pat, None, None) {
405            let Some(e) = m.get(&W_.e_) else {
406                continue;
407            };
408            let Ok(e) = i64::try_from(e) else {
409                continue;
410            };
411
412            pols.push((
413                PolDef {
414                    pol_type: PolType::U,
415                    eid: EdgeIndex(e as usize),
416                },
417                pat.replace_wildcards(&m).unwrap(),
418            ));
419        }
420
421        let pat = function!(GS.v, W_.e_, W_.i_).to_pattern();
422        for m in full_prefactor.pattern_match(&pat, None, None) {
423            let Some(e) = m.get(&W_.e_) else {
424                continue;
425            };
426            let Ok(e) = i64::try_from(e) else {
427                continue;
428            };
429
430            pols.push((
431                PolDef {
432                    pol_type: PolType::V,
433                    eid: EdgeIndex(e as usize),
434                },
435                pat.replace_wildcards(&m).unwrap(),
436            ));
437        }
438
439        let pat = function!(GS.ubar, W_.e_, W_.i_).to_pattern();
440        for m in full_prefactor.pattern_match(&pat, None, None) {
441            let Some(e) = m.get(&W_.e_) else {
442                continue;
443            };
444            let Ok(e) = i64::try_from(e) else {
445                continue;
446            };
447
448            pols.push((
449                PolDef {
450                    pol_type: PolType::UBar,
451                    eid: EdgeIndex(e as usize),
452                },
453                pat.replace_wildcards(&m).unwrap(),
454            ));
455        }
456
457        let pat = function!(GS.vbar, W_.e_, W_.i_).to_pattern();
458        for m in full_prefactor.pattern_match(&pat, None, None) {
459            let Some(e) = m.get(&W_.e_) else {
460                continue;
461            };
462            let Ok(e) = i64::try_from(e) else {
463                continue;
464            };
465
466            pols.push((
467                PolDef {
468                    pol_type: PolType::VBar,
469                    eid: EdgeIndex(e as usize),
470                },
471                pat.replace_wildcards(&m).unwrap(),
472            ));
473        }
474
475        pols.sort_by_key(|a| a.0);
476
477        pols
478    }
479}
480
481impl Default for GlobalPrefactor {
482    fn default() -> Self {
483        GlobalPrefactor {
484            projector: Atom::num(1),
485            num: Atom::num(1),
486        }
487    }
488}
489
490impl Serialize for GlobalPrefactor {
491    fn serialize<S>(&self, serializer: S) -> std::result::Result<S::Ok, S::Error>
492    where
493        S: serde::Serializer,
494    {
495        let mut state = serializer.serialize_struct("GlobalPrefactor", 2)?;
496        state.serialize_field("projector", &self.projector.to_string())?;
497        state.serialize_field("num", &self.num.to_string())?;
498
499        state.end()
500    }
501}
502
503impl<'de> Deserialize<'de> for GlobalPrefactor {
504    fn deserialize<D>(deserializer: D) -> std::result::Result<Self, D::Error>
505    where
506        D: serde::Deserializer<'de>,
507    {
508        #[derive(Deserialize)]
509        struct GlobalPrefactorHelper {
510            num: String,
511            projector: String,
512        }
513        let helper = GlobalPrefactorHelper::deserialize(deserializer)?;
514        Ok(GlobalPrefactor {
515            projector: parse!(&helper.projector),
516            num: parse!(&helper.num),
517        })
518    }
519}
520
521pub trait NumeratorNode {}
522
523pub mod graph;
524pub mod uninit;
525#[allow(clippy::default_constructed_unit_structs)]
526impl Default for Numerator<UnInit> {
527    fn default() -> Self {
528        Numerator {
529            state: UnInit::default(),
530        }
531    }
532}
533
534#[derive(Debug, Clone, bincode_trait_derive::Encode, bincode_trait_derive::Decode)]
535#[trait_decode(trait = symbolica::state::HasStateMap)]
536pub struct SymbolicExpression<State> {
537    // pub colorless: ParamTensor<OrderedStructure<Euclidean, Aind>>,
538    // pub color: ParamTensor<OrderedStructure<Euclidean, Aind>>,
539    pub expr: Atom,
540    pub state: State,
541}
542
543pub trait GetSingleAtom {
544    fn get_single_atom(&self) -> Result<Atom, NumeratorStateError>;
545}
546
547pub trait UnexpandedNumerator: NumeratorState + GetSingleAtom {
548    // fn expr(&self) -> Result<Atom, NumeratorStateError>;
549
550    fn map_color(self, f: impl Fn(Atom) -> Atom) -> Self;
551
552    fn map_color_mut(&mut self, f: impl FnMut(&mut Atom));
553
554    fn map_colorless(self, f: impl Fn(Atom) -> Atom) -> Self;
555}
556
557impl<E: ExpressionState> GetSingleAtom for SymbolicExpression<E> {
558    fn get_single_atom(&self) -> Result<Atom, NumeratorStateError> {
559        Ok(self.expr.clone())
560    }
561}
562
563impl<E: ExpressionState> SymbolicExpression<E> {
564    // // #[allow(dead_code)]
565    // fn map_color(self, f: impl Fn(Atom) -> Atom) -> Self {
566    //     SymbolicExpression {
567    //         colorless: self.colorless,
568    //         color: self.color.map_data_self(f),
569    //         state: self.state,
570    //     }
571    // }
572
573    // // #[allow(dead_code)]
574    // fn map_color_mut(&mut self, f: impl FnMut(&mut Atom)) {
575    //     self.color.map_data_mut(f);
576    // }
577    // // #[allow(dead_code)]
578    // fn map_colorless(self, f: impl Fn(Atom) -> Atom) -> Self {
579    //     SymbolicExpression {
580    //         colorless: self.colorless.map_data_self(f),
581    //         color: self.color,
582    //         state: self.state,
583    //     }
584    // }
585}
586
587impl<E: ExpressionState> SymbolicExpression<E> {
588    pub(crate) fn new(expression: Atom) -> Self {
589        E::new(expression)
590    }
591    pub(crate) fn new_color(expression: Atom) -> Self {
592        E::new_color(expression)
593    }
594}
595
596pub trait ExpressionState:
597    Serialize
598    + Clone
599    + DeserializeOwned
600    + Debug
601    + Encode
602    + for<'a> Decode<GammaLoopContextContainer<'a>>
603    + Default
604{
605    fn forget_type(data: SymbolicExpression<Self>) -> PythonState;
606
607    fn new(expression: Atom) -> SymbolicExpression<Self> {
608        SymbolicExpression {
609            // colorless: ParamTensor::composite(DataTensor::new_scalar(expression)),
610            // color: ParamTensor::composite(DataTensor::new_scalar(Atom::num(1))),
611            expr: expression,
612            state: Self::default(),
613        }
614    }
615
616    fn new_color(expression: Atom) -> SymbolicExpression<Self> {
617        SymbolicExpression {
618            // color: ParamTensor::composite(DataTensor::new_scalar(expression)),
619            // colorless: ParamTensor::composite(DataTensor::new_scalar(Atom::num(1))),
620            expr: expression,
621            state: Self::default(),
622        }
623    }
624
625    fn get_expression(
626        num: &mut PythonState,
627    ) -> Result<SymbolicExpression<Self>, NumeratorStateError>;
628}
629
630impl<E: ExpressionState> TypedNumeratorState for SymbolicExpression<E> {
631    fn apply<F, S: TypedNumeratorState>(
632        num: &mut Numerator<PythonState>,
633        mut f: F,
634    ) -> Result<(), NumeratorStateError>
635    where
636        F: FnMut(Numerator<Self>) -> Numerator<S>,
637    {
638        let s = Self::try_from(&mut num.state)?;
639        *num = f(Numerator { state: s }).forget_type();
640        Ok(())
641    }
642}
643
644impl<E: ExpressionState> TryFrom<&mut PythonState> for SymbolicExpression<E> {
645    type Error = NumeratorStateError;
646
647    fn try_from(value: &mut PythonState) -> std::result::Result<Self, Self::Error> {
648        let a = E::get_expression(value)?;
649        Ok(a)
650    }
651}
652
653impl<E: ExpressionState> TryFrom<PythonState> for SymbolicExpression<E> {
654    type Error = NumeratorStateError;
655
656    fn try_from(mut value: PythonState) -> std::result::Result<Self, Self::Error> {
657        let a = E::get_expression(&mut value)?;
658        Ok(a)
659    }
660}
661
662#[derive(Debug, Clone, Copy, Serialize, Deserialize, Encode, Decode, Default)]
663pub struct Local {}
664pub type AppliedFeynmanRule = SymbolicExpression<Local>;
665
666impl ExpressionState for Local {
667    fn forget_type(data: SymbolicExpression<Self>) -> PythonState {
668        PythonState::AppliedFeynmanRule(Some(data))
669    }
670
671    fn get_expression(
672        num: &mut PythonState,
673    ) -> Result<SymbolicExpression<Self>, NumeratorStateError> {
674        if let PythonState::AppliedFeynmanRule(s) = num {
675            if let Some(s) = s.take() {
676                Ok(s)
677            } else {
678                Err(NumeratorStateError::NoneVariant)
679            }
680        } else {
681            Err(NumeratorStateError::NotAppliedFeynmanRule)
682        }
683    }
684}
685
686#[derive(Debug, Copy, Clone, Serialize, Deserialize, Encode, Decode, Default)]
687pub struct NonLocal {}
688pub type Global = SymbolicExpression<NonLocal>;
689
690impl ExpressionState for NonLocal {
691    fn forget_type(data: SymbolicExpression<Self>) -> PythonState {
692        PythonState::Global(Some(data))
693    }
694
695    fn get_expression(
696        num: &mut PythonState,
697    ) -> Result<SymbolicExpression<Self>, NumeratorStateError> {
698        if let PythonState::Global(s) = num {
699            if let Some(s) = s.take() {
700                Ok(s)
701            } else {
702                Err(NumeratorStateError::NoneVariant)
703            }
704        } else {
705            Err(NumeratorStateError::NotGlobal)
706        }
707    }
708}
709
710impl Numerator<Global> {
711    #[instrument(skip(self))]
712    pub(crate) fn color_simplify(self) -> Numerator<ColorSimplified> {
713        // debug!("Color simplifying global numerator");
714        // let mut fully_simplified = true;
715
716        let state = ColorSimplified {
717            expr: self.state.expr.simplify_color(),
718            state: Color::Fully,
719        };
720        // debug!("Color simplified numerator:{}", state.expr);
721        Numerator { state }
722    }
723}
724
725#[derive(Debug, Copy, Clone, Serialize, Deserialize, Encode, Decode, Default)]
726pub enum Color {
727    #[default]
728    Fully,
729    Partially,
730}
731pub type ColorSimplified = SymbolicExpression<Color>;
732
733impl ExpressionState for Color {
734    fn forget_type(data: SymbolicExpression<Self>) -> PythonState {
735        PythonState::ColorSimplified(Some(data))
736    }
737
738    fn get_expression(
739        num: &mut PythonState,
740    ) -> Result<SymbolicExpression<Self>, NumeratorStateError> {
741        if let PythonState::ColorSimplified(s) = num {
742            if let Some(s) = s.take() {
743                Ok(s)
744            } else {
745                Err(NumeratorStateError::NoneVariant)
746            }
747        } else {
748            Err(NumeratorStateError::NotColorSimplified)
749        }
750    }
751}
752
753// #[derive(Debug, Clone, Serialize, Deserialize, Encode, Decode, Default)]
754// pub struct Projected {}
755// pub type ColorProjected = SymbolicExpression<Projected>;
756
757// impl ExpressionState for Projected {
758//     fn forget_type(data: SymbolicExpression<Self>) -> PythonState {
759//         PythonState::ColorProjected(Some(data))
760//     }
761
762//     fn get_expression(
763//         num: &mut PythonState,
764//     ) -> Result<SymbolicExpression<Self>, NumeratorStateError> {
765//         if let PythonState::ColorProjected(s) = num {
766//             if let Some(s) = s.take() {
767//                 Ok(s)
768//             } else {
769//                 Err(NumeratorStateError::NoneVariant)
770//             }
771//         } else {
772//             Err(NumeratorStateError::NotColorProjected)
773//         }
774//     }
775// }
776
777#[derive(Debug, Copy, Clone, Serialize, Deserialize, Encode, Decode, Default)]
778pub struct Gamma {}
779pub type GammaSimplified = SymbolicExpression<Gamma>;
780
781impl ExpressionState for Gamma {
782    fn forget_type(data: SymbolicExpression<Self>) -> PythonState {
783        PythonState::GammaSimplified(Some(data))
784    }
785
786    fn get_expression(
787        num: &mut PythonState,
788    ) -> Result<SymbolicExpression<Self>, NumeratorStateError> {
789        if let PythonState::GammaSimplified(s) = num {
790            if let Some(s) = s.take() {
791                Ok(s)
792            } else {
793                Err(NumeratorStateError::NoneVariant)
794            }
795        } else {
796            Err(NumeratorStateError::NotGammaSymplified)
797        }
798    }
799}
800
801impl<State: ExpressionState> NumeratorState for SymbolicExpression<State> {
802    fn export(&self) -> String {
803        self.get_single_atom().unwrap().to_canonical_string()
804    }
805
806    fn forget_type(self) -> PythonState {
807        State::forget_type(self)
808    }
809
810    fn update_model(&mut self, _model: &Model) -> Result<()> {
811        Err(eyre!("Only an expression, nothing to update"))
812    }
813}
814
815impl<T: Copy + Default> Numerator<SymbolicExpression<T>> {
816    pub(crate) fn canonize_lorentz(&self) -> Result<Self, String> {
817        let pats: Vec<LibraryRep> = vec![Minkowski {}.into(), Bispinor {}.into()];
818
819        let mut indices_map = AHashMap::new();
820
821        for p in &pats {
822            for a in self.state.expr.pattern_match(
823                &p.to_symbolic([W_.x_, W_.y_]).to_pattern(),
824                None,
825                None,
826            ) {
827                indices_map.insert(
828                    p.to_symbolic([a[&W_.x_].clone(), a[&W_.y_].clone()]),
829                    p.to_symbolic([a[&W_.x_].clone()]),
830                );
831            }
832        }
833
834        let sorted = indices_map.into_iter().sorted().collect::<Vec<_>>();
835
836        let expr = self
837            .state
838            .expr
839            .canonize_tensors(sorted)
840            .map_err(|e| e.to_string())?
841            .canonical_form;
842
843        Ok(Self {
844            state: SymbolicExpression {
845                expr,
846                state: T::default(),
847            },
848        })
849    }
850
851    // pub(crate) fn canonize_color(&self) -> Result<Self, String> {
852
853    //     let pats: Vec<_> = vec![ColorAdjoint{}];
854    //     let dualizablepats: Vec<_> = vec![
855    //         ColorFundamental::selfless_symbol(),
856    //         ColorSextet::selfless_symbol(),
857    //     ];
858
859    //     let mut color = self.state.expr.replace(&function!(symbol!(DOWNIND), GS.x__).to_pattern())
860    //                 .with(Atom::var(GS.x__).to_pattern())
861    //     ;
862
863    //     let mut indices_map = AHashMap::new();
864
865    //     color.iter_flat().for_each(|(_, v)| {
866    //         for p in pats.iter().chain(&dualizablepats) {
867    //             for a in
868    //                 v.0.pattern_match(&function!(*p, GS.x_, GS.y_).to_pattern(), None, None)
869    //             {
870    //                 indices_map.insert(
871    //                     function!(*p, a[&GS.x_], a[&GS.y_]),
872    //                     function!(*p, a[&GS.x_]),
873    //                 );
874    //             }
875    //         }
876    //     });
877
878    //     let sorted = indices_map.into_iter().sorted().collect::<Vec<_>>();
879    //     // println!(
880    //     //     "indices sorted [{}]",
881    //     //     sorted
882    //     //         .iter()
883    //     //         .map(|(a, b)| format!(
884    //     //             "(Atom::parse(\"{}\").unwrap(),Atom::parse(\"{}\").unwrap())",
885    //     //             a, b
886    //     //         ))
887    //     //         .collect::<Vec<_>>()
888    //     //         .join(", ")
889    //     // );
890
891    //     color = color.map_data_ref_result(|a| a.0.canonize_tensors(&sorted).map(|a| a.into()))?;
892
893    //     let colorless = self.state.colorless.clone();
894    //     Ok(Self {
895    //         state: SymbolicExpression {
896    //             colorless,
897    //             color,
898    //             state: T::default(),
899    //         },
900    //     }));
901    //     todo!()
902    // }
903}
904
905impl Numerator<AppliedFeynmanRule> {
906    #[allow(clippy::wrong_self_convention)]
907    pub(crate) fn to_d_dim<'a>(mut self, dim: impl Into<AtomOrView<'a>>) -> Self {
908        self.state.expr = self.state.expr.map_mink_dim(dim);
909        self
910    }
911
912    #[instrument(skip(self), fields(expr=%self.state.expr.to_ordered_simple()))]
913    pub(crate) fn color_simplify(self) -> Numerator<ColorSimplified> {
914        // debug!("Color simplifying global numerator");
915        // let mut fully_simplified = true;
916
917        let state = ColorSimplified {
918            expr: self.state.expr.simplify_color(),
919            state: Color::Fully,
920        };
921        debug!(
922            "Color simplified numerator:{}",
923            state.expr.to_ordered_simple()
924        );
925        Numerator { state }
926    }
927}
928
929// #[derive(Debug, Error)]
930// pub enum ColorError {
931//     #[error("Not fully simplified: {0}")]
932//     NotFully(Atom),
933// }
934
935impl Numerator<ColorSimplified> {
936    pub(crate) fn gamma_simplify(self) -> Numerator<GammaSimplified> {
937        debug!("Gamma simplifying color symplified numerator");
938        let expr = self.state.expr.simplify_gamma();
939        crate::debug_tags!(#generation, #inspect, #dump;
940            stage = "numerator_after_simplify_gamma",
941            log.after_gamma = expr,
942            "Numerator after gamma simplification"
943        );
944
945        Numerator {
946            state: GammaSimplified {
947                expr,
948                state: Default::default(),
949            },
950        }
951    }
952}
953
954pub type Gloopoly =
955    symbolica::poly::polynomial::MultivariatePolynomial<symbolica::domains::atom::AtomField, u8>;
956
957#[derive(Debug, Clone)]
958// #[trait_decode(trait = symbolica::state::HasStateMap)]
959pub struct PolySplit {
960    pub colorless: DataTensor<Gloopoly, ShadowedStructure<Aind>>,
961    pub var_map: Arc<Vec<PolyVariable>>,
962    pub energies: Vec<usize>,
963    pub color: ParamTensor<ShadowedStructure<Aind>>,
964    pub colorsimplified: Color,
965}
966
967impl Encode for PolySplit {
968    fn encode<E: bincode::enc::Encoder>(
969        &self,
970        _encoder: &mut E,
971    ) -> std::result::Result<(), bincode::error::EncodeError> {
972        todo!()
973    }
974}
975
976impl PolySplit {
977    pub(crate) fn from_color_out(
978        _color_simplified: Numerator<ColorSimplified>,
979    ) -> DataTensor<Atom> {
980        disable!(
981
982        let colorless_parsed = color_simplified
983            .state
984            .colorless
985            .map_data(|a| {
986                let mut net =
987                    TensorNetwork::<MixedTensor<f64, AtomStructure>, Atom>::try_from(
988                        a.as_view(),
989                    )
990                    .unwrap();
991                net.contract().unwrap();
992                net.to_fully_parametric()
993                    .result_tensor_smart()
994                    .unwrap()
995                    .tensor
996                    .map_structure(OrderedStructure::from)
997            })
998            .flatten(&Atom::num(0))
999            .unwrap();
1000
1001        colorless_parsed
1002        );
1003        todo!()
1004    }
1005
1006    fn to_shadowed_poly_impl(
1007        poly: &Gloopoly,
1008        workspace: &Workspace,
1009        reps: Arc<Mutex<Vec<Atom>>>,
1010    ) -> Atom {
1011        if poly.is_zero() {
1012            return Atom::num(0);
1013        }
1014
1015        let mut add = Atom::num(0);
1016        let coef = symbol!("coef");
1017        let shift = reps.as_ref().lock().unwrap().len();
1018
1019        let mut mul_h;
1020        let mut var_h = workspace.new_atom();
1021        let mut num_h = workspace.new_atom();
1022        let mut pow_h = workspace.new_atom();
1023
1024        for (i, monomial) in poly.into_iter().enumerate() {
1025            mul_h = Atom::num(1);
1026            for (var_id, &pow) in poly.variables().iter().zip(monomial.exponents) {
1027                if pow > 0 {
1028                    match var_id {
1029                        PolyVariable::Symbol(v) => {
1030                            var_h.to_var(*v);
1031                        }
1032                        PolyVariable::Temporary(_) => {
1033                            unreachable!("Temporary variable in expression")
1034                        }
1035                        PolyVariable::Function(_, a) | PolyVariable::Power(a) => {
1036                            var_h.set_from_view(&a.as_view());
1037                        }
1038                    }
1039
1040                    if pow > 0 {
1041                        num_h.to_num(pow as i64);
1042                        pow_h.to_pow(var_h.as_view(), num_h.as_view());
1043                        mul_h *= pow_h.as_view();
1044                    } else {
1045                        mul_h *= var_h.as_view();
1046                    }
1047                }
1048            }
1049
1050            reps.lock()
1051                .as_mut()
1052                .unwrap()
1053                .push(monomial.coefficient.clone());
1054
1055            mul_h *= function!(coef, Atom::num((i + shift) as i64));
1056            add += mul_h.as_view();
1057        }
1058
1059        add
1060    }
1061    fn shadow_poly(poly: Gloopoly, reps: Arc<Mutex<Vec<Atom>>>) -> Atom {
1062        Workspace::get_local().with(|ws| Self::to_shadowed_poly_impl(&poly, ws, reps))
1063    }
1064
1065    pub(crate) fn optimize(self) -> PolyContracted {
1066        let reps = Arc::new(Mutex::new(Vec::new()));
1067
1068        let colorless = self
1069            .colorless
1070            .map_data(|a| Self::shadow_poly(a, reps.clone()));
1071
1072        let out = match self.colorsimplified {
1073            Color::Fully => ParamTensor::composite(colorless)
1074                .contract(&self.color)
1075                .unwrap(),
1076            Color::Partially => {
1077                warn!(
1078                    "Not fully color-simplified, taking the colorless part associated to {}",
1079                    self.color.get_owned_linear(FlatIndex::from(0)).unwrap()
1080                );
1081                ParamTensor::new_scalar(colorless.get_owned_linear(FlatIndex::from(0)).unwrap())
1082            }
1083        };
1084
1085        let reps = Arc::try_unwrap(reps).unwrap().into_inner().unwrap();
1086
1087        PolyContracted {
1088            tensor: out,
1089            coef_map: reps,
1090        }
1091    }
1092}
1093
1094impl Numerator<PolySplit> {
1095    pub(crate) fn contract(self) -> Result<Numerator<PolyContracted>> {
1096        match self.validate_squared_energies_impl() {
1097            Err(_) => {
1098                debug!("Trying to contract polynomial");
1099                let state = self.state.optimize();
1100                debug!("PolyContracted: {}", state.tensor);
1101                Ok(Numerator { state })
1102            }
1103            Ok(r) => Err(eyre!("has higher powers here: {}", r)),
1104        }
1105    }
1106
1107    fn validate_squared_energies_impl(
1108        &self,
1109    ) -> Result<DataTensor<ExpandedIndex, ShadowedStructure<Aind>>, ()> {
1110        self.state.colorless.map_data_ref_result(|p| {
1111            let mut square: Result<Vec<usize>, ()> = Err(());
1112            for (i, &e) in p.exponents.iter().enumerate() {
1113                if e > 1 {
1114                    if let Ok(sq) = &mut square {
1115                        sq.push(i);
1116                    } else {
1117                        square = Ok(vec![i]);
1118                    }
1119                }
1120            }
1121            square.map(ExpandedIndex::from)
1122        })
1123    }
1124
1125    pub(crate) fn validate_squared_energies(&self) -> bool {
1126        self.validate_squared_energies_impl().is_err()
1127    }
1128}
1129
1130#[derive(Debug, Clone, bincode_trait_derive::Encode, bincode_trait_derive::Decode)]
1131#[trait_decode(trait = symbolica::state::HasStateMap)]
1132pub struct PolyContracted {
1133    pub tensor: ParamTensor<ShadowedStructure<Aind>>,
1134    pub coef_map: Vec<Atom>,
1135}
1136
1137impl Numerator<PolyContracted> {
1138    #[allow(clippy::wrong_self_convention)]
1139    pub(crate) fn to_contracted(self) -> Numerator<Contracted> {
1140        let coefs: Vec<_> = (0..self.state.coef_map.len())
1141            .map(|i| function!(GS.coeff, Atom::num(i as i64)).to_pattern())
1142            .collect();
1143
1144        let coefs_reps: Vec<_> = self.state.coef_map.iter().map(|a| a.to_pattern()).collect();
1145
1146        let reps: Vec<_> = coefs
1147            .into_iter()
1148            .zip(coefs_reps)
1149            .map(|(p, rhs)| Replacement::new(p, rhs))
1150            .collect();
1151
1152        Numerator {
1153            state: Contracted {
1154                tensor: self.state.tensor.replace_multiple(&reps),
1155            },
1156        }
1157    }
1158
1159    fn generate_fn_map(&self) -> FunctionMap {
1160        let mut fn_map = FunctionMap::new();
1161
1162        for (v, k) in self.state.coef_map.clone().iter().enumerate() {
1163            fn_map
1164                .add_tagged_function::<Symbol>(
1165                    GS.coeff,
1166                    vec![Atom::num(v as i64)],
1167                    vec![],
1168                    k.clone(),
1169                )
1170                .unwrap();
1171        }
1172
1173        Numerator::<Contracted>::add_consts_to_fn_map(&mut fn_map);
1174        fn_map
1175    }
1176}
1177
1178impl NumeratorState for PolyContracted {
1179    fn export(&self) -> String {
1180        self.tensor.to_string()
1181    }
1182    fn forget_type(self) -> PythonState {
1183        PythonState::PolyContracted(Some(self))
1184    }
1185
1186    fn update_model(&mut self, _model: &Model) -> Result<()> {
1187        Err(eyre!(
1188            "Only applied feynman rule, simplified color, gamma, parsed into network and contracted, nothing to update"
1189        ))
1190    }
1191}
1192
1193impl PolyContracted {}
1194
1195impl GammaSimplified {
1196    pub(crate) fn parse(self) -> Network {
1197        let lib = DummyLibrary::<ParamTensor<ShadowedStructure<Aind>>, _>::new();
1198        let net = ParsingNet::try_from_view(
1199            self.get_single_atom().unwrap().as_view(),
1200            &lib,
1201            &ParseSettings::default(),
1202        )
1203        .unwrap();
1204
1205        // println!("net scalar{}", net.scalar.as_ref().unwrap());
1206        Network { net }
1207    }
1208
1209    // pub(crate) fn parse_only_colorless(self) -> Network {
1210    //     let lib = DummyLibrary::<(), _>::new();
1211    //     let net = ParsingNet::try_from_view(
1212    //         self.colorless
1213    //             .clone()
1214    //             .scalar()
1215    //             .ok_or(NumeratorStateError::Any(eyre!("not a scalar")))
1216    //             .unwrap()
1217    //             .as_view(),
1218    //         &lib,
1219    //     )
1220    //     .unwrap();
1221
1222    //     // println!("net scalar{}", net.scalar.as_ref().unwrap());
1223    //     Network { net }
1224    // }
1225}
1226
1227impl Numerator<GammaSimplified> {
1228    pub(crate) fn parse(self) -> Result<Numerator<Network>> {
1229        // debug!("GammaSymplified numerator: {}", self.export());
1230        debug!("Parsing gamma simplified numerator into tensor network");
1231        Ok(Numerator {
1232            state: Network {
1233                net: ParsingNet::try_from_view(
1234                    self.state.expr.as_view(),
1235                    TENSORLIB.read().unwrap().deref(),
1236                    &ParseSettings::default(),
1237                )?,
1238            },
1239        })
1240    }
1241
1242    // pub(crate) fn parse_only_colorless(self) -> Numerator<Network> {
1243    //     debug!("Parsing only colorless gamma simplified numerator into tensor network");
1244    //     Numerator {
1245    //         state: self.state.parse_only_colorless(),
1246    //     }
1247    // }
1248}
1249
1250pub type ParsingNet = spenso::network::Network<
1251    NetworkStore<ParamTensor<ShadowedStructure<Aind>>, Atom>,
1252    ExplicitKey<Aind>,
1253    Symbol,
1254    Aind,
1255>;
1256
1257#[derive(Debug, Clone, bincode_trait_derive::Encode, bincode_trait_derive::Decode)]
1258#[trait_decode(trait = symbolica::state::HasStateMap)]
1259pub struct Network {
1260    // #[bincode(with_serde
1261    pub net: ParsingNet,
1262}
1263
1264impl TryFrom<PythonState> for Network {
1265    type Error = NumeratorStateError;
1266
1267    fn try_from(value: PythonState) -> std::result::Result<Self, Self::Error> {
1268        match value {
1269            PythonState::Network(s) => {
1270                if let Some(s) = s {
1271                    Ok(s)
1272                } else {
1273                    Err(NumeratorStateError::NoneVariant)
1274                }
1275            }
1276            _ => Err(NumeratorStateError::NotNetwork),
1277        }
1278    }
1279}
1280
1281#[derive(Clone, Copy, Debug)]
1282pub struct ContractionSettings {
1283    n_steps: Option<usize>,
1284    mode: ExecutionMode,
1285}
1286
1287impl From<()> for ContractionSettings {
1288    fn from(_: ()) -> Self {
1289        Self {
1290            n_steps: None,
1291            mode: ExecutionMode::All,
1292        }
1293    }
1294}
1295
1296impl Default for ContractionSettings {
1297    fn default() -> Self {
1298        Self {
1299            n_steps: None,
1300            mode: ExecutionMode::All,
1301        }
1302    }
1303}
1304
1305#[derive(Clone, Copy, Debug)]
1306pub enum ExecutionMode {
1307    Single,
1308    Scalar,
1309    All,
1310}
1311
1312impl Network {
1313    pub(crate) fn parse_impl(expr: AtomView) -> Self {
1314        let lib = DummyLibrary::<ParamTensor<ShadowedStructure<Aind>>, _>::new();
1315        let net = ParsingNet::try_from_view(expr, &lib, &ParseSettings::default()).unwrap();
1316
1317        // println!("net scalar{}", net.scalar.as_ref().unwrap());
1318        Network { net }
1319    }
1320
1321    pub(crate) fn contract(&mut self, settings: impl Into<ContractionSettings>) -> Result<()> {
1322        let lib = TENSORLIB.read().unwrap();
1323        let fnlib = FUN_LIB.deref();
1324        let settings = settings.into();
1325        debug!(
1326            "Contracting network:{} with settings: {:#?}",
1327            self.net.dot(),
1328            settings
1329        );
1330        if let Some(n) = settings.n_steps {
1331            for _ in 0..n {
1332                match settings.mode {
1333                    ExecutionMode::All => self
1334                        .net
1335                        .execute::<Steps<1>, MinResultRank, _, _, _>(lib.deref(), fnlib)?,
1336                    ExecutionMode::Scalar => self
1337                        .net
1338                        .execute::<Steps<1>, ContractScalars, _, _, _>(lib.deref(), fnlib)?,
1339                    ExecutionMode::Single => self
1340                        .net
1341                        .execute::<Steps<1>, SingleSmallestDegree<false>, _, _, _>(
1342                            lib.deref(),
1343                            fnlib,
1344                        )?,
1345                }
1346            }
1347        } else {
1348            match settings.mode {
1349                ExecutionMode::All => {
1350                    self.net
1351                        .execute::<Sequential, MinResultRank, _, _, _>(lib.deref(), fnlib)?;
1352                }
1353                ExecutionMode::Scalar => {
1354                    self.net
1355                        .execute::<Sequential, ContractScalars, _, _, _>(lib.deref(), fnlib)?;
1356                }
1357                ExecutionMode::Single => {
1358                    self.net
1359                        .execute::<Sequential, SingleSmallestDegree<false>, _, _, _>(
1360                            lib.deref(),
1361                            fnlib,
1362                        )?;
1363                }
1364            }
1365        }
1366        Ok(())
1367    }
1368}
1369
1370impl NumeratorState for Network {
1371    fn export(&self) -> String {
1372        " self.expression.to_string()".to_string()
1373    }
1374
1375    fn forget_type(self) -> PythonState {
1376        PythonState::Network(Some(self))
1377    }
1378
1379    fn update_model(&mut self, _model: &Model) -> Result<()> {
1380        Err(eyre!(
1381            "Only applied feynman rule, simplified color, gamma and parsed into network, nothing to update"
1382        ))
1383    }
1384}
1385
1386impl TypedNumeratorState for Network {
1387    fn apply<F, S: TypedNumeratorState>(
1388        num: &mut Numerator<PythonState>,
1389        mut f: F,
1390    ) -> Result<(), NumeratorStateError>
1391    where
1392        F: FnMut(Numerator<Self>) -> Numerator<S>,
1393    {
1394        if let PythonState::Network(s) = &mut num.state {
1395            if let Some(s) = s.take() {
1396                *num = f(Numerator { state: s }).forget_type();
1397                return Ok(());
1398            } else {
1399                return Err(NumeratorStateError::NoneVariant);
1400            }
1401        }
1402        Err(NumeratorStateError::NotNetwork)
1403    }
1404}
1405
1406#[derive(Debug, Clone, bincode_trait_derive::Encode, bincode_trait_derive::Decode)]
1407#[trait_decode(trait = symbolica::state::HasStateMap)]
1408pub struct Contracted {
1409    pub tensor: ParamTensor<ShadowedStructure<Aind>>,
1410}
1411
1412impl TryFrom<PythonState> for Contracted {
1413    type Error = NumeratorStateError;
1414
1415    fn try_from(value: PythonState) -> std::result::Result<Self, Self::Error> {
1416        match value {
1417            PythonState::Contracted(s) => {
1418                if let Some(s) = s {
1419                    Ok(s)
1420                } else {
1421                    Err(NumeratorStateError::NoneVariant)
1422                }
1423            }
1424            _ => Err(NumeratorStateError::NotContracted),
1425        }
1426    }
1427}
1428
1429impl Contracted {
1430    pub(crate) fn one() -> Self {
1431        Contracted {
1432            tensor: ParamTensor::new_scalar(Atom::one()),
1433        }
1434    }
1435
1436    pub(crate) fn zero() -> Self {
1437        Contracted {
1438            tensor: ParamTensor::new_scalar(Atom::Zero),
1439        }
1440    }
1441
1442    pub(crate) fn generate_kinematic_params_impl(
1443        n_edges: usize,
1444        pol_data: Vec<(String, i64, usize)>,
1445    ) -> Vec<Atom> {
1446        fn atoms_for_pol(name: String, num: i64, size: usize) -> Vec<Atom> {
1447            let mut data = vec![];
1448            for index in 0..size {
1449                let e = FunctionBuilder::new(symbol!(&name));
1450                data.push(
1451                    e.add_arg(Atom::num(num))
1452                        .add_arg(parse!(&format!("cind({})", index)))
1453                        .finish(),
1454                );
1455            }
1456            data
1457        }
1458        let mut params: Vec<Atom> = vec![];
1459
1460        let mut pols = Vec::new();
1461
1462        for i in 0..n_edges {
1463            let named_structure: NamedStructure<String> =
1464                NamedStructure::from_iter([Lorentz {}.new_slot(4, i)], "Q".into(), Some(i))
1465                    .into_canonical();
1466            params.extend(
1467                named_structure
1468                    .to_shell()
1469                    .expanded_shadow()
1470                    .unwrap()
1471                    .data
1472                    .clone(),
1473            );
1474        }
1475
1476        for (name, num, size) in pol_data {
1477            pols.extend(atoms_for_pol(name, num, size));
1478        }
1479
1480        params.extend(pols);
1481        params.push(Atom::i());
1482
1483        params
1484    }
1485}
1486
1487impl NumeratorState for Contracted {
1488    fn export(&self) -> String {
1489        self.tensor.to_string()
1490    }
1491    fn forget_type(self) -> PythonState {
1492        PythonState::Contracted(Some(self))
1493    }
1494
1495    fn update_model(&mut self, _model: &Model) -> Result<()> {
1496        Err(eyre!(
1497            "Only applied feynman rule, simplified color, gamma, parsed into network and contracted, nothing to update"
1498        ))
1499    }
1500}
1501
1502impl TypedNumeratorState for Contracted {
1503    fn apply<F, S: TypedNumeratorState>(
1504        num: &mut Numerator<PythonState>,
1505        mut f: F,
1506    ) -> Result<(), NumeratorStateError>
1507    where
1508        F: FnMut(Numerator<Self>) -> Numerator<S>,
1509    {
1510        if let PythonState::Contracted(s) = &mut num.state {
1511            if let Some(s) = s.take() {
1512                *num = f(Numerator { state: s }).forget_type();
1513                return Ok(());
1514            } else {
1515                return Err(NumeratorStateError::NoneVariant);
1516            }
1517        }
1518        Err(NumeratorStateError::NotContracted)
1519    }
1520}
1521
1522impl Numerator<Contracted> {
1523    fn generate_fn_map(&self) -> FunctionMap {
1524        let mut map = FunctionMap::new();
1525        Numerator::<Contracted>::add_consts_to_fn_map(&mut map);
1526        map
1527    }
1528    // #[allow(clippy::too_many_arguments)]
1529    // pub(crate) fn generate_evaluators_from_params(
1530    //     self,
1531    //     n_edges: usize,
1532    //     name: &str,
1533    //     model_params_start: usize,
1534    //     params: &[Atom],
1535    //     double_param_values: Vec<Complex<F<f64>>>,
1536    //     quad_param_values: Vec<Complex<F<f128>>>,
1537    //     extra_info: &ExtraInfo,
1538    //     export_settings: &GenerationSettings,
1539    // ) -> Numerator<Evaluators> {
1540    //     let o = &export_settings.numerator_settings.eval_settings;
1541    //     let owned_fn_map = self.generate_fn_map();
1542
1543    //     let inline_asm = export_settings.compile.inline_asm();
1544    //     let compile_options = export_settings
1545    //         .compile
1546    //         .to_symbolica_compile_options();
1547
1548    //     let eval_settings = NumeratorEvaluatorSettings {
1549    //         options: o,
1550    //         inline_asm,
1551    //         compile_options,
1552    //     };
1553
1554    //     let fn_map: FunctionMap = owned_fn_map;
1555    //     let single = self.state.evaluator(
1556    //         extra_info.path.clone(),
1557    //         name,
1558    //         &eval_settings,
1559    //         params,
1560    //         &fn_map,
1561    //     );
1562
1563    //     match o {
1564    //         NumeratorEvaluatorOptions::Joint(_) => Numerator {
1565    //             state: Evaluators {
1566    //                 orientated: Some(single.orientated_joint_impl(
1567    //                     n_edges,
1568    //                     name,
1569    //                     params,
1570    //                     extra_info,
1571    //                     &eval_settings,
1572    //                     &fn_map,
1573    //                 )),
1574    //                 single,
1575    //                 choice: SingleOrCombined::Combined,
1576    //                 orientations: extra_info.orientations.clone(),
1577    //                 quad_param_values,
1578    //                 double_param_values,
1579    //                 model_params_start,
1580    //                 emr_len: n_edges,
1581    //                 fn_map,
1582    //             },
1583    //         },
1584    //         NumeratorEvaluatorOptions::Iterative(IterativeOptions {
1585    //             iterations,
1586    //             n_cores,
1587    //             verbose,
1588    //             ..
1589    //         }) => Numerator {
1590    //             state: Evaluators {
1591    //                 orientated: Some(single.orientated_iterative_impl(
1592    //                     n_edges,
1593    //                     name,
1594    //                     params,
1595    //                     extra_info,
1596    //                     &eval_settings,
1597    //                     *iterations,
1598    //                     *n_cores,
1599    //                     *verbose,
1600    //                     &fn_map,
1601    //                 )),
1602    //                 single,
1603    //                 choice: SingleOrCombined::Combined,
1604    //                 orientations: extra_info.orientations.clone(),
1605    //                 quad_param_values,
1606    //                 double_param_values,
1607    //                 model_params_start,
1608    //                 emr_len: n_edges,
1609    //                 fn_map,
1610    //             },
1611    //         },
1612    //         _ => Numerator {
1613    //             state: Evaluators {
1614    //                 orientated: None,
1615    //                 single,
1616    //                 choice: SingleOrCombined::Single,
1617    //                 orientations: extra_info.orientations.clone(),
1618    //                 quad_param_values,
1619    //                 double_param_values,
1620    //                 model_params_start,
1621    //                 emr_len: n_edges,
1622    //                 fn_map,
1623    //             },
1624    //         },
1625    //     }
1626    // }
1627}
1628
1629#[derive(Debug, Clone, Serialize, Deserialize, Encode, Decode, PartialEq)]
1630pub struct IterativeOptions {
1631    pub eval_options: EvaluatorOptions,
1632    pub iterations: usize,
1633    pub n_cores: usize,
1634    pub verbose: bool,
1635}
1636
1637#[derive(Debug, Clone, Serialize, Deserialize, Encode, Decode, PartialEq)]
1638pub enum NumeratorParseMode {
1639    Polynomial,
1640    Direct,
1641}
1642
1643#[derive(Debug, Clone, Serialize, Deserialize, Encode, Decode, PartialEq)]
1644#[serde(tag = "type")]
1645pub enum NumeratorEvaluatorOptions {
1646    #[serde(rename = "Single")]
1647    Single(EvaluatorOptions),
1648    #[serde(rename = "Joint")]
1649    Joint(EvaluatorOptions),
1650    #[serde(rename = "Iterative")]
1651    Iterative(IterativeOptions),
1652}
1653
1654#[derive(Clone)]
1655pub struct NumeratorEvaluatorSettings<'a> {
1656    pub options: &'a NumeratorEvaluatorOptions,
1657    pub inline_asm: InlineASM,
1658    pub compile_options: CompileOptions,
1659}
1660
1661impl Default for NumeratorEvaluatorOptions {
1662    fn default() -> Self {
1663        NumeratorEvaluatorOptions::Single(EvaluatorOptions::default())
1664    }
1665}
1666
1667impl NumeratorEvaluatorOptions {
1668    pub(crate) fn compile_options(&self) -> NumeratorCompileOptions {
1669        match self {
1670            NumeratorEvaluatorOptions::Single(options) => options.compile_options,
1671            NumeratorEvaluatorOptions::Joint(options) => options.compile_options,
1672            NumeratorEvaluatorOptions::Iterative(options) => options.eval_options.compile_options,
1673        }
1674    }
1675
1676    pub(crate) fn cpe_rounds(&self) -> Option<usize> {
1677        match self {
1678            NumeratorEvaluatorOptions::Single(options) => options.cpe_rounds,
1679            NumeratorEvaluatorOptions::Joint(options) => options.cpe_rounds,
1680            NumeratorEvaluatorOptions::Iterative(options) => options.eval_options.cpe_rounds,
1681        }
1682    }
1683}
1684
1685#[derive(Debug, Clone, Serialize, Deserialize, Copy, PartialEq, Eq, Hash, Encode, Decode)]
1686pub struct EvaluatorOptions {
1687    pub cpe_rounds: Option<usize>,
1688    pub compile_options: NumeratorCompileOptions,
1689}
1690
1691impl Default for EvaluatorOptions {
1692    fn default() -> Self {
1693        EvaluatorOptions {
1694            cpe_rounds: Some(1),
1695            compile_options: NumeratorCompileOptions::Compiled,
1696        }
1697    }
1698}
1699
1700#[derive(Debug, Clone, Serialize, Deserialize, Copy, PartialEq, Eq, Hash, Encode, Decode)]
1701#[serde(tag = "subtype")]
1702pub enum NumeratorCompileOptions {
1703    #[serde(rename = "Compiled")]
1704    Compiled,
1705    #[serde(rename = "NotCompiled")]
1706    NotCompiled,
1707}
1708
1709impl NumeratorCompileOptions {
1710    pub(crate) fn compile(&self) -> bool {
1711        matches!(self, NumeratorCompileOptions::Compiled)
1712    }
1713}
1714
1715#[derive(Error, Debug)]
1716pub enum NumeratorStateError {
1717    #[error("Not UnInit")]
1718    NotUnit,
1719    #[error("Not AppliedFeynmanRule")]
1720    NotAppliedFeynmanRule,
1721    #[error("Not ColorProjected")]
1722    NotColorProjected,
1723    #[error("Not Global")]
1724    NotGlobal,
1725    #[error("Not ColorSimplified")]
1726    NotColorSimplified,
1727    #[error("Not GammaSymplified")]
1728    NotGammaSymplified,
1729    #[error("Not Network")]
1730    NotNetwork,
1731    #[error("Not Contracted")]
1732    NotContracted,
1733    #[error("Not Evaluators")]
1734    NotEvaluators,
1735    #[error("None variant")]
1736    NoneVariant,
1737    #[error("Expanded")]
1738    Expanded,
1739    #[error("Any")]
1740    Any(#[from] eyre::Report),
1741}
1742
1743#[derive(Debug, Clone, bincode_trait_derive::Encode, bincode_trait_derive::Decode)]
1744#[trait_decode(trait = symbolica::state::HasStateMap)]
1745#[allow(clippy::large_enum_variant)]
1746pub enum PythonState {
1747    UnInit(Option<UnInit>),
1748    Global(Option<Global>),
1749    AppliedFeynmanRule(Option<AppliedFeynmanRule>),
1750    ColorSimplified(Option<ColorSimplified>),
1751    // ColorProjected(Option<ColorProjected>),
1752    GammaSimplified(Option<GammaSimplified>),
1753    Network(Option<Network>),
1754    Contracted(Option<Contracted>),
1755    PolyContracted(Option<PolyContracted>),
1756}
1757
1758impl Default for PythonState {
1759    fn default() -> Self {
1760        PythonState::UnInit(Some(UnInit))
1761    }
1762}
1763
1764impl NumeratorState for PythonState {
1765    fn export(&self) -> String {
1766        match self {
1767            PythonState::UnInit(state) => {
1768                if let Some(s) = state {
1769                    s.export()
1770                } else {
1771                    "None".into()
1772                }
1773            }
1774            PythonState::Global(state) => {
1775                if let Some(s) = state {
1776                    s.export()
1777                } else {
1778                    "None".into()
1779                }
1780            }
1781            PythonState::AppliedFeynmanRule(state) => {
1782                if let Some(s) = state {
1783                    s.export()
1784                } else {
1785                    "None".into()
1786                }
1787            }
1788            PythonState::ColorSimplified(state) => {
1789                if let Some(s) = state {
1790                    s.export()
1791                } else {
1792                    "None".into()
1793                }
1794            }
1795
1796            // PythonState::ColorProjected(state) => {
1797            //     if let Some(s) = state {
1798            //         s.export()
1799            //     } else {
1800            //         "None".into()
1801            //     }
1802            // }
1803            PythonState::GammaSimplified(state) => {
1804                if let Some(s) = state {
1805                    s.export()
1806                } else {
1807                    "None".into()
1808                }
1809            }
1810            PythonState::Network(state) => {
1811                if let Some(s) = state {
1812                    s.export()
1813                } else {
1814                    "None".into()
1815                }
1816            }
1817            PythonState::Contracted(state) => {
1818                if let Some(s) = state {
1819                    s.export()
1820                } else {
1821                    "None".into()
1822                }
1823            }
1824            PythonState::PolyContracted(state) => {
1825                if let Some(s) = state {
1826                    s.export()
1827                } else {
1828                    "None".into()
1829                }
1830            }
1831        }
1832    }
1833
1834    fn forget_type(self) -> PythonState {
1835        self
1836    }
1837
1838    fn update_model(&mut self, model: &Model) -> Result<()> {
1839        match self {
1840            PythonState::Global(state) => {
1841                if let Some(s) = state {
1842                    s.update_model(model)
1843                } else {
1844                    Err(NumeratorStateError::NoneVariant.into())
1845                }
1846            }
1847            PythonState::AppliedFeynmanRule(state) => {
1848                if let Some(s) = state {
1849                    s.update_model(model)
1850                } else {
1851                    Err(NumeratorStateError::NoneVariant.into())
1852                }
1853            }
1854            PythonState::ColorSimplified(state) => {
1855                if let Some(s) = state {
1856                    s.update_model(model)
1857                } else {
1858                    Err(NumeratorStateError::NoneVariant.into())
1859                }
1860            }
1861            PythonState::GammaSimplified(state) => {
1862                if let Some(s) = state {
1863                    s.update_model(model)
1864                } else {
1865                    Err(NumeratorStateError::NoneVariant.into())
1866                }
1867            }
1868            PythonState::Network(state) => {
1869                if let Some(s) = state {
1870                    s.update_model(model)
1871                } else {
1872                    Err(NumeratorStateError::NoneVariant.into())
1873                }
1874            }
1875            PythonState::Contracted(state) => {
1876                if let Some(s) = state {
1877                    s.update_model(model)
1878                } else {
1879                    Err(NumeratorStateError::NoneVariant.into())
1880                }
1881            }
1882            PythonState::PolyContracted(state) => {
1883                if let Some(s) = state {
1884                    s.update_model(model)
1885                } else {
1886                    Err(NumeratorStateError::NoneVariant.into())
1887                }
1888            }
1889
1890            _ => Err(eyre!("No model to update")),
1891        }
1892    }
1893}
1894
1895impl GetSingleAtom for PythonState {
1896    fn get_single_atom(&self) -> Result<Atom, NumeratorStateError> {
1897        match self {
1898            PythonState::Global(state) => {
1899                if let Some(s) = state {
1900                    s.get_single_atom()
1901                } else {
1902                    Err(NumeratorStateError::NoneVariant)
1903                }
1904            }
1905            PythonState::AppliedFeynmanRule(state) => {
1906                if let Some(s) = state {
1907                    s.get_single_atom()
1908                } else {
1909                    Err(NumeratorStateError::NoneVariant)
1910                }
1911            }
1912            PythonState::ColorSimplified(state) => {
1913                if let Some(s) = state {
1914                    s.get_single_atom()
1915                } else {
1916                    Err(NumeratorStateError::NoneVariant)
1917                }
1918            }
1919            PythonState::GammaSimplified(state) => {
1920                if let Some(s) = state {
1921                    s.get_single_atom()
1922                } else {
1923                    Err(NumeratorStateError::NoneVariant)
1924                }
1925            }
1926            _ => Err(NumeratorStateError::Expanded),
1927        }
1928    }
1929}