1use linnet::half_edge::{
2 HedgeGraph,
3 involution::{EdgeData, Flow, Orientation},
4 subgraph::{SuBitGraph, SubSetLike},
5};
6use spenso::{
7 iterators::IteratableTensor,
8 network::parsing::ShadowedStructure,
9 shadowing::Concretize,
10 structure::{PermutedStructure, TensorStructure},
11 tensors::parametric::ParamTensor,
12};
13use symbolica::atom::{Atom, AtomOrView, FunctionBuilder, Symbol};
14
15use crate::{
16 graph::{Edge, Graph, HedgeData, edge::ParseEdge},
17 model::ArcParticle,
18 utils::GS,
19};
20
21use super::aind::Aind;
22
23pub trait HedgePolarizationData {
24 fn polarization(&self, builder: FunctionBuilder) -> Atom;
25
26 fn edge_spin_slots<'a>(
27 &'a self,
28 ) -> impl Iterator<Item = spenso::structure::representation::LibrarySlot<Aind>> + 'a;
29}
30
31impl HedgePolarizationData for HedgeData {
32 fn polarization(&self, builder: FunctionBuilder) -> Atom {
33 HedgeData::polarization(self, builder)
34 }
35
36 fn edge_spin_slots<'a>(
37 &'a self,
38 ) -> impl Iterator<Item = spenso::structure::representation::LibrarySlot<Aind>> + 'a {
39 HedgeData::edge_spin_slots(self)
40 }
41}
42
43pub trait GeneratePolarizations {
44 fn generate_polarizations_of<S: SubSetLike>(&self, subgraph: &S) -> Atom;
47 fn generate_polarization_parameters_of<S: SubSetLike>(&self, subgraph: &S) -> Vec<Atom>;
48 }
51
52impl Graph {
53 pub fn generate_polarizations(&self) -> Atom {
54 self.generate_polarizations_of(&self.underlying.external_filter::<SuBitGraph>())
55 }
56 pub fn generate_polarization_params(&self) -> Vec<Atom> {
57 self.generate_polarization_parameters_of(&self.underlying.external_filter::<SuBitGraph>())
58 }
59}
60
61impl GeneratePolarizations for Graph {
62 fn generate_polarizations_of<S: SubSetLike>(&self, subgraph: &S) -> Atom {
63 self.underlying.generate_polarizations_of(subgraph)
64 }
65
66 fn generate_polarization_parameters_of<S: SubSetLike>(&self, subgraph: &S) -> Vec<Atom> {
67 self.underlying
68 .generate_polarization_parameters_of(subgraph)
69 }
70
71 }
82
83impl<V, E> GeneratePolarizations for HedgeGraph<E, V, HedgeData>
84where
85 for<'a> EdgeData<&'a E>: ReversibleEdge,
86{
87 fn generate_polarizations_of<S: SubSetLike>(&self, subgraph: &S) -> Atom {
88 let mut pols = Atom::num(1);
89
90 for h in subgraph.included_iter() {
91 let eid = self[&h];
92 pols *= self.get_edge_data_full(h).polarization(
93 &[Atom::num(eid.0)],
94 &self[h],
95 self.flow(h),
96 );
97 }
98
99 pols
100 }
101
102 fn generate_polarization_parameters_of<S: SubSetLike>(&self, subgraph: &S) -> Vec<Atom> {
103 let mut pols = Vec::new();
104
105 for h in subgraph.included_iter() {
106 let eid = self[&h];
107
108 let Some(pol) = self.get_edge_data_full(h).polarization_structure(
109 &[Atom::num(eid.0)],
110 &self[h],
111 self.flow(h),
112 ) else {
113 continue;
114 };
115
116 let concrete: ParamTensor<_> = pol
117 .structure
118 .to_shell()
119 .concretize(Some(pol.index_permutation));
120
121 for (_, i) in concrete.iter_flat() {
122 pols.push(i.to_owned());
123 }
124 }
125
126 pols
127 }
128
129 }
140
141pub trait ReversibleEdge {
142 fn pdg(&self) -> isize;
143
144 fn pol_symbol(&self, flow: Flow) -> Option<Symbol>;
145
146 fn polarization<'a, T, H>(&self, add_args: &'a [T], hedge_data: &H, flow: Flow) -> Atom
147 where
148 &'a T: Into<AtomOrView<'a>>,
149 H: HedgePolarizationData;
150
151 fn polarization_structure<'a, T, H>(
152 &self,
153 add_args: &'a [T],
154 hedge_data: &H,
155 flow: Flow,
156 ) -> Option<PermutedStructure<ShadowedStructure<Aind>>>
157 where
158 &'a T: Into<AtomOrView<'a>>,
159 H: HedgePolarizationData;
160}
161
162impl ReversibleEdge for EdgeData<&Edge> {
163 fn pdg(&self) -> isize {
164 if let Some(p) = self.data.particle() {
165 match self.orientation {
166 Orientation::Default | Orientation::Undirected => p.pdg_code,
167 Orientation::Reversed => -p.pdg_code,
168 }
169 } else {
170 0
171 }
172 }
173
174 fn pol_symbol(&self, flow: Flow) -> Option<Symbol> {
175 if let Some(p) = self.data.particle() {
176 match (p.spin, flow) {
178 (2, Flow::Sink) => {
179 if self.pdg() > 0 {
180 Some(GS.u)
181 } else {
182 Some(GS.vbar)
183 }
184 }
185 (2, Flow::Source) => {
186 if self.pdg() > 0 {
187 Some(GS.ubar)
188 } else {
189 Some(GS.v)
190 }
191 }
192 (3, Flow::Sink) => Some(GS.epsilon),
193 (3, Flow::Source) => Some(GS.epsilonbar),
194 _ => None,
195 }
196 } else {
197 None
198 }
199 }
200
201 fn polarization<'a, T, H>(&self, add_args: &'a [T], hedge_data: &H, flow: Flow) -> Atom
202 where
203 &'a T: Into<AtomOrView<'a>>,
204 H: HedgePolarizationData,
205 {
206 if let Some(name) = self.pol_symbol(flow) {
207 hedge_data.polarization(FunctionBuilder::new(name).add_args(add_args))
208 } else {
209 Atom::num(1)
210 }
211 }
212
213 fn polarization_structure<'a, T, H>(
214 &self,
215 add_args: &'a [T],
216 hedge_data: &H,
217 flow: Flow,
218 ) -> Option<PermutedStructure<ShadowedStructure<Aind>>>
219 where
220 &'a T: Into<AtomOrView<'a>>,
221 H: HedgePolarizationData,
222 {
223 self.pol_symbol(flow).map(|name| {
224 ShadowedStructure::from_iter(
225 hedge_data.edge_spin_slots(),
226 name,
227 Some(add_args.iter().map(|arg| arg.into().into_owned()).collect()),
228 )
229 })
230 }
231}
232
233impl ReversibleEdge for EdgeData<&ParseEdge> {
234 fn pdg(&self) -> isize {
235 if let Some(p) = self.data.particle.particle() {
236 match self.orientation {
237 Orientation::Default | Orientation::Undirected => p.pdg_code,
238 Orientation::Reversed => p.pdg_code,
239 }
240 } else {
241 0
242 }
243 }
244
245 fn pol_symbol(&self, flow: Flow) -> Option<Symbol> {
246 if let Some(p) = self.data.particle.particle() {
247 match (p.spin, flow) {
255 (2, Flow::Sink) => {
256 if self.pdg() > 0 {
257 Some(GS.u)
259 } else {
260 Some(GS.vbar)
262 }
263 }
264 (2, Flow::Source) => {
265 if self.pdg() > 0 {
266 Some(GS.ubar)
268 } else {
269 Some(GS.v)
271 }
272 }
273 (3, Flow::Sink) => Some(GS.epsilon),
274 (3, Flow::Source) => Some(GS.epsilonbar),
275 _ => None,
276 }
277 } else {
278 None
279 }
280 }
281
282 fn polarization<'a, T, H>(&self, add_args: &'a [T], hedge_data: &H, flow: Flow) -> Atom
283 where
284 &'a T: Into<AtomOrView<'a>>,
285 H: HedgePolarizationData,
286 {
287 if let Some(name) = self.pol_symbol(flow) {
288 hedge_data.polarization(FunctionBuilder::new(name).add_args(add_args))
289 } else {
290 Atom::num(1)
291 }
292 }
293
294 fn polarization_structure<'a, T, H>(
295 &self,
296 add_args: &'a [T],
297 hedge_data: &H,
298 flow: Flow,
299 ) -> Option<PermutedStructure<ShadowedStructure<Aind>>>
300 where
301 &'a T: Into<AtomOrView<'a>>,
302 H: HedgePolarizationData,
303 {
304 self.pol_symbol(flow).map(|name| {
305 ShadowedStructure::from_iter(
306 hedge_data.edge_spin_slots(),
307 name,
308 Some(add_args.iter().map(|arg| arg.into().into_owned()).collect()),
309 )
310 })
311 }
312}
313
314impl ReversibleEdge for EdgeData<(usize, isize)> {
315 fn pdg(&self) -> isize {
316 match self.orientation {
317 Orientation::Default | Orientation::Undirected => self.data.1,
318 Orientation::Reversed => -self.data.1,
319 }
320 }
321
322 fn pol_symbol(&self, flow: Flow) -> Option<Symbol> {
323 match (self.data.0, flow) {
324 (2, Flow::Sink) => {
325 if self.pdg() > 0 {
326 Some(GS.u)
327 } else {
328 Some(GS.vbar)
329 }
330 }
331 (2, Flow::Source) => {
332 if self.pdg() > 0 {
333 Some(GS.ubar)
334 } else {
335 Some(GS.v)
336 }
337 }
338 (3, Flow::Sink) => Some(GS.epsilon),
339 (3, Flow::Source) => Some(GS.epsilonbar),
340 _ => None,
341 }
342 }
343
344 fn polarization<'a, T, H>(&self, add_args: &'a [T], hedge_data: &H, flow: Flow) -> Atom
345 where
346 &'a T: Into<AtomOrView<'a>>,
347 H: HedgePolarizationData,
348 {
349 if let Some(name) = self.pol_symbol(flow) {
350 hedge_data.polarization(FunctionBuilder::new(name).add_args(add_args))
351 } else {
352 Atom::num(1)
353 }
354 }
355
356 fn polarization_structure<'a, T, H>(
357 &self,
358 add_args: &'a [T],
359 hedge_data: &H,
360 flow: Flow,
361 ) -> Option<PermutedStructure<ShadowedStructure<Aind>>>
362 where
363 &'a T: Into<AtomOrView<'a>>,
364 H: HedgePolarizationData,
365 {
366 self.pol_symbol(flow).map(|name| {
367 ShadowedStructure::from_iter(
368 hedge_data.edge_spin_slots(),
369 name,
370 Some(add_args.iter().map(|arg| arg.into().into_owned()).collect()),
371 )
372 })
373 }
374}
375
376impl ReversibleEdge for EdgeData<ArcParticle> {
377 fn pdg(&self) -> isize {
378 match self.orientation {
379 Orientation::Default | Orientation::Undirected => self.data.pdg_code,
380 Orientation::Reversed => -self.data.pdg_code,
381 }
382 }
383
384 fn pol_symbol(&self, flow: Flow) -> Option<Symbol> {
385 match (self.data.spin, flow) {
386 (2, Flow::Sink) => {
387 if self.pdg() > 0 {
388 Some(GS.u)
389 } else {
390 Some(GS.vbar)
391 }
392 }
393 (2, Flow::Source) => {
394 if self.pdg() > 0 {
395 Some(GS.ubar)
396 } else {
397 Some(GS.v)
398 }
399 }
400 (3, Flow::Sink) => Some(GS.epsilon),
401 (3, Flow::Source) => Some(GS.epsilonbar),
402 _ => None,
403 }
404 }
405
406 fn polarization<'a, T, H>(&self, add_args: &'a [T], hedge_data: &H, flow: Flow) -> Atom
407 where
408 &'a T: Into<AtomOrView<'a>>,
409 H: HedgePolarizationData,
410 {
411 if let Some(name) = self.pol_symbol(flow) {
412 hedge_data.polarization(FunctionBuilder::new(name).add_args(add_args))
413 } else {
414 Atom::num(1)
415 }
416 }
417
418 fn polarization_structure<'a, T, H>(
419 &self,
420 add_args: &'a [T],
421 hedge_data: &H,
422 flow: Flow,
423 ) -> Option<PermutedStructure<ShadowedStructure<Aind>>>
424 where
425 &'a T: Into<AtomOrView<'a>>,
426 H: HedgePolarizationData,
427 {
428 self.pol_symbol(flow).map(|name| {
429 ShadowedStructure::from_iter(
430 hedge_data.edge_spin_slots(),
431 name,
432 Some(add_args.iter().map(|arg| arg.into().into_owned()).collect()),
433 )
434 })
435 }
436}
437
438#[cfg(test)]
439mod test {
440
441 use idenso::{color::ColorSimplifier, dirac::GammaSimplifier, tensor::SymbolicNetParse};
443
444 use spenso::network::parsing::ParseSettings;
445 use symbolica::{
446 atom::{Atom, AtomCore},
447 parse_lit,
448 };
449
450 use crate::{
451 dot,
452 graph::{Graph, parse::IntoGraph},
453 initialisation::{initialise, test_initialise},
454 numerator::aind::Aind,
455 processes::{Amplitude, AmplitudeGraph, DotExportSettings},
456 settings::{
457 GlobalSettings, RuntimeSettings,
458 global::{GenerationSettings, OrientationPattern},
459 runtime::{LockedRuntimeSettings, kinematic::KinematicsSettings},
460 },
461 uv::UltravioletGraph,
462 };
463
464 #[test]
465 fn qqx_aaa_tree() {
466 test_initialise().unwrap();
467
468 let mut graph:AmplitudeGraph = dot!(digraph qqx_aaa_tree_1 {
469 num="spenso::g(spenso::dind(spenso::cof(3, hedge(1))), spenso::cof(3, hedge(2)))/3"
470 ext [style=invis]
471 ext -> v1:1 [particle="d" id=1];
472 ext -> v3:2 [particle="d~" id=2];
473 v1:3 -> ext [particle="a" id=3];
474 v2:4 -> ext [particle="a" id=4];
475 v3:0 -> ext [particle="a" id=0];
476 v1 -> v2 [particle="d" id=5];
477 v2 -> v3 [particle="d" id=6];
478 }).unwrap();
479
480 let vk = crate::utils::vakint().unwrap();
481
482 graph.generate_cff(&OrientationPattern::default()).unwrap();
485 graph
486 .build_integrands(&GenerationSettings::default(), vk)
487 .unwrap();
488
489 println!("{}", graph.derived_data.all_mighty_integrand);
490 }
491
492 #[test]
493 fn simplify() {
494 test_initialise().unwrap();
495 let expr = parse_lit!(
496 -GC_1 * GC_11
497 ^ 2 * Q(4, mink(dim, gammalooprs::edge(4, 1)))
498 * Q(5, mink(dim, gammalooprs::edge(5, 1)))
499 * g(
500 mink(dim, gammalooprs::hedge(16)),
501 mink(dim, gammalooprs::hedge(17))
502 )
503 * g(
504 coad(8, gammalooprs::hedge(16)),
505 coad(8, gammalooprs::hedge(17))
506 )
507 * g(
508 dind(cof(3, gammalooprs::hedge(4))),
509 cof(3, gammalooprs::hedge(6))
510 )
511 * g(
512 dind(cof(3, gammalooprs::hedge(5))),
513 cof(3, gammalooprs::hedge(4))
514 )
515 * g(
516 dind(cof(3, gammalooprs::hedge(6))),
517 cof(3, gammalooprs::hedge(7))
518 )
519 * gamma(
520 bis(4, gammalooprs::hedge(4)),
521 bis(4, gammalooprs::hedge(6)),
522 mink(dim, gammalooprs::hedge(8))
523 )
524 * gamma(
525 bis(4, gammalooprs::hedge(7)),
526 bis(4, gammalooprs::hedge(13)),
527 mink(dim, gammalooprs::hedge(17))
528 )
529 * gamma(
530 bis(4, gammalooprs::hedge(11)),
531 bis(4, gammalooprs::hedge(5)),
532 mink(dim, gammalooprs::hedge(16))
533 )
534 * gamma(
535 bis(4, gammalooprs::hedge(5)),
536 bis(4, gammalooprs::hedge(4)),
537 mink(dim, gammalooprs::edge(4, 1))
538 )
539 * gamma(
540 bis(4, gammalooprs::hedge(6)),
541 bis(4, gammalooprs::hedge(7)),
542 mink(dim, gammalooprs::edge(5, 1))
543 )
544 * t(
545 coad(8, gammalooprs::hedge(16)),
546 cof(3, gammalooprs::hedge(5)),
547 dind(cof(3, gammalooprs::hedge(11)))
548 )
549 * t(
550 coad(8, gammalooprs::hedge(17)),
551 cof(3, gammalooprs::hedge(13)),
552 dind(cof(3, gammalooprs::hedge(7)))
553 ),
554 default_namespace = "spenso"
555 );
556
557 let net = expr
558 .parse_to_symbolic_net::<Aind>(&ParseSettings::default())
559 .unwrap();
560 println!("{}", net.dot_pretty());
561
562 let _ = expr.simplify_gamma();
563 }
564
565 mod failing {
566 use super::*;
567
568 #[test]
569 fn evaluate_pols() {
570 initialise().unwrap();
571 let model = crate::utils::load_generic_model("sm");
572
573 let graphs: Vec<Graph> = dot!(
574 digraph bxatobx{
575 graph [
576 color_num="spenso::g(spenso::dind(spenso::cof(3,hedge(0))),spenso::cof(3,hedge(2)))"
578 ]
579 bla [style=invis]
580 bla -> A:1 [particle=a id=0]
581 bla -> A:2 [particle="b~" id=2]
582 A:0 -> bla [particle="b~" id=1]
583 })
584 .unwrap();
585
586 let mut amp: Amplitude = Amplitude::from_graph_list("name", graphs.clone()).unwrap();
587 let mut settings = RuntimeSettings::default();
588
589 for g in graphs {
590 println!("{}", g.dot_serialize(&DotExportSettings::default()));
591 settings.kinematics = KinematicsSettings::random(&g, 42);
592
593 }
595
596 let proc_set = GenerationSettings::default();
597 let thread_pool = rayon::ThreadPoolBuilder::new()
598 .num_threads(1)
599 .build()
600 .unwrap();
601
602 let default_runtime_settings = RuntimeSettings::default();
603 let locked_runtime_settings = LockedRuntimeSettings::from(&default_runtime_settings);
604 amp.preprocess(&model, &proc_set, &locked_runtime_settings, &thread_pool)
605 .unwrap();
606
607 amp.build_integrand(
608 &model,
609 "test_process",
610 &GlobalSettings::default(),
611 (&RuntimeSettings::default()).into(),
612 &thread_pool,
613 )
614 .unwrap();
615
616 }
618
619 #[test]
620 fn pols() {
621 initialise().unwrap();
622 let mut graphs: Vec<Graph> = dot!(
623 digraph bxatobx{
624 graph [
625 num="v(0,spenso::bis(4,hedge(0)))*vbar(2,spenso::bis(4,hedge(2)))*ϵ(1,spenso::mink(4,hedge(1)))"
626 ]
627 ext [style=invis]
628 ext -> A:1 [particle=a id=1]
629 ext -> A:2 [dir=back particle="b~" id=2]
630 A:0 -> ext [dir=back particle="b~" id=0]
631 }
632
633 digraph batob{
634 graph [
635 num="ubar(0,spenso::bis(4,hedge(0)))*u(2,spenso::bis(4,hedge(2)))*ϵ(1,spenso::mink(4,hedge(1)))"
636 ]
637 ext [style=invis]
638 ext -> A:1 [particle=a id=1]
639 ext -> A:2 [particle="b" id=2]
640 A:0 -> ext [particle="b" id=0]
641 }
642
643 digraph bbato{
644 graph [
645 num="vbar(0,spenso::bis(4,hedge(0)))*u(2,spenso::bis(4,hedge(2)))*ϵ(1,spenso::mink(4,hedge(1)))"
646 ]
647 ext [style=invis]
648 ext -> A:1 [particle=a id=1]
649 ext -> A:2 [particle="b" id=2]
650 ext -> A:0 [dir=back pdg=-5 id=0]
651 }
652
653 digraph bbato{
654 graph [
655 num="vbar(0,spenso::bis(4,hedge(0)))*u(2,spenso::bis(4,hedge(2)))*ϵbar(1,spenso::mink(4,hedge(1)))"
656 ]
657 ext [style=invis]
658 A:1 -> ext [particle=a id=1]
659 ext -> A:2 [particle="b" id=2]
660 ext -> A:0 [dir=back pdg=-5 id=0]
661 }
662
663 )
664 .unwrap();
665
666 for g in &mut graphs {
667 let pols = g.generate_polarizations();
668 println!("{pols}");
669 let expected = &g.global_prefactor.num;
670 println!("{expected}");
671 assert_eq!(
672 expected, &pols,
673 "\nExpected: {:}\nActual: {:} for graph {:}",
674 expected, pols, g.name,
675 );
676 }
677 }
678
679 #[test]
680 fn vertex_rule() {
681 let mut graphs: Vec<Graph> = dot!(
682 digraph dxda{
683 ext [style=invis]
684 ext->v1:0[particle="d" id=0]
685 ext->v1:1[particle="d~" id=1]
686 v1:2->ext[particle="a" id=2]
687 }
688
689 )
690 .unwrap();
691
692 for g in &mut graphs {
693 let mut out = String::new();
694 g.dot_serialize_fmt(&mut out, &DotExportSettings::default())
695 .unwrap();
696 println!("{}", out);
697
698 assert!(g.iter_nodes().all(|(_, _, v)| {
699 let a = v.vertex_rule.as_ref().unwrap().name.as_str();
700 a == "V_71"
701 }),);
702 }
703 }
704
705 #[test]
706 fn pslash() {
707 let mut graphs: Vec<Graph> = dot!(
708 digraph dxda{
709 ext [style=invis]
710 node[num=1]
711 ext->v1:0[particle="d" id=0]
712 v1:1->v2:2[particle="d" id=1]
713 v2:3->ext[particle="d" id=2]
714 }
715
716 )
717 .unwrap();
718
719 for g in &mut graphs {
720 let mut out = String::new();
721 g.dot_serialize_fmt(&mut out, &DotExportSettings::default())
722 .unwrap();
723 println!("{}", out);
724 }
725 }
726
727 #[test]
728 fn tree() {
729 initialise().unwrap();
730 let mut graphs: Vec<Graph> = dot!(
731 digraph qqx_aaa_tree_1 {
732 num="spenso::g(spenso::dind(spenso::cof(3, hedge(1))), spenso::cof(3, hedge(2)))/3"
733 ext [style=invis]
734 ext -> v1:1 [particle="d" id=1];
735 ext -> v3:2 [dir=back particle="d~" id=2];
736 v1:3 -> ext [particle="a" id=3];
737 v2:4 -> ext [particle="a" id=4];
738 v3:0 -> ext [particle="a" id=0];
739 v1 -> v2 [particle="d" id=5];
740 v2 -> v3 [particle="d" id=6];
741 }
742
743 digraph qqx_aaa_tree_1 {
744 ext [style=invis]
745 ext -> v1:1 [particle="d" id=1];
746 ext -> v3:2 [dir=back particle="d~" id=2];
747 v1:3 -> ext [particle="a" id=3];
748 v2:4 -> ext [particle="a" id=4];
749 v3:0 -> ext [particle="a" id=0];
750 v1 -> v2 [particle="d" id=5];
751 v2 -> v3 [particle="d" id=6];
752 num="spenso::g(spenso::dind(spenso::cof(3, hedge(1))), spenso::cof(3, hedge(2)))/3"
753 }
754
755
756 digraph qqx_aaa_tree_1_glob {
757 ext [style=invis];
758 ext -> v1:1 [particle="d", id=1];
759 ext -> v3:2 [dir=back particle="d~", id=2];
760 v1:3 -> ext [particle="a", id=3];
761 v2:4 -> ext [particle="a", id=4];
762 v3:0 -> ext [particle="a", id=0];
763 v1 -> v2 [particle="d", id=5];
764 v2 -> v3 [particle="d", id=6];
765 num=" UFO::GC_1^3
766 *spenso::g(spenso::cof(3,hedge(1)),spenso::dind(spenso::cof(3,hedge(5))))
767 *spenso::gamma(spenso::bis(4,hedge(5)),spenso::bis(4,hedge(1)),spenso::mink(4,hedge(3)))
768
769 *spenso::g(spenso::cof(3,hedge(5)),spenso::dind(spenso::cof(3,hedge(6))))
770 *Q(5,spenso::mink(4,edge(5,1)))
771 *spenso::gamma(spenso::bis(4,hedge(6)),spenso::bis(4,hedge(5)),spenso::mink(4,edge(5,1)))
772
773
774 *spenso::g(spenso::cof(3,hedge(6)),spenso::dind(spenso::cof(3,hedge(7))))
775 *spenso::gamma(spenso::bis(4,hedge(7)),spenso::bis(4,hedge(6)),spenso::mink(4,hedge(4)))
776
777 *spenso::g(spenso::cof(3,hedge(7)),spenso::dind(spenso::cof(3,hedge(8))))
778 *spenso::gamma(spenso::bis(4,hedge(8)),spenso::bis(4,hedge(7)),spenso::mink(4,edge(6,1)))
779 *Q(6,spenso::mink(4,edge(6,1)))
780
781 *spenso::g(spenso::cof(3,hedge(8)),spenso::dind(spenso::cof(3,hedge(2))))
782 *spenso::gamma(spenso::bis(4,hedge(2)),spenso::bis(4,hedge(8)),spenso::mink(4,hedge(0)))
783
784 "
785 overall_factor="1"
786 projector="u(1,spenso::bis(4,hedge(1)))
787 *vbar(2,spenso::bis(4,hedge(2)))
788 *ϵbar(0,spenso::mink(4,hedge(0)))
789 *ϵbar(3,spenso::mink(4,hedge(3)))
790 *ϵbar(4,spenso::mink(4,hedge(4)))
791 *spenso::g(spenso::cof(3,hedge(2)),spenso::dind(spenso::cof(3,hedge(1))))/3"
792
793 edge [num="1"];
794 node [num="1"];
795 }
796
797
798 )
799 .unwrap();
800
801 let mut a: Option<Atom> = None;
802 for g in &mut graphs {
803 let mut out = String::new();
804
805 let new_a = (g
806 .numerator(&g.full_filter(), &g.empty_subgraph())
807 .state
808 .expr
809 * &g.global_prefactor.projector
810 * &g.global_prefactor.num
811 * &g.overall_factor)
812 .simplify_color();
813 println!("New:{new_a}");
814 if let Some(a) = &a {
815 println!("Old:{a}");
816 assert_eq!(&new_a, a, "{}", (&new_a / a).expand().to_canonical_string());
817 } else {
818 a = Some(new_a);
819 }
820 g.dot_serialize_fmt(&mut out, &DotExportSettings::default())
821 .unwrap();
822 println!("{}", out);
823 }
824
825 let mut a = Amplitude::from_graph_list("test", graphs.clone()).unwrap();
826
827 let model = crate::utils::load_generic_model("sm");
828
829 let generation_pool = rayon::ThreadPoolBuilder::new()
830 .num_threads(1)
831 .build()
832 .unwrap();
833
834 let default_runtime_settings = RuntimeSettings::default();
835 let locked_runtime_settings = LockedRuntimeSettings::from(&default_runtime_settings);
836 a.preprocess(
837 &model,
838 &GenerationSettings::default(),
839 &locked_runtime_settings,
840 &generation_pool,
841 )
842 .unwrap();
843 }
844
845 #[test]
846 fn dod_override() {
847 let _gr:Vec<Graph> = dot!(digraph g{
848 node [num=1]
849 edge [num=1]
850 a->b[dod=-100]
851 b->c[dod="-100"]
852 }
853 digraph triangle_ct {
854 num="(-1*_gammaloop::P(1,spenso::cind(1))*_gammaloop::P(2,spenso::cind(1))+-1*_gammaloop::P(1,spenso::cind(2))*_gammaloop::P(2,spenso::cind(2))+-1*_gammaloop::P(1,spenso::cind(3))*_gammaloop::P(2,spenso::cind(3))+_gammaloop::P(1,spenso::cind(0))*_gammaloop::P(2,spenso::cind(0)))^-2*(-1*_gammaloop::P(2,spenso::mink(4,python::mu2))+-1*_gammaloop::Q(6,spenso::mink(4,python::mu2))+_gammaloop::P(1,spenso::mink(4,python::mu7)))*(-1*_gammaloop::Q(7,spenso::mink(4,python::mu2))+_gammaloop::P(2,spenso::mink(4,python::mu2)))*-1/4*_gammaloop::G^2*_gammaloop::P(1,spenso::mink(4,python::mu3))*_gammaloop::P(1,spenso::mink(4,python::mu5))*_gammaloop::P(2,spenso::mink(4,python::mu4))*_gammaloop::P(2,spenso::mink(4,python::mu6))*spenso::gamma(spenso::bis(4,_gammaloop::hedge(2)),spenso::bis(4,python::s1),spenso::mink(4,python::mu1))*spenso::gamma(spenso::bis(4,python::s1),spenso::bis(4,python::s2),spenso::mink(4,python::mu2))*spenso::gamma(spenso::bis(4,python::s2),spenso::bis(4,python::s3),spenso::mink(4,python::mu3))*spenso::gamma(spenso::bis(4,python::s3),spenso::bis(4,python::tree_form_factor_spinor_2),spenso::mink(4,python::mu4))*spenso::gamma(spenso::bis(4,python::s4),spenso::bis(4,python::s6),spenso::mink(4,python::mu7))*spenso::gamma(spenso::bis(4,python::s5),spenso::bis(4,python::s4),spenso::mink(4,python::mu6))*spenso::gamma(spenso::bis(4,python::s6),spenso::bis(4,_gammaloop::hedge(1)),spenso::mink(4,python::mu1))*spenso::gamma(spenso::bis(4,python::tree_form_factor_spinor_1),spenso::bis(4,python::s5),spenso::mink(4,python::mu5))";
855 overall_factor="1";
856 projector="((-1*_gammaloop::P(3,spenso::cind(0))+-1*_gammaloop::P(4,spenso::cind(0))+_gammaloop::P(1,spenso::cind(0)))^2+(-1*_gammaloop::P(3,spenso::cind(1))+-1*_gammaloop::P(4,spenso::cind(1))+_gammaloop::P(1,spenso::cind(1)))^2*-1+(-1*_gammaloop::P(3,spenso::cind(2))+-1*_gammaloop::P(4,spenso::cind(2))+_gammaloop::P(1,spenso::cind(2)))^2*-1+(-1*_gammaloop::P(3,spenso::cind(3))+-1*_gammaloop::P(4,spenso::cind(3))+_gammaloop::P(1,spenso::cind(3)))^2*-1)^-1*((-1*_gammaloop::P(3,spenso::cind(0))+_gammaloop::P(1,spenso::cind(0)))^2+(-1*_gammaloop::P(3,spenso::cind(1))+_gammaloop::P(1,spenso::cind(1)))^2*-1+(-1*_gammaloop::P(3,spenso::cind(2))+_gammaloop::P(1,spenso::cind(2)))^2*-1+(-1*_gammaloop::P(3,spenso::cind(3))+_gammaloop::P(1,spenso::cind(3)))^2*-1)^-1*(-1*_gammaloop::P(3,spenso::mink(4,_gammaloop::edge(5,1)))+_gammaloop::P(1,spenso::mink(4,_gammaloop::edge(5,1))))*(-1*_gammaloop::P(3,spenso::mink(4,_gammaloop::edge(6,1)))+-1*_gammaloop::P(4,spenso::mink(4,_gammaloop::edge(6,1)))+_gammaloop::P(1,spenso::mink(4,_gammaloop::edge(6,1))))*-1/27*_gammaloop::ee^3*_gammaloop::u(1,spenso::bis(4,_gammaloop::hedge(1)))*_gammaloop::vbar(2,spenso::bis(4,_gammaloop::hedge(2)))*_gammaloop::ϵbar(0,spenso::mink(4,_gammaloop::hedge(0)))*_gammaloop::ϵbar(3,spenso::mink(4,_gammaloop::hedge(3)))*_gammaloop::ϵbar(4,spenso::mink(4,_gammaloop::hedge(4)))*spenso::gamma(spenso::bis(4,_gammaloop::hedge(5)),spenso::bis(4,python::tree_form_factor_spinor_1),spenso::mink(4,_gammaloop::hedge(3)))*spenso::gamma(spenso::bis(4,_gammaloop::hedge(6)),spenso::bis(4,_gammaloop::hedge(5)),spenso::mink(4,_gammaloop::edge(5,1)))*spenso::gamma(spenso::bis(4,_gammaloop::hedge(7)),spenso::bis(4,_gammaloop::hedge(6)),spenso::mink(4,_gammaloop::hedge(4)))*spenso::gamma(spenso::bis(4,_gammaloop::hedge(8)),spenso::bis(4,_gammaloop::hedge(7)),spenso::mink(4,_gammaloop::edge(6,1)))*spenso::gamma(spenso::bis(4,python::tree_form_factor_spinor_2),spenso::bis(4,_gammaloop::hedge(8)),spenso::mink(4,_gammaloop::hedge(0)))";
857 edge [num="1", dod="-100"];
858 node [num="1", dod="-100"];
859 ext [style=invis];
860 ext -> vl1:1 [particle="d", id=1];
861 ext -> vl2:2 [dir=back particle="d~", id=2];
862 v1:3 -> ext [id=3];
863 v1:4 -> ext [id=4];
864 v1:0 -> ext [id=0];
865 vl1 -> v1 [particle="d", id=5];
866 v1 -> vl2 [particle="d", id=6];
867 vl1 -> vl2 [particle="g", id=7, lmb_id=0];
868 }
869 )
870 .unwrap();
871 }
872 }
873}