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};
31use 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;
46use 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)]
83pub struct NumeratorSettings {
85 #[serde(default, skip_serializing_if = "IsDefault::is_default")]
86 pub eval_settings: NumeratorEvaluatorOptions,
87 pub parse_mode: NumeratorParseMode,
89 pub dump_expression: Option<ExpressionFormat>,
91 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 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
164impl<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 }
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 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 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 }
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 expr: expression,
615 state: Self::default(),
616 }
617 }
618
619 fn new_color(expression: Atom) -> SymbolicExpression<Self> {
620 SymbolicExpression {
621 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 let state = ColorSimplified {
720 expr: self.state.expr.simplify_color(),
721 state: Color::Fully,
722 };
723 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, 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 }
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 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
932impl 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)]
961pub 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 Network { net }
1210 }
1211
1212 }
1229
1230impl Numerator<GammaSimplified> {
1231 pub(crate) fn parse(self) -> Result<Numerator<Network>> {
1232 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 }
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 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 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 }
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 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::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