gammalooprs/numerator/
uninit.rs1use std::sync::atomic::AtomicUsize;
2
3use linnet::half_edge::subgraph::subset::SubSet;
4use linnet::half_edge::subgraph::{ModifySubSet, SubGraphLike, SubSetLike, SubSetOps};
5use linnet::half_edge::{NodeIndex, involution::HedgePair};
6use symbolica::atom::Atom;
7use symbolica_utils::AtomPrintExt;
8use tracing::debug;
9use tracing::instrument;
10
11use crate::graph::Graph;
12
13use super::{AppliedFeynmanRule, Numerator, UnInit};
14
15static MAXEDGECOUNTER: AtomicUsize = AtomicUsize::new(0);
16
17impl Numerator<UnInit> {
18 #[instrument(skip_all, fields(graph=%graph.name,debug_dot=%graph.debug_dot(),subgraph_dot=%graph.dot(subgraph)))]
19 #[allow(clippy::wrong_self_convention)]
20 pub(crate) fn from_new_graph<S: SubGraphLike>(
21 self,
22 graph: &Graph,
23 subgraph: &S,
24 ) -> Numerator<AppliedFeynmanRule> {
25 let mut num = Atom::one();
26
27 let mut seen: SubSet<NodeIndex> = SubSet::empty(graph.n_nodes());
28
29 for (p, eid, e) in graph.underlying.iter_edges_of(subgraph) {
30 let i = MAXEDGECOUNTER.fetch_max(eid.0, std::sync::atomic::Ordering::Relaxed);
31 if i == eid.0 {
32 }
48 if let HedgePair::Paired { source, sink } = p {
49 let source_n = graph.node_id(source);
50 if !seen[source_n] {
51 seen.add(source_n);
52 num *= graph[source_n].get_num();
53 }
54 let sink_n = graph.node_id(sink);
55 if !seen[sink_n] {
56 seen.add(sink_n);
57 num *= graph[sink_n].get_num();
58 }
59
60 num *= &e.data.num.value }
62 }
63
64 let notseen = !seen;
65
66 for node_id in notseen.included_iter() {
68 if graph
69 .iter_crown(node_id)
70 .all(|h| subgraph.includes(&h) || graph[graph[&h]].is_dummy)
71 {
72 num *= graph[node_id].get_num()
73 }
74 }
75
76 debug!( numerator = %num.to_bare_ordered_string(),"Numerator constructed",);
77
78 Numerator {
79 state: AppliedFeynmanRule {
80 expr: num,
81 state: Default::default(),
82 },
83 }
84 }
85 #[instrument(skip_all, fields(graph=%graph.name,debug_dot=%graph.debug_dot(),subgraph_dot=%graph.dot(subgraph)))]
86 #[allow(clippy::wrong_self_convention)]
87 pub(crate) fn fill_in_reduced<S: SubGraphLike + SubSetOps>(
88 self,
89 graph: &Graph,
90 subgraph: &S,
91 ignore: &S,
92 ) -> Numerator<AppliedFeynmanRule> {
93 let mut num = Atom::one();
94
95 let mut seen: SubSet<NodeIndex> = SubSet::empty(graph.n_nodes());
96
97 for (nid, _, _) in graph.underlying.iter_nodes_of(ignore) {
98 seen.add(nid);
99 }
100 let not_ignored = subgraph.subtract(ignore);
101
102 for (p, _eid, e) in graph.underlying.iter_edges_of(¬_ignored) {
103 if let HedgePair::Paired { source, sink } = p {
104 let source_n = graph.node_id(source);
105 if !seen[source_n] {
106 seen.add(source_n);
107 num *= graph[source_n].get_num();
108 }
109 let sink_n = graph.node_id(sink);
110 if !seen[sink_n] {
111 seen.add(sink_n);
112 num *= graph[sink_n].get_num();
113 }
114
115 num *= &e.data.num.value }
117 }
118
119 let notseen = !seen;
120
121 for node_id in notseen.included_iter() {
123 if graph
124 .iter_crown(node_id)
125 .all(|h| subgraph.includes(&h) || graph[graph[&h]].is_dummy)
126 {
127 num *= graph[node_id].get_num()
128 }
129 }
130
131 debug!( numerator = %num.to_bare_ordered_string(),"Numerator constructed",);
132
133 Numerator {
134 state: AppliedFeynmanRule {
135 expr: num,
136 state: Default::default(),
137 },
138 }
139 }
140}