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};
30use 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;
42use 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)]
87pub struct NumeratorSettings {
89 #[serde(default, skip_serializing_if = "IsDefault::is_default")]
90 pub eval_settings: NumeratorEvaluatorOptions,
91 pub parse_mode: NumeratorParseMode,
93 pub dump_expression: Option<ExpressionFormat>,
95 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 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
168impl<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 }
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 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 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 }
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 expr: expression,
612 state: Self::default(),
613 }
614 }
615
616 fn new_color(expression: Atom) -> SymbolicExpression<Self> {
617 SymbolicExpression {
618 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 let state = ColorSimplified {
717 expr: self.state.expr.simplify_color(),
718 state: Color::Fully,
719 };
720 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, 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 }
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 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
929impl 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)]
958pub 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 Network { net }
1207 }
1208
1209 }
1226
1227impl Numerator<GammaSimplified> {
1228 pub(crate) fn parse(self) -> Result<Numerator<Network>> {
1229 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 }
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 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 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 }
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 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::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}