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