From 268841990ef5cdb31291a60317fecae7d265d17b Mon Sep 17 00:00:00 2001
From: Anton Reinhard <anton.reinhard@proton.me>
Date: Mon, 27 Nov 2023 19:28:55 +0100
Subject: [PATCH] Work on QED Model execution

---
 .gitignore                      |   1 +
 docs/src/QED-Bhabha-DAG.drawio  | 259 ++++++++++++++++++++++++++++++++
 docs/src/QED-Compton-DAG.drawio | 259 ++++++++++++++++++++++++++++++++
 docs/src/QED-DAG.drawio         | 259 ++++++++++++++++++++++++++++++++
 src/MetagraphOptimization.jl    |   8 +-
 src/code_gen/main.jl            |  10 +-
 src/models/abc/compute.jl       |   2 +-
 src/models/abc/create.jl        | 134 -----------------
 src/models/abc/particle.jl      |  20 ++-
 src/models/abc/properties.jl    |   9 --
 src/models/interface.jl         |  15 ++
 src/models/qed/compute.jl       | 139 +++++++++++++++--
 src/models/qed/create.jl        |  55 +++++++
 src/models/qed/parse.jl         |  44 ++++++
 src/models/qed/particle.jl      | 116 +++++++++++---
 src/models/qed/print.jl         |  61 ++++++++
 src/models/qed/properties.jl    | 135 +++++++++++++++++
 src/task/properties.jl          |   9 ++
 src/utility.jl                  | 136 +++++++++++++++++
 test/Project.toml               |   1 +
 test/unit_tests_qedmodel.jl     | 140 +++++++++++++++++
 21 files changed, 1613 insertions(+), 199 deletions(-)
 create mode 100644 docs/src/QED-Bhabha-DAG.drawio
 create mode 100644 docs/src/QED-Compton-DAG.drawio
 create mode 100644 docs/src/QED-DAG.drawio
 create mode 100644 src/models/qed/create.jl
 create mode 100644 src/models/qed/parse.jl
 create mode 100644 src/models/qed/print.jl
 create mode 100644 src/models/qed/properties.jl

diff --git a/.gitignore b/.gitignore
index 423c8ef..034bc94 100644
--- a/.gitignore
+++ b/.gitignore
@@ -28,3 +28,4 @@ Manifest.toml
 .vscode
 .julia
 **/.ipynb_checkpoints/
+*.bkp
diff --git a/docs/src/QED-Bhabha-DAG.drawio b/docs/src/QED-Bhabha-DAG.drawio
new file mode 100644
index 0000000..0fbd5e4
--- /dev/null
+++ b/docs/src/QED-Bhabha-DAG.drawio
@@ -0,0 +1,259 @@
+<mxfile host="Electron" modified="2023-11-25T19:36:18.149Z" agent="Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) draw.io/21.6.1 Chrome/114.0.5735.289 Electron/25.9.4 Safari/537.36" etag="hBUSDG3lmnElLEv2sh-Z" version="21.6.1" type="device">
+  <diagram name="Page-1" id="pzz-rsbNjEFeZeQIA-38">
+    <mxGraphModel dx="1430" dy="853" grid="1" gridSize="10" guides="1" tooltips="1" connect="1" arrows="1" fold="1" page="1" pageScale="1" pageWidth="500" pageHeight="900" math="0" shadow="0">
+      <root>
+        <mxCell id="0" />
+        <mxCell id="1" parent="0" />
+        <mxCell id="KG5lhhUBjoQ79gfvQvIC-19" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;strokeWidth=2;" parent="1" source="KG5lhhUBjoQ79gfvQvIC-6" target="KG5lhhUBjoQ79gfvQvIC-18" edge="1">
+          <mxGeometry relative="1" as="geometry" />
+        </mxCell>
+        <mxCell id="KG5lhhUBjoQ79gfvQvIC-6" value="&lt;b style=&quot;border-color: var(--border-color);&quot;&gt;&lt;font style=&quot;border-color: var(--border-color);&quot; color=&quot;#336600&quot;&gt;base_state&lt;/font&gt;&lt;/b&gt;&amp;nbsp;-&amp;gt;&lt;br&gt;&lt;b style=&quot;border-color: var(--border-color);&quot;&gt;&lt;font style=&quot;border-color: var(--border-color);&quot; color=&quot;#cc00cc&quot;&gt;AdjointBiSpinor&lt;/font&gt;&lt;/b&gt;" style="rounded=1;whiteSpace=wrap;html=1;strokeWidth=2;fillColor=#f5f5f5;gradientColor=#b3b3b3;strokeColor=#666666;" parent="1" vertex="1">
+          <mxGeometry x="190" y="600" width="120" height="60" as="geometry" />
+        </mxCell>
+        <mxCell id="KG5lhhUBjoQ79gfvQvIC-20" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;strokeWidth=2;" parent="1" source="KG5lhhUBjoQ79gfvQvIC-7" target="KG5lhhUBjoQ79gfvQvIC-18" edge="1">
+          <mxGeometry relative="1" as="geometry" />
+        </mxCell>
+        <mxCell id="KG5lhhUBjoQ79gfvQvIC-7" value="&lt;b style=&quot;border-color: var(--border-color);&quot;&gt;&lt;font style=&quot;border-color: var(--border-color);&quot; color=&quot;#336600&quot;&gt;base_state&lt;/font&gt;&lt;/b&gt;&amp;nbsp;-&amp;gt;&lt;br&gt;&lt;b style=&quot;border-color: var(--border-color);&quot;&gt;&lt;font style=&quot;border-color: var(--border-color);&quot; color=&quot;#cc00cc&quot;&gt;BiSpinor&lt;/font&gt;&lt;/b&gt;" style="rounded=1;whiteSpace=wrap;html=1;strokeWidth=2;fillColor=#f5f5f5;gradientColor=#b3b3b3;strokeColor=#666666;" parent="1" vertex="1">
+          <mxGeometry x="310" y="600" width="120" height="60" as="geometry" />
+        </mxCell>
+        <mxCell id="KG5lhhUBjoQ79gfvQvIC-28" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;strokeWidth=2;" parent="1" source="KG5lhhUBjoQ79gfvQvIC-8" target="KG5lhhUBjoQ79gfvQvIC-26" edge="1">
+          <mxGeometry relative="1" as="geometry" />
+        </mxCell>
+        <mxCell id="KG5lhhUBjoQ79gfvQvIC-8" value="&lt;b style=&quot;border-color: var(--border-color);&quot;&gt;&lt;font style=&quot;border-color: var(--border-color);&quot; color=&quot;#336600&quot;&gt;base_state&lt;/font&gt;&lt;/b&gt;&amp;nbsp;-&amp;gt;&lt;br&gt;&lt;b style=&quot;border-color: var(--border-color);&quot;&gt;&lt;font style=&quot;border-color: var(--border-color);&quot; color=&quot;#cc00cc&quot;&gt;AdjointBiSpinor&lt;/font&gt;&lt;/b&gt;" style="rounded=1;whiteSpace=wrap;html=1;strokeWidth=2;fillColor=#f5f5f5;gradientColor=#b3b3b3;strokeColor=#666666;" parent="1" vertex="1">
+          <mxGeometry x="550" y="600" width="120" height="60" as="geometry" />
+        </mxCell>
+        <mxCell id="KG5lhhUBjoQ79gfvQvIC-29" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;strokeWidth=2;" parent="1" source="KG5lhhUBjoQ79gfvQvIC-9" target="KG5lhhUBjoQ79gfvQvIC-26" edge="1">
+          <mxGeometry relative="1" as="geometry" />
+        </mxCell>
+        <mxCell id="KG5lhhUBjoQ79gfvQvIC-9" value="&lt;b style=&quot;border-color: var(--border-color);&quot;&gt;&lt;font style=&quot;border-color: var(--border-color);&quot; color=&quot;#336600&quot;&gt;base_state&lt;/font&gt;&lt;/b&gt;&amp;nbsp;-&amp;gt;&lt;br&gt;&lt;b style=&quot;border-color: var(--border-color);&quot;&gt;&lt;font style=&quot;border-color: var(--border-color);&quot; color=&quot;#cc00cc&quot;&gt;BiSpinor&lt;/font&gt;&lt;/b&gt;" style="rounded=1;whiteSpace=wrap;html=1;strokeWidth=2;fillColor=#f5f5f5;gradientColor=#b3b3b3;strokeColor=#666666;" parent="1" vertex="1">
+          <mxGeometry x="430" y="600" width="120" height="60" as="geometry" />
+        </mxCell>
+        <mxCell id="KG5lhhUBjoQ79gfvQvIC-21" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;strokeWidth=2;" parent="1" source="KG5lhhUBjoQ79gfvQvIC-14" target="KG5lhhUBjoQ79gfvQvIC-6" edge="1">
+          <mxGeometry relative="1" as="geometry" />
+        </mxCell>
+        <mxCell id="KG5lhhUBjoQ79gfvQvIC-14" value="U(p&lt;sub&gt;1&lt;/sub&gt;)&lt;br style=&quot;border-color: var(--border-color);&quot;&gt;&lt;font color=&quot;#0000ff&quot;&gt;&lt;b&gt;IncomingAntiFermion&lt;/b&gt;&lt;/font&gt;&lt;br&gt;Outer Edge" style="ellipse;whiteSpace=wrap;html=1;strokeWidth=2;fillColor=#f5f5f5;gradientColor=#9AC7BF;strokeColor=#666666;" parent="1" vertex="1">
+          <mxGeometry x="190" y="700" width="120" height="80" as="geometry" />
+        </mxCell>
+        <mxCell id="KG5lhhUBjoQ79gfvQvIC-22" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;strokeWidth=2;" parent="1" source="KG5lhhUBjoQ79gfvQvIC-15" target="KG5lhhUBjoQ79gfvQvIC-7" edge="1">
+          <mxGeometry relative="1" as="geometry" />
+        </mxCell>
+        <mxCell id="KG5lhhUBjoQ79gfvQvIC-15" value="U(e&lt;sub style=&quot;border-color: var(--border-color);&quot;&gt;1&lt;/sub&gt;)&lt;br style=&quot;border-color: var(--border-color);&quot;&gt;&lt;b&gt;&lt;font color=&quot;#0000ff&quot;&gt;IncomingFermion&lt;br&gt;&lt;/font&gt;&lt;/b&gt;Outer Edge" style="ellipse;whiteSpace=wrap;html=1;strokeWidth=2;fillColor=#f5f5f5;gradientColor=#9AC7BF;strokeColor=#666666;" parent="1" vertex="1">
+          <mxGeometry x="310" y="700" width="120" height="80" as="geometry" />
+        </mxCell>
+        <mxCell id="KG5lhhUBjoQ79gfvQvIC-23" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;strokeWidth=2;" parent="1" source="KG5lhhUBjoQ79gfvQvIC-16" target="KG5lhhUBjoQ79gfvQvIC-9" edge="1">
+          <mxGeometry relative="1" as="geometry" />
+        </mxCell>
+        <mxCell id="KG5lhhUBjoQ79gfvQvIC-16" value="U(p&lt;span style=&quot;font-size: 10px;&quot;&gt;&lt;sub&gt;2&lt;/sub&gt;&lt;/span&gt;)&lt;br style=&quot;border-color: var(--border-color);&quot;&gt;&lt;b&gt;&lt;font color=&quot;#0000ff&quot;&gt;OutgoingAntiFermion&lt;br&gt;&lt;/font&gt;&lt;/b&gt;Outer Edge" style="ellipse;whiteSpace=wrap;html=1;strokeWidth=2;fillColor=#f5f5f5;gradientColor=#9AC7BF;strokeColor=#666666;" parent="1" vertex="1">
+          <mxGeometry x="430" y="700" width="120" height="80" as="geometry" />
+        </mxCell>
+        <mxCell id="KG5lhhUBjoQ79gfvQvIC-24" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;strokeWidth=2;" parent="1" source="KG5lhhUBjoQ79gfvQvIC-17" target="KG5lhhUBjoQ79gfvQvIC-8" edge="1">
+          <mxGeometry relative="1" as="geometry" />
+        </mxCell>
+        <mxCell id="KG5lhhUBjoQ79gfvQvIC-17" value="U(e&lt;sub style=&quot;border-color: var(--border-color);&quot;&gt;2&lt;/sub&gt;)&lt;br style=&quot;border-color: var(--border-color);&quot;&gt;&lt;b&gt;&lt;font color=&quot;#0000ff&quot;&gt;OutgoingFermion&lt;br&gt;&lt;/font&gt;&lt;/b&gt;Outer Edge" style="ellipse;whiteSpace=wrap;html=1;strokeWidth=2;fillColor=#f5f5f5;gradientColor=#9AC7BF;strokeColor=#666666;" parent="1" vertex="1">
+          <mxGeometry x="550" y="700" width="120" height="80" as="geometry" />
+        </mxCell>
+        <mxCell id="KG5lhhUBjoQ79gfvQvIC-30" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;strokeWidth=2;" parent="1" source="KG5lhhUBjoQ79gfvQvIC-18" target="KG5lhhUBjoQ79gfvQvIC-25" edge="1">
+          <mxGeometry relative="1" as="geometry" />
+        </mxCell>
+        <mxCell id="KG5lhhUBjoQ79gfvQvIC-18" value="V(e&lt;sub&gt;1&lt;/sub&gt;, p&lt;sub&gt;1&lt;/sub&gt;)&lt;br&gt;Result Particle:&lt;br&gt;q: &lt;font color=&quot;#0000ff&quot;&gt;&lt;b&gt;OutgoingPhoton&lt;br&gt;&lt;/b&gt;&lt;/font&gt;" style="ellipse;whiteSpace=wrap;html=1;strokeWidth=2;fillColor=#f5f5f5;gradientColor=#9AC7BF;strokeColor=#666666;" parent="1" vertex="1">
+          <mxGeometry x="240" y="480" width="140" height="80" as="geometry" />
+        </mxCell>
+        <mxCell id="KG5lhhUBjoQ79gfvQvIC-36" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;strokeWidth=2;" parent="1" source="KG5lhhUBjoQ79gfvQvIC-25" target="KG5lhhUBjoQ79gfvQvIC-35" edge="1">
+          <mxGeometry relative="1" as="geometry" />
+        </mxCell>
+        <mxCell id="KG5lhhUBjoQ79gfvQvIC-25" value="&lt;b&gt;&lt;font color=&quot;#336600&quot;&gt;vertex&lt;/font&gt;&lt;/b&gt; -&amp;gt;&lt;br&gt;AdjointBiSpinor * &lt;br&gt;DiracMatrix *&lt;br&gt;BiSpinor&lt;br&gt;=&amp;nbsp;&lt;b style=&quot;border-color: var(--border-color);&quot;&gt;&lt;font color=&quot;#cc00cc&quot; style=&quot;border-color: var(--border-color);&quot;&gt;Complex&lt;br&gt;&lt;/font&gt;&lt;/b&gt;" style="rounded=1;whiteSpace=wrap;html=1;strokeWidth=2;fillColor=#f5f5f5;gradientColor=#b3b3b3;strokeColor=#666666;" parent="1" vertex="1">
+          <mxGeometry x="250" y="360" width="120" height="80" as="geometry" />
+        </mxCell>
+        <mxCell id="KG5lhhUBjoQ79gfvQvIC-32" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;strokeWidth=2;" parent="1" source="KG5lhhUBjoQ79gfvQvIC-26" target="KG5lhhUBjoQ79gfvQvIC-27" edge="1">
+          <mxGeometry relative="1" as="geometry" />
+        </mxCell>
+        <mxCell id="KG5lhhUBjoQ79gfvQvIC-26" value="V(e&lt;sub&gt;2&lt;/sub&gt;, p&lt;sub&gt;2&lt;/sub&gt;)&lt;br&gt;Result Particle:&lt;br&gt;q&#39;: &lt;b&gt;&lt;font color=&quot;#0000ff&quot;&gt;IncomingPhoton&lt;/font&gt;&lt;/b&gt;" style="ellipse;whiteSpace=wrap;html=1;strokeWidth=2;fillColor=#f5f5f5;gradientColor=#9AC7BF;strokeColor=#666666;" parent="1" vertex="1">
+          <mxGeometry x="480" y="480" width="140" height="80" as="geometry" />
+        </mxCell>
+        <mxCell id="KG5lhhUBjoQ79gfvQvIC-37" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;strokeWidth=2;" parent="1" source="KG5lhhUBjoQ79gfvQvIC-27" target="KG5lhhUBjoQ79gfvQvIC-35" edge="1">
+          <mxGeometry relative="1" as="geometry">
+            <Array as="points">
+              <mxPoint x="550" y="340" />
+              <mxPoint x="420" y="340" />
+            </Array>
+          </mxGeometry>
+        </mxCell>
+        <mxCell id="KG5lhhUBjoQ79gfvQvIC-27" value="&lt;b style=&quot;border-color: var(--border-color);&quot;&gt;&lt;font style=&quot;border-color: var(--border-color);&quot; color=&quot;#336600&quot;&gt;vertex&lt;/font&gt;&lt;/b&gt;&amp;nbsp;-&amp;gt;&lt;br&gt;AdjointBiSpinor * &lt;br&gt;DiracMatrix *&lt;br&gt;BiSpinor&lt;br&gt;=&amp;nbsp;&lt;b style=&quot;border-color: var(--border-color);&quot;&gt;&lt;font color=&quot;#cc00cc&quot; style=&quot;border-color: var(--border-color);&quot;&gt;Complex&lt;/font&gt;&lt;/b&gt;" style="rounded=1;whiteSpace=wrap;html=1;strokeWidth=2;fillColor=#f5f5f5;gradientColor=#b3b3b3;strokeColor=#666666;" parent="1" vertex="1">
+          <mxGeometry x="490" y="360" width="120" height="80" as="geometry" />
+        </mxCell>
+        <mxCell id="KG5lhhUBjoQ79gfvQvIC-39" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;strokeWidth=2;" parent="1" source="KG5lhhUBjoQ79gfvQvIC-35" target="KG5lhhUBjoQ79gfvQvIC-38" edge="1">
+          <mxGeometry relative="1" as="geometry" />
+        </mxCell>
+        <mxCell id="KG5lhhUBjoQ79gfvQvIC-35" value="S2(q, q&#39;)&lt;br&gt;q == -q&#39;&lt;br&gt;&lt;b&gt;&lt;font color=&quot;#0000ff&quot;&gt;No Result Particle&lt;/font&gt;&lt;/b&gt;" style="ellipse;whiteSpace=wrap;html=1;strokeWidth=2;fillColor=#f5f5f5;gradientColor=#9AC7BF;strokeColor=#666666;" parent="1" vertex="1">
+          <mxGeometry x="360" y="240" width="120" height="80" as="geometry" />
+        </mxCell>
+        <mxCell id="KG5lhhUBjoQ79gfvQvIC-71" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;strokeWidth=2;" parent="1" source="KG5lhhUBjoQ79gfvQvIC-38" target="KG5lhhUBjoQ79gfvQvIC-70" edge="1">
+          <mxGeometry relative="1" as="geometry">
+            <Array as="points">
+              <mxPoint x="670" y="170" />
+            </Array>
+          </mxGeometry>
+        </mxCell>
+        <mxCell id="KG5lhhUBjoQ79gfvQvIC-38" value="&lt;b style=&quot;&quot;&gt;&lt;font color=&quot;#336600&quot;&gt;inner_edge&lt;/font&gt;&lt;/b&gt; -&amp;gt;&lt;br&gt;Complex * propagator(q) * Complex&amp;nbsp;&lt;br&gt;=&amp;nbsp;&lt;b style=&quot;border-color: var(--border-color);&quot;&gt;&lt;font style=&quot;border-color: var(--border-color);&quot; color=&quot;#cc00cc&quot;&gt;Complex&lt;br&gt;&lt;/font&gt;&lt;/b&gt;" style="rounded=1;whiteSpace=wrap;html=1;strokeWidth=2;fillColor=#f5f5f5;gradientColor=#b3b3b3;strokeColor=#666666;" parent="1" vertex="1">
+          <mxGeometry x="350" y="140" width="140" height="60" as="geometry" />
+        </mxCell>
+        <mxCell id="KG5lhhUBjoQ79gfvQvIC-40" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;strokeWidth=2;" parent="1" source="KG5lhhUBjoQ79gfvQvIC-41" target="KG5lhhUBjoQ79gfvQvIC-57" edge="1">
+          <mxGeometry relative="1" as="geometry" />
+        </mxCell>
+        <mxCell id="KG5lhhUBjoQ79gfvQvIC-41" value="&lt;b style=&quot;border-color: var(--border-color);&quot;&gt;&lt;font style=&quot;border-color: var(--border-color);&quot; color=&quot;#336600&quot;&gt;base_state&lt;/font&gt;&lt;/b&gt;&amp;nbsp;-&amp;gt;&lt;br&gt;&lt;b style=&quot;border-color: var(--border-color);&quot;&gt;&lt;font style=&quot;border-color: var(--border-color);&quot; color=&quot;#cc00cc&quot;&gt;AdjointBiSpinor&lt;/font&gt;&lt;/b&gt;" style="rounded=1;whiteSpace=wrap;html=1;strokeWidth=2;fillColor=#f5f5f5;gradientColor=#b3b3b3;strokeColor=#666666;" parent="1" vertex="1">
+          <mxGeometry x="670" y="600" width="120" height="60" as="geometry" />
+        </mxCell>
+        <mxCell id="KG5lhhUBjoQ79gfvQvIC-68" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;strokeWidth=2;" parent="1" source="KG5lhhUBjoQ79gfvQvIC-43" target="KG5lhhUBjoQ79gfvQvIC-61" edge="1">
+          <mxGeometry relative="1" as="geometry" />
+        </mxCell>
+        <mxCell id="KG5lhhUBjoQ79gfvQvIC-43" value="&lt;b style=&quot;&quot;&gt;&lt;font color=&quot;#336600&quot;&gt;base_state&lt;/font&gt;&lt;/b&gt; -&amp;gt;&lt;br&gt;&lt;b style=&quot;border-color: var(--border-color);&quot;&gt;&lt;font style=&quot;border-color: var(--border-color);&quot; color=&quot;#cc00cc&quot;&gt;AdjointBiSpinor&lt;/font&gt;&lt;/b&gt;" style="rounded=1;whiteSpace=wrap;html=1;strokeWidth=2;fillColor=#f5f5f5;gradientColor=#b3b3b3;strokeColor=#666666;" parent="1" vertex="1">
+          <mxGeometry x="1030" y="600" width="120" height="60" as="geometry" />
+        </mxCell>
+        <mxCell id="KG5lhhUBjoQ79gfvQvIC-67" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;strokeWidth=2;" parent="1" source="KG5lhhUBjoQ79gfvQvIC-45" target="KG5lhhUBjoQ79gfvQvIC-57" edge="1">
+          <mxGeometry relative="1" as="geometry" />
+        </mxCell>
+        <mxCell id="KG5lhhUBjoQ79gfvQvIC-45" value="&lt;b style=&quot;border-color: var(--border-color);&quot;&gt;&lt;font style=&quot;border-color: var(--border-color);&quot; color=&quot;#336600&quot;&gt;base_state&lt;/font&gt;&lt;/b&gt;&amp;nbsp;-&amp;gt;&lt;br&gt;&lt;b style=&quot;border-color: var(--border-color);&quot;&gt;&lt;font style=&quot;border-color: var(--border-color);&quot; color=&quot;#cc00cc&quot;&gt;BiSpinor&lt;/font&gt;&lt;/b&gt;" style="rounded=1;whiteSpace=wrap;html=1;strokeWidth=2;fillColor=#f5f5f5;gradientColor=#b3b3b3;strokeColor=#666666;" parent="1" vertex="1">
+          <mxGeometry x="790" y="600" width="120" height="60" as="geometry" />
+        </mxCell>
+        <mxCell id="KG5lhhUBjoQ79gfvQvIC-46" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;strokeWidth=2;" parent="1" source="KG5lhhUBjoQ79gfvQvIC-47" target="KG5lhhUBjoQ79gfvQvIC-61" edge="1">
+          <mxGeometry relative="1" as="geometry" />
+        </mxCell>
+        <mxCell id="KG5lhhUBjoQ79gfvQvIC-47" value="&lt;b style=&quot;border-color: var(--border-color);&quot;&gt;&lt;font style=&quot;border-color: var(--border-color);&quot; color=&quot;#336600&quot;&gt;base_state&lt;/font&gt;&lt;/b&gt;&amp;nbsp;-&amp;gt;&lt;br&gt;&lt;b style=&quot;border-color: var(--border-color);&quot;&gt;&lt;font style=&quot;border-color: var(--border-color);&quot; color=&quot;#cc00cc&quot;&gt;BiSpinor&lt;/font&gt;&lt;/b&gt;" style="rounded=1;whiteSpace=wrap;html=1;strokeWidth=2;fillColor=#f5f5f5;gradientColor=#b3b3b3;strokeColor=#666666;" parent="1" vertex="1">
+          <mxGeometry x="910" y="600" width="120" height="60" as="geometry" />
+        </mxCell>
+        <mxCell id="KG5lhhUBjoQ79gfvQvIC-48" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;strokeWidth=2;" parent="1" source="KG5lhhUBjoQ79gfvQvIC-49" target="KG5lhhUBjoQ79gfvQvIC-41" edge="1">
+          <mxGeometry relative="1" as="geometry" />
+        </mxCell>
+        <mxCell id="KG5lhhUBjoQ79gfvQvIC-49" value="U(p&lt;sub style=&quot;border-color: var(--border-color);&quot;&gt;1&lt;/sub&gt;)&lt;br style=&quot;border-color: var(--border-color);&quot;&gt;&lt;font style=&quot;border-color: var(--border-color);&quot; color=&quot;#0000ff&quot;&gt;&lt;b style=&quot;border-color: var(--border-color);&quot;&gt;IncomingAntiFermion&lt;/b&gt;&lt;/font&gt;&lt;br style=&quot;border-color: var(--border-color);&quot;&gt;Outer Edge" style="ellipse;whiteSpace=wrap;html=1;strokeWidth=2;fillColor=#f5f5f5;gradientColor=#9AC7BF;strokeColor=#666666;" parent="1" vertex="1">
+          <mxGeometry x="670" y="700" width="120" height="80" as="geometry" />
+        </mxCell>
+        <mxCell id="KG5lhhUBjoQ79gfvQvIC-69" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;strokeWidth=2;" parent="1" source="KG5lhhUBjoQ79gfvQvIC-51" target="KG5lhhUBjoQ79gfvQvIC-43" edge="1">
+          <mxGeometry relative="1" as="geometry" />
+        </mxCell>
+        <mxCell id="KG5lhhUBjoQ79gfvQvIC-51" value="U(e&lt;sub&gt;2&lt;/sub&gt;)&lt;br style=&quot;border-color: var(--border-color);&quot;&gt;&lt;b style=&quot;border-color: var(--border-color);&quot;&gt;&lt;font style=&quot;border-color: var(--border-color);&quot; color=&quot;#0000ff&quot;&gt;OutgoingFermion&lt;br style=&quot;border-color: var(--border-color);&quot;&gt;&lt;/font&gt;&lt;/b&gt;Outer Edge" style="ellipse;whiteSpace=wrap;html=1;strokeWidth=2;fillColor=#f5f5f5;gradientColor=#9AC7BF;strokeColor=#666666;" parent="1" vertex="1">
+          <mxGeometry x="1030" y="700" width="120" height="80" as="geometry" />
+        </mxCell>
+        <mxCell id="KG5lhhUBjoQ79gfvQvIC-52" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;strokeWidth=2;" parent="1" source="KG5lhhUBjoQ79gfvQvIC-53" target="KG5lhhUBjoQ79gfvQvIC-47" edge="1">
+          <mxGeometry relative="1" as="geometry" />
+        </mxCell>
+        <mxCell id="KG5lhhUBjoQ79gfvQvIC-53" value="U(e&lt;sub&gt;1&lt;/sub&gt;)&lt;br style=&quot;border-color: var(--border-color);&quot;&gt;&lt;b style=&quot;border-color: var(--border-color);&quot;&gt;&lt;font style=&quot;border-color: var(--border-color);&quot; color=&quot;#0000ff&quot;&gt;IncomingFermion&lt;br style=&quot;border-color: var(--border-color);&quot;&gt;&lt;/font&gt;&lt;/b&gt;Outer Edge" style="ellipse;whiteSpace=wrap;html=1;strokeWidth=2;fillColor=#f5f5f5;gradientColor=#9AC7BF;strokeColor=#666666;" parent="1" vertex="1">
+          <mxGeometry x="910" y="700" width="120" height="80" as="geometry" />
+        </mxCell>
+        <mxCell id="KG5lhhUBjoQ79gfvQvIC-54" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;strokeWidth=2;" parent="1" source="KG5lhhUBjoQ79gfvQvIC-55" target="KG5lhhUBjoQ79gfvQvIC-45" edge="1">
+          <mxGeometry relative="1" as="geometry" />
+        </mxCell>
+        <mxCell id="KG5lhhUBjoQ79gfvQvIC-55" value="U(p&lt;sub style=&quot;border-color: var(--border-color);&quot;&gt;2&lt;/sub&gt;)&lt;br style=&quot;border-color: var(--border-color);&quot;&gt;&lt;font color=&quot;#0000ff&quot;&gt;&lt;b&gt;OutgoingAntiFermion&lt;br&gt;&lt;/b&gt;&lt;/font&gt;Outer Edge" style="ellipse;whiteSpace=wrap;html=1;strokeWidth=2;fillColor=#f5f5f5;gradientColor=#9AC7BF;strokeColor=#666666;" parent="1" vertex="1">
+          <mxGeometry x="790" y="700" width="120" height="80" as="geometry" />
+        </mxCell>
+        <mxCell id="KG5lhhUBjoQ79gfvQvIC-56" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;strokeWidth=2;" parent="1" source="KG5lhhUBjoQ79gfvQvIC-57" target="KG5lhhUBjoQ79gfvQvIC-59" edge="1">
+          <mxGeometry relative="1" as="geometry" />
+        </mxCell>
+        <mxCell id="KG5lhhUBjoQ79gfvQvIC-57" value="&lt;font style=&quot;font-size: 12px;&quot;&gt;V(p&lt;sub&gt;1&lt;/sub&gt;, p&lt;sub&gt;2&lt;/sub&gt;)&lt;/font&gt;&lt;br&gt;Result Particle:&lt;br&gt;q: &lt;b&gt;&lt;font color=&quot;#0000ff&quot;&gt;IncomingPhoton&lt;/font&gt;&lt;/b&gt;" style="ellipse;whiteSpace=wrap;html=1;strokeWidth=2;fillColor=#f5f5f5;gradientColor=#9AC7BF;strokeColor=#666666;" parent="1" vertex="1">
+          <mxGeometry x="720" y="480" width="140" height="80" as="geometry" />
+        </mxCell>
+        <mxCell id="KG5lhhUBjoQ79gfvQvIC-58" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;strokeWidth=2;" parent="1" source="KG5lhhUBjoQ79gfvQvIC-59" target="KG5lhhUBjoQ79gfvQvIC-65" edge="1">
+          <mxGeometry relative="1" as="geometry" />
+        </mxCell>
+        <mxCell id="KG5lhhUBjoQ79gfvQvIC-59" value="&lt;b style=&quot;border-color: var(--border-color);&quot;&gt;&lt;font style=&quot;border-color: var(--border-color);&quot; color=&quot;#336600&quot;&gt;vertex&lt;/font&gt;&lt;/b&gt;&amp;nbsp;-&amp;gt;&lt;br&gt;AdjointBiSpinor * &lt;br&gt;DiracMatrix *&lt;br&gt;BiSpinor&lt;br&gt;=&amp;nbsp;&lt;b style=&quot;border-color: var(--border-color);&quot;&gt;&lt;font style=&quot;border-color: var(--border-color);&quot; color=&quot;#cc00cc&quot;&gt;Complex&lt;/font&gt;&lt;/b&gt;" style="rounded=1;whiteSpace=wrap;html=1;strokeWidth=2;fillColor=#f5f5f5;gradientColor=#b3b3b3;strokeColor=#666666;" parent="1" vertex="1">
+          <mxGeometry x="730" y="360" width="120" height="80" as="geometry" />
+        </mxCell>
+        <mxCell id="KG5lhhUBjoQ79gfvQvIC-60" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;strokeWidth=2;" parent="1" source="KG5lhhUBjoQ79gfvQvIC-61" target="KG5lhhUBjoQ79gfvQvIC-63" edge="1">
+          <mxGeometry relative="1" as="geometry" />
+        </mxCell>
+        <mxCell id="KG5lhhUBjoQ79gfvQvIC-61" value="&lt;font style=&quot;font-size: 12px;&quot;&gt;V(e&lt;sub&gt;1&lt;/sub&gt;, e&lt;sub&gt;2&lt;/sub&gt;)&lt;/font&gt;&lt;br&gt;Result Particle:&lt;br&gt;q&#39;: &lt;font color=&quot;#0000ff&quot;&gt;&lt;b&gt;OutgoingPhoton&lt;/b&gt;&lt;/font&gt;" style="ellipse;whiteSpace=wrap;html=1;strokeWidth=2;fillColor=#f5f5f5;gradientColor=#9AC7BF;strokeColor=#666666;" parent="1" vertex="1">
+          <mxGeometry x="960" y="480" width="140" height="80" as="geometry" />
+        </mxCell>
+        <mxCell id="KG5lhhUBjoQ79gfvQvIC-62" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;strokeWidth=2;" parent="1" source="KG5lhhUBjoQ79gfvQvIC-63" target="KG5lhhUBjoQ79gfvQvIC-65" edge="1">
+          <mxGeometry relative="1" as="geometry">
+            <Array as="points">
+              <mxPoint x="1030" y="340" />
+              <mxPoint x="900" y="340" />
+            </Array>
+          </mxGeometry>
+        </mxCell>
+        <mxCell id="KG5lhhUBjoQ79gfvQvIC-63" value="&lt;b style=&quot;border-color: var(--border-color);&quot;&gt;&lt;font style=&quot;border-color: var(--border-color);&quot; color=&quot;#336600&quot;&gt;vertex&lt;/font&gt;&lt;/b&gt;&amp;nbsp;-&amp;gt;&lt;br&gt;AdjointBiSpinor * &lt;br&gt;DiracMatrix * &lt;br&gt;BiSpinor &lt;br&gt;=&amp;nbsp;&lt;b style=&quot;border-color: var(--border-color);&quot;&gt;&lt;font style=&quot;border-color: var(--border-color);&quot; color=&quot;#cc00cc&quot;&gt;Complex&lt;br&gt;&lt;/font&gt;&lt;/b&gt;" style="rounded=1;whiteSpace=wrap;html=1;strokeWidth=2;fillColor=#f5f5f5;gradientColor=#b3b3b3;strokeColor=#666666;" parent="1" vertex="1">
+          <mxGeometry x="970" y="360" width="120" height="80" as="geometry" />
+        </mxCell>
+        <mxCell id="KG5lhhUBjoQ79gfvQvIC-64" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;strokeWidth=2;" parent="1" source="KG5lhhUBjoQ79gfvQvIC-65" target="KG5lhhUBjoQ79gfvQvIC-66" edge="1">
+          <mxGeometry relative="1" as="geometry" />
+        </mxCell>
+        <mxCell id="KG5lhhUBjoQ79gfvQvIC-65" value="S2(q, q&#39;)&lt;br&gt;q == -q&#39;&lt;br&gt;&lt;b&gt;&lt;font color=&quot;#0000ff&quot;&gt;No Result Particle&lt;/font&gt;&lt;/b&gt;" style="ellipse;whiteSpace=wrap;html=1;strokeWidth=2;fillColor=#f5f5f5;gradientColor=#9AC7BF;strokeColor=#666666;" parent="1" vertex="1">
+          <mxGeometry x="840" y="240" width="120" height="80" as="geometry" />
+        </mxCell>
+        <mxCell id="KG5lhhUBjoQ79gfvQvIC-72" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;strokeWidth=2;" parent="1" source="KG5lhhUBjoQ79gfvQvIC-66" target="KG5lhhUBjoQ79gfvQvIC-70" edge="1">
+          <mxGeometry relative="1" as="geometry">
+            <Array as="points">
+              <mxPoint x="670" y="170" />
+            </Array>
+          </mxGeometry>
+        </mxCell>
+        <mxCell id="KG5lhhUBjoQ79gfvQvIC-66" value="&lt;b style=&quot;border-color: var(--border-color);&quot;&gt;&lt;font style=&quot;border-color: var(--border-color);&quot; color=&quot;#336600&quot;&gt;inner_edge&lt;/font&gt;&lt;/b&gt;&amp;nbsp;-&amp;gt;&lt;br&gt;Complex * propagator(q) * Complex&lt;br&gt;=&amp;nbsp;&lt;b style=&quot;border-color: var(--border-color);&quot;&gt;&lt;font color=&quot;#cc00cc&quot;&gt;Complex&lt;/font&gt;&lt;/b&gt;" style="rounded=1;whiteSpace=wrap;html=1;strokeWidth=2;fillColor=#f5f5f5;gradientColor=#b3b3b3;strokeColor=#666666;" parent="1" vertex="1">
+          <mxGeometry x="830" y="140" width="140" height="60" as="geometry" />
+        </mxCell>
+        <mxCell id="KG5lhhUBjoQ79gfvQvIC-70" value="&lt;span style=&quot;font-size: 32px;&quot;&gt;diff()&lt;/span&gt;" style="ellipse;whiteSpace=wrap;html=1;strokeWidth=2;fillColor=#ffcd28;strokeColor=#d79b00;gradientColor=#ffa500;" parent="1" vertex="1">
+          <mxGeometry x="610" y="20" width="120" height="80" as="geometry" />
+        </mxCell>
+        <mxCell id="KG5lhhUBjoQ79gfvQvIC-73" value="&lt;b&gt;&lt;font style=&quot;font-size: 22px;&quot;&gt;ValueAcc&lt;/font&gt;&lt;/b&gt;" style="text;html=1;strokeColor=none;fillColor=none;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;" parent="1" vertex="1">
+          <mxGeometry x="10" y="155" width="120" height="30" as="geometry" />
+        </mxCell>
+        <mxCell id="KG5lhhUBjoQ79gfvQvIC-74" value="&lt;b&gt;&lt;font style=&quot;font-size: 22px;&quot;&gt;ValueAcc&lt;/font&gt;&lt;/b&gt;" style="text;html=1;strokeColor=none;fillColor=none;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;" parent="1" vertex="1">
+          <mxGeometry x="10" y="385" width="120" height="30" as="geometry" />
+        </mxCell>
+        <mxCell id="KG5lhhUBjoQ79gfvQvIC-75" value="&lt;b&gt;&lt;font style=&quot;font-size: 22px;&quot;&gt;ValueAcc&lt;/font&gt;&lt;/b&gt;" style="text;html=1;strokeColor=none;fillColor=none;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;" parent="1" vertex="1">
+          <mxGeometry x="10" y="615" width="120" height="30" as="geometry" />
+        </mxCell>
+        <mxCell id="KG5lhhUBjoQ79gfvQvIC-76" value="&lt;b&gt;&lt;font style=&quot;font-size: 22px;&quot;&gt;Particle Propagation&lt;/font&gt;&lt;/b&gt;" style="text;html=1;strokeColor=none;fillColor=none;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;" parent="1" vertex="1">
+          <mxGeometry x="10" y="725" width="120" height="30" as="geometry" />
+        </mxCell>
+        <mxCell id="KG5lhhUBjoQ79gfvQvIC-77" value="&lt;b&gt;&lt;font style=&quot;font-size: 22px;&quot;&gt;Particle Propagation&lt;/font&gt;&lt;/b&gt;" style="text;html=1;strokeColor=none;fillColor=none;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;" parent="1" vertex="1">
+          <mxGeometry x="10" y="505" width="120" height="30" as="geometry" />
+        </mxCell>
+        <mxCell id="KG5lhhUBjoQ79gfvQvIC-78" value="&lt;b&gt;&lt;font style=&quot;font-size: 22px;&quot;&gt;Particle Propagation&lt;/font&gt;&lt;/b&gt;" style="text;html=1;strokeColor=none;fillColor=none;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;" parent="1" vertex="1">
+          <mxGeometry x="10" y="265" width="120" height="30" as="geometry" />
+        </mxCell>
+        <mxCell id="KG5lhhUBjoQ79gfvQvIC-79" value="" style="endArrow=none;dashed=1;html=1;dashPattern=1 3;strokeWidth=2;rounded=0;" parent="1" edge="1">
+          <mxGeometry width="50" height="50" relative="1" as="geometry">
+            <mxPoint y="220" as="sourcePoint" />
+            <mxPoint x="1160" y="220" as="targetPoint" />
+          </mxGeometry>
+        </mxCell>
+        <mxCell id="KG5lhhUBjoQ79gfvQvIC-80" value="" style="endArrow=none;dashed=1;html=1;dashPattern=1 3;strokeWidth=2;rounded=0;" parent="1" edge="1">
+          <mxGeometry width="50" height="50" relative="1" as="geometry">
+            <mxPoint y="340" as="sourcePoint" />
+            <mxPoint x="1160" y="340" as="targetPoint" />
+          </mxGeometry>
+        </mxCell>
+        <mxCell id="KG5lhhUBjoQ79gfvQvIC-81" value="" style="endArrow=none;dashed=1;html=1;dashPattern=1 3;strokeWidth=2;rounded=0;" parent="1" edge="1">
+          <mxGeometry width="50" height="50" relative="1" as="geometry">
+            <mxPoint y="460" as="sourcePoint" />
+            <mxPoint x="1160" y="460" as="targetPoint" />
+          </mxGeometry>
+        </mxCell>
+        <mxCell id="KG5lhhUBjoQ79gfvQvIC-82" value="" style="endArrow=none;dashed=1;html=1;dashPattern=1 3;strokeWidth=2;rounded=0;" parent="1" edge="1">
+          <mxGeometry width="50" height="50" relative="1" as="geometry">
+            <mxPoint y="120" as="sourcePoint" />
+            <mxPoint x="1160" y="120" as="targetPoint" />
+          </mxGeometry>
+        </mxCell>
+        <mxCell id="KG5lhhUBjoQ79gfvQvIC-83" value="" style="endArrow=none;dashed=1;html=1;dashPattern=1 3;strokeWidth=2;rounded=0;" parent="1" edge="1">
+          <mxGeometry width="50" height="50" relative="1" as="geometry">
+            <mxPoint y="580" as="sourcePoint" />
+            <mxPoint x="1160" y="580" as="targetPoint" />
+          </mxGeometry>
+        </mxCell>
+        <mxCell id="KG5lhhUBjoQ79gfvQvIC-84" value="" style="endArrow=none;dashed=1;html=1;dashPattern=1 3;strokeWidth=2;rounded=0;" parent="1" edge="1">
+          <mxGeometry width="50" height="50" relative="1" as="geometry">
+            <mxPoint y="680" as="sourcePoint" />
+            <mxPoint x="1160" y="680" as="targetPoint" />
+          </mxGeometry>
+        </mxCell>
+        <mxCell id="KG5lhhUBjoQ79gfvQvIC-85" value="" style="endArrow=none;dashed=1;html=1;dashPattern=1 3;strokeWidth=2;rounded=0;" parent="1" edge="1">
+          <mxGeometry width="50" height="50" relative="1" as="geometry">
+            <mxPoint y="800" as="sourcePoint" />
+            <mxPoint x="1160" y="800" as="targetPoint" />
+          </mxGeometry>
+        </mxCell>
+      </root>
+    </mxGraphModel>
+  </diagram>
+</mxfile>
diff --git a/docs/src/QED-Compton-DAG.drawio b/docs/src/QED-Compton-DAG.drawio
new file mode 100644
index 0000000..dd51f9d
--- /dev/null
+++ b/docs/src/QED-Compton-DAG.drawio
@@ -0,0 +1,259 @@
+<mxfile host="Electron" modified="2023-11-25T19:38:46.724Z" agent="Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) draw.io/21.6.1 Chrome/114.0.5735.289 Electron/25.9.4 Safari/537.36" etag="GgWoS9drZkpaqTCZiHI_" version="21.6.1" type="device">
+  <diagram name="Page-1" id="pzz-rsbNjEFeZeQIA-38">
+    <mxGraphModel dx="1430" dy="853" grid="1" gridSize="10" guides="1" tooltips="1" connect="1" arrows="1" fold="1" page="1" pageScale="1" pageWidth="500" pageHeight="900" math="0" shadow="0">
+      <root>
+        <mxCell id="0" />
+        <mxCell id="1" parent="0" />
+        <mxCell id="KG5lhhUBjoQ79gfvQvIC-19" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;strokeWidth=2;" parent="1" source="KG5lhhUBjoQ79gfvQvIC-6" target="KG5lhhUBjoQ79gfvQvIC-18" edge="1">
+          <mxGeometry relative="1" as="geometry" />
+        </mxCell>
+        <mxCell id="KG5lhhUBjoQ79gfvQvIC-6" value="&lt;b style=&quot;border-color: var(--border-color);&quot;&gt;&lt;font style=&quot;border-color: var(--border-color);&quot; color=&quot;#336600&quot;&gt;base_state&lt;/font&gt;&lt;/b&gt;&amp;nbsp;-&amp;gt;&lt;br&gt;&lt;b style=&quot;border-color: var(--border-color);&quot;&gt;&lt;font color=&quot;#cc00cc&quot;&gt;LorentzVector&lt;/font&gt;&lt;/b&gt;" style="rounded=1;whiteSpace=wrap;html=1;strokeWidth=2;fillColor=#f5f5f5;gradientColor=#b3b3b3;strokeColor=#666666;" parent="1" vertex="1">
+          <mxGeometry x="190" y="600" width="120" height="60" as="geometry" />
+        </mxCell>
+        <mxCell id="KG5lhhUBjoQ79gfvQvIC-20" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;strokeWidth=2;" parent="1" source="KG5lhhUBjoQ79gfvQvIC-7" target="KG5lhhUBjoQ79gfvQvIC-18" edge="1">
+          <mxGeometry relative="1" as="geometry" />
+        </mxCell>
+        <mxCell id="KG5lhhUBjoQ79gfvQvIC-7" value="&lt;b style=&quot;border-color: var(--border-color);&quot;&gt;&lt;font style=&quot;border-color: var(--border-color);&quot; color=&quot;#336600&quot;&gt;base_state&lt;/font&gt;&lt;/b&gt;&amp;nbsp;-&amp;gt;&lt;br&gt;&lt;b style=&quot;border-color: var(--border-color);&quot;&gt;&lt;font style=&quot;border-color: var(--border-color);&quot; color=&quot;#cc00cc&quot;&gt;BiSpinor&lt;/font&gt;&lt;/b&gt;" style="rounded=1;whiteSpace=wrap;html=1;strokeWidth=2;fillColor=#f5f5f5;gradientColor=#b3b3b3;strokeColor=#666666;" parent="1" vertex="1">
+          <mxGeometry x="310" y="600" width="120" height="60" as="geometry" />
+        </mxCell>
+        <mxCell id="KG5lhhUBjoQ79gfvQvIC-28" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;strokeWidth=2;" parent="1" source="KG5lhhUBjoQ79gfvQvIC-8" target="KG5lhhUBjoQ79gfvQvIC-26" edge="1">
+          <mxGeometry relative="1" as="geometry" />
+        </mxCell>
+        <mxCell id="KG5lhhUBjoQ79gfvQvIC-8" value="&lt;b style=&quot;border-color: var(--border-color);&quot;&gt;&lt;font style=&quot;border-color: var(--border-color);&quot; color=&quot;#336600&quot;&gt;base_state&lt;/font&gt;&lt;/b&gt;&amp;nbsp;-&amp;gt;&lt;br&gt;&lt;b style=&quot;border-color: var(--border-color);&quot;&gt;&lt;font style=&quot;border-color: var(--border-color);&quot; color=&quot;#cc00cc&quot;&gt;AdjointBiSpinor&lt;/font&gt;&lt;/b&gt;" style="rounded=1;whiteSpace=wrap;html=1;strokeWidth=2;fillColor=#f5f5f5;gradientColor=#b3b3b3;strokeColor=#666666;" parent="1" vertex="1">
+          <mxGeometry x="550" y="600" width="120" height="60" as="geometry" />
+        </mxCell>
+        <mxCell id="KG5lhhUBjoQ79gfvQvIC-29" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;strokeWidth=2;" parent="1" source="KG5lhhUBjoQ79gfvQvIC-9" target="KG5lhhUBjoQ79gfvQvIC-26" edge="1">
+          <mxGeometry relative="1" as="geometry" />
+        </mxCell>
+        <mxCell id="KG5lhhUBjoQ79gfvQvIC-9" value="&lt;b style=&quot;border-color: var(--border-color);&quot;&gt;&lt;font style=&quot;border-color: var(--border-color);&quot; color=&quot;#336600&quot;&gt;base_state&lt;/font&gt;&lt;/b&gt;&amp;nbsp;-&amp;gt;&lt;br&gt;&lt;b style=&quot;border-color: var(--border-color);&quot;&gt;&lt;font style=&quot;border-color: var(--border-color);&quot; color=&quot;#cc00cc&quot;&gt;LorentzVector&lt;/font&gt;&lt;/b&gt;" style="rounded=1;whiteSpace=wrap;html=1;strokeWidth=2;fillColor=#f5f5f5;gradientColor=#b3b3b3;strokeColor=#666666;" parent="1" vertex="1">
+          <mxGeometry x="430" y="600" width="120" height="60" as="geometry" />
+        </mxCell>
+        <mxCell id="KG5lhhUBjoQ79gfvQvIC-21" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;strokeWidth=2;" parent="1" source="KG5lhhUBjoQ79gfvQvIC-14" target="KG5lhhUBjoQ79gfvQvIC-6" edge="1">
+          <mxGeometry relative="1" as="geometry" />
+        </mxCell>
+        <mxCell id="KG5lhhUBjoQ79gfvQvIC-14" value="U(γ&lt;sub style=&quot;border-color: var(--border-color);&quot;&gt;1&lt;/sub&gt;)&lt;br style=&quot;border-color: var(--border-color);&quot;&gt;&lt;font color=&quot;#0000ff&quot;&gt;&lt;b&gt;IncomingPhoton&lt;/b&gt;&lt;/font&gt;&lt;br&gt;Outer Edge" style="ellipse;whiteSpace=wrap;html=1;strokeWidth=2;fillColor=#f5f5f5;gradientColor=#9AC7BF;strokeColor=#666666;" parent="1" vertex="1">
+          <mxGeometry x="190" y="700" width="120" height="80" as="geometry" />
+        </mxCell>
+        <mxCell id="KG5lhhUBjoQ79gfvQvIC-22" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;strokeWidth=2;" parent="1" source="KG5lhhUBjoQ79gfvQvIC-15" target="KG5lhhUBjoQ79gfvQvIC-7" edge="1">
+          <mxGeometry relative="1" as="geometry" />
+        </mxCell>
+        <mxCell id="KG5lhhUBjoQ79gfvQvIC-15" value="U(p&lt;sub style=&quot;border-color: var(--border-color);&quot;&gt;1&lt;/sub&gt;)&lt;br style=&quot;border-color: var(--border-color);&quot;&gt;&lt;b&gt;&lt;font color=&quot;#0000ff&quot;&gt;IncomingFermion&lt;br&gt;&lt;/font&gt;&lt;/b&gt;Outer Edge" style="ellipse;whiteSpace=wrap;html=1;strokeWidth=2;fillColor=#f5f5f5;gradientColor=#9AC7BF;strokeColor=#666666;" parent="1" vertex="1">
+          <mxGeometry x="310" y="700" width="120" height="80" as="geometry" />
+        </mxCell>
+        <mxCell id="KG5lhhUBjoQ79gfvQvIC-23" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;strokeWidth=2;" parent="1" source="KG5lhhUBjoQ79gfvQvIC-16" target="KG5lhhUBjoQ79gfvQvIC-9" edge="1">
+          <mxGeometry relative="1" as="geometry" />
+        </mxCell>
+        <mxCell id="KG5lhhUBjoQ79gfvQvIC-16" value="U(γ&lt;sub style=&quot;border-color: var(--border-color);&quot;&gt;2&lt;/sub&gt;)&lt;br style=&quot;border-color: var(--border-color);&quot;&gt;&lt;b&gt;&lt;font color=&quot;#0000ff&quot;&gt;OutgoingPhoton&lt;br&gt;&lt;/font&gt;&lt;/b&gt;Outer Edge" style="ellipse;whiteSpace=wrap;html=1;strokeWidth=2;fillColor=#f5f5f5;gradientColor=#9AC7BF;strokeColor=#666666;" parent="1" vertex="1">
+          <mxGeometry x="430" y="700" width="120" height="80" as="geometry" />
+        </mxCell>
+        <mxCell id="KG5lhhUBjoQ79gfvQvIC-24" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;strokeWidth=2;" parent="1" source="KG5lhhUBjoQ79gfvQvIC-17" target="KG5lhhUBjoQ79gfvQvIC-8" edge="1">
+          <mxGeometry relative="1" as="geometry" />
+        </mxCell>
+        <mxCell id="KG5lhhUBjoQ79gfvQvIC-17" value="U(p&lt;sub style=&quot;border-color: var(--border-color);&quot;&gt;2&lt;/sub&gt;)&lt;br style=&quot;border-color: var(--border-color);&quot;&gt;&lt;b&gt;&lt;font color=&quot;#0000ff&quot;&gt;OutgoingFermion&lt;br&gt;&lt;/font&gt;&lt;/b&gt;Outer Edge" style="ellipse;whiteSpace=wrap;html=1;strokeWidth=2;fillColor=#f5f5f5;gradientColor=#9AC7BF;strokeColor=#666666;" parent="1" vertex="1">
+          <mxGeometry x="550" y="700" width="120" height="80" as="geometry" />
+        </mxCell>
+        <mxCell id="KG5lhhUBjoQ79gfvQvIC-30" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;strokeWidth=2;" parent="1" source="KG5lhhUBjoQ79gfvQvIC-18" target="KG5lhhUBjoQ79gfvQvIC-25" edge="1">
+          <mxGeometry relative="1" as="geometry" />
+        </mxCell>
+        <mxCell id="KG5lhhUBjoQ79gfvQvIC-18" value="V(γ&lt;sub&gt;1&lt;/sub&gt;, p&lt;sub&gt;1&lt;/sub&gt;)&lt;br&gt;Result Particle:&lt;br&gt;q: &lt;font color=&quot;#0000ff&quot;&gt;&lt;b&gt;OutgoingFermion&lt;/b&gt;&lt;/font&gt;" style="ellipse;whiteSpace=wrap;html=1;strokeWidth=2;fillColor=#f5f5f5;gradientColor=#9AC7BF;strokeColor=#666666;" parent="1" vertex="1">
+          <mxGeometry x="240" y="480" width="140" height="80" as="geometry" />
+        </mxCell>
+        <mxCell id="KG5lhhUBjoQ79gfvQvIC-36" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;strokeWidth=2;" parent="1" source="KG5lhhUBjoQ79gfvQvIC-25" target="KG5lhhUBjoQ79gfvQvIC-35" edge="1">
+          <mxGeometry relative="1" as="geometry" />
+        </mxCell>
+        <mxCell id="KG5lhhUBjoQ79gfvQvIC-25" value="&lt;b&gt;&lt;font color=&quot;#336600&quot;&gt;vertex&lt;/font&gt;&lt;/b&gt; -&amp;gt;&lt;br&gt;LorentzVector * DiracMatrix * &lt;br&gt;BiSpinor&lt;br&gt;=&amp;nbsp;&lt;b style=&quot;border-color: var(--border-color);&quot;&gt;&lt;font color=&quot;#cc00cc&quot; style=&quot;border-color: var(--border-color);&quot;&gt;BiSpinor&lt;/font&gt;&lt;/b&gt;" style="rounded=1;whiteSpace=wrap;html=1;strokeWidth=2;fillColor=#f5f5f5;gradientColor=#b3b3b3;strokeColor=#666666;" parent="1" vertex="1">
+          <mxGeometry x="250" y="360" width="120" height="80" as="geometry" />
+        </mxCell>
+        <mxCell id="KG5lhhUBjoQ79gfvQvIC-32" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;strokeWidth=2;" parent="1" source="KG5lhhUBjoQ79gfvQvIC-26" target="KG5lhhUBjoQ79gfvQvIC-27" edge="1">
+          <mxGeometry relative="1" as="geometry" />
+        </mxCell>
+        <mxCell id="KG5lhhUBjoQ79gfvQvIC-26" value="V(γ&lt;sub&gt;2&lt;/sub&gt;, p&lt;sub&gt;2&lt;/sub&gt;)&lt;br&gt;Result Particle:&lt;br&gt;q&#39;: &lt;b&gt;&lt;font color=&quot;#0000ff&quot;&gt;IncomingFermion&lt;/font&gt;&lt;/b&gt;" style="ellipse;whiteSpace=wrap;html=1;strokeWidth=2;fillColor=#f5f5f5;gradientColor=#9AC7BF;strokeColor=#666666;" parent="1" vertex="1">
+          <mxGeometry x="480" y="480" width="140" height="80" as="geometry" />
+        </mxCell>
+        <mxCell id="KG5lhhUBjoQ79gfvQvIC-37" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;strokeWidth=2;" parent="1" source="KG5lhhUBjoQ79gfvQvIC-27" target="KG5lhhUBjoQ79gfvQvIC-35" edge="1">
+          <mxGeometry relative="1" as="geometry">
+            <Array as="points">
+              <mxPoint x="550" y="340" />
+              <mxPoint x="420" y="340" />
+            </Array>
+          </mxGeometry>
+        </mxCell>
+        <mxCell id="KG5lhhUBjoQ79gfvQvIC-27" value="&lt;b style=&quot;border-color: var(--border-color);&quot;&gt;&lt;font style=&quot;border-color: var(--border-color);&quot; color=&quot;#336600&quot;&gt;vertex&lt;/font&gt;&lt;/b&gt;&amp;nbsp;-&amp;gt;&lt;br&gt;AdjointBiSpinor * LorentzVector * &lt;br&gt;DiracMatrix &lt;br&gt;=&amp;nbsp;&lt;b style=&quot;border-color: var(--border-color);&quot;&gt;&lt;font color=&quot;#cc00cc&quot; style=&quot;border-color: var(--border-color);&quot;&gt;AdjointBiSpinor&lt;/font&gt;&lt;/b&gt;" style="rounded=1;whiteSpace=wrap;html=1;strokeWidth=2;fillColor=#f5f5f5;gradientColor=#b3b3b3;strokeColor=#666666;" parent="1" vertex="1">
+          <mxGeometry x="490" y="360" width="120" height="80" as="geometry" />
+        </mxCell>
+        <mxCell id="KG5lhhUBjoQ79gfvQvIC-39" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;strokeWidth=2;" parent="1" source="KG5lhhUBjoQ79gfvQvIC-35" target="KG5lhhUBjoQ79gfvQvIC-38" edge="1">
+          <mxGeometry relative="1" as="geometry" />
+        </mxCell>
+        <mxCell id="KG5lhhUBjoQ79gfvQvIC-35" value="S2(q, q&#39;)&lt;br&gt;q == -q&#39;&lt;br&gt;&lt;b&gt;&lt;font color=&quot;#0000ff&quot;&gt;No Result Particle&lt;/font&gt;&lt;/b&gt;" style="ellipse;whiteSpace=wrap;html=1;strokeWidth=2;fillColor=#f5f5f5;gradientColor=#9AC7BF;strokeColor=#666666;" parent="1" vertex="1">
+          <mxGeometry x="360" y="240" width="120" height="80" as="geometry" />
+        </mxCell>
+        <mxCell id="KG5lhhUBjoQ79gfvQvIC-71" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;strokeWidth=2;" parent="1" source="KG5lhhUBjoQ79gfvQvIC-38" target="KG5lhhUBjoQ79gfvQvIC-70" edge="1">
+          <mxGeometry relative="1" as="geometry">
+            <Array as="points">
+              <mxPoint x="670" y="170" />
+            </Array>
+          </mxGeometry>
+        </mxCell>
+        <mxCell id="KG5lhhUBjoQ79gfvQvIC-38" value="&lt;b style=&quot;&quot;&gt;&lt;font color=&quot;#336600&quot;&gt;inner_edge&lt;/font&gt;&lt;/b&gt; -&amp;gt;&lt;br&gt;AdjointBiSpinor * propagator(q) * BiSpinor =&amp;nbsp;&lt;b style=&quot;border-color: var(--border-color);&quot;&gt;&lt;font style=&quot;border-color: var(--border-color);&quot; color=&quot;#cc00cc&quot;&gt;ComplexF64&lt;/font&gt;&lt;/b&gt;" style="rounded=1;whiteSpace=wrap;html=1;strokeWidth=2;fillColor=#f5f5f5;gradientColor=#b3b3b3;strokeColor=#666666;" parent="1" vertex="1">
+          <mxGeometry x="350" y="140" width="140" height="60" as="geometry" />
+        </mxCell>
+        <mxCell id="KG5lhhUBjoQ79gfvQvIC-40" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;strokeWidth=2;" parent="1" source="KG5lhhUBjoQ79gfvQvIC-41" target="KG5lhhUBjoQ79gfvQvIC-57" edge="1">
+          <mxGeometry relative="1" as="geometry" />
+        </mxCell>
+        <mxCell id="KG5lhhUBjoQ79gfvQvIC-41" value="&lt;b style=&quot;border-color: var(--border-color);&quot;&gt;&lt;font style=&quot;border-color: var(--border-color);&quot; color=&quot;#336600&quot;&gt;base_state&lt;/font&gt;&lt;/b&gt;&amp;nbsp;-&amp;gt;&lt;br&gt;&lt;b style=&quot;border-color: var(--border-color);&quot;&gt;&lt;font style=&quot;border-color: var(--border-color);&quot; color=&quot;#cc00cc&quot;&gt;LorentzVector&lt;/font&gt;&lt;/b&gt;" style="rounded=1;whiteSpace=wrap;html=1;strokeWidth=2;fillColor=#f5f5f5;gradientColor=#b3b3b3;strokeColor=#666666;" parent="1" vertex="1">
+          <mxGeometry x="670" y="600" width="120" height="60" as="geometry" />
+        </mxCell>
+        <mxCell id="KG5lhhUBjoQ79gfvQvIC-68" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;strokeWidth=2;" parent="1" source="KG5lhhUBjoQ79gfvQvIC-43" target="KG5lhhUBjoQ79gfvQvIC-61" edge="1">
+          <mxGeometry relative="1" as="geometry" />
+        </mxCell>
+        <mxCell id="KG5lhhUBjoQ79gfvQvIC-43" value="&lt;b style=&quot;&quot;&gt;&lt;font color=&quot;#336600&quot;&gt;base_state&lt;/font&gt;&lt;/b&gt; -&amp;gt;&lt;br&gt;&lt;b style=&quot;border-color: var(--border-color);&quot;&gt;&lt;font style=&quot;border-color: var(--border-color);&quot; color=&quot;#cc00cc&quot;&gt;BiSpinor&lt;/font&gt;&lt;/b&gt;" style="rounded=1;whiteSpace=wrap;html=1;strokeWidth=2;fillColor=#f5f5f5;gradientColor=#b3b3b3;strokeColor=#666666;" parent="1" vertex="1">
+          <mxGeometry x="1030" y="600" width="120" height="60" as="geometry" />
+        </mxCell>
+        <mxCell id="KG5lhhUBjoQ79gfvQvIC-67" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;strokeWidth=2;" parent="1" source="KG5lhhUBjoQ79gfvQvIC-45" target="KG5lhhUBjoQ79gfvQvIC-57" edge="1">
+          <mxGeometry relative="1" as="geometry" />
+        </mxCell>
+        <mxCell id="KG5lhhUBjoQ79gfvQvIC-45" value="&lt;b style=&quot;border-color: var(--border-color);&quot;&gt;&lt;font style=&quot;border-color: var(--border-color);&quot; color=&quot;#336600&quot;&gt;base_state&lt;/font&gt;&lt;/b&gt;&amp;nbsp;-&amp;gt;&lt;br&gt;&lt;b style=&quot;border-color: var(--border-color);&quot;&gt;&lt;font style=&quot;border-color: var(--border-color);&quot; color=&quot;#cc00cc&quot;&gt;AdjointBiSpinor&lt;/font&gt;&lt;/b&gt;" style="rounded=1;whiteSpace=wrap;html=1;strokeWidth=2;fillColor=#f5f5f5;gradientColor=#b3b3b3;strokeColor=#666666;" parent="1" vertex="1">
+          <mxGeometry x="790" y="600" width="120" height="60" as="geometry" />
+        </mxCell>
+        <mxCell id="KG5lhhUBjoQ79gfvQvIC-46" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;strokeWidth=2;" parent="1" source="KG5lhhUBjoQ79gfvQvIC-47" target="KG5lhhUBjoQ79gfvQvIC-61" edge="1">
+          <mxGeometry relative="1" as="geometry" />
+        </mxCell>
+        <mxCell id="KG5lhhUBjoQ79gfvQvIC-47" value="&lt;b style=&quot;border-color: var(--border-color);&quot;&gt;&lt;font style=&quot;border-color: var(--border-color);&quot; color=&quot;#336600&quot;&gt;base_state&lt;/font&gt;&lt;/b&gt;&amp;nbsp;-&amp;gt;&lt;br&gt;&lt;b style=&quot;border-color: var(--border-color);&quot;&gt;&lt;font style=&quot;border-color: var(--border-color);&quot; color=&quot;#cc00cc&quot;&gt;LorentzVector&lt;/font&gt;&lt;/b&gt;" style="rounded=1;whiteSpace=wrap;html=1;strokeWidth=2;fillColor=#f5f5f5;gradientColor=#b3b3b3;strokeColor=#666666;" parent="1" vertex="1">
+          <mxGeometry x="910" y="600" width="120" height="60" as="geometry" />
+        </mxCell>
+        <mxCell id="KG5lhhUBjoQ79gfvQvIC-48" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;strokeWidth=2;" parent="1" source="KG5lhhUBjoQ79gfvQvIC-49" target="KG5lhhUBjoQ79gfvQvIC-41" edge="1">
+          <mxGeometry relative="1" as="geometry" />
+        </mxCell>
+        <mxCell id="KG5lhhUBjoQ79gfvQvIC-49" value="U(γ&lt;sub style=&quot;border-color: var(--border-color);&quot;&gt;1&lt;/sub&gt;)&lt;br style=&quot;border-color: var(--border-color);&quot;&gt;&lt;font style=&quot;border-color: var(--border-color);&quot; color=&quot;#0000ff&quot;&gt;&lt;b style=&quot;border-color: var(--border-color);&quot;&gt;IncomingPhoton&lt;/b&gt;&lt;/font&gt;&lt;br style=&quot;border-color: var(--border-color);&quot;&gt;Outer Edge" style="ellipse;whiteSpace=wrap;html=1;strokeWidth=2;fillColor=#f5f5f5;gradientColor=#9AC7BF;strokeColor=#666666;" parent="1" vertex="1">
+          <mxGeometry x="670" y="700" width="120" height="80" as="geometry" />
+        </mxCell>
+        <mxCell id="KG5lhhUBjoQ79gfvQvIC-69" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;strokeWidth=2;" parent="1" source="KG5lhhUBjoQ79gfvQvIC-51" target="KG5lhhUBjoQ79gfvQvIC-43" edge="1">
+          <mxGeometry relative="1" as="geometry" />
+        </mxCell>
+        <mxCell id="KG5lhhUBjoQ79gfvQvIC-51" value="U(p&lt;sub style=&quot;border-color: var(--border-color);&quot;&gt;1&lt;/sub&gt;)&lt;br style=&quot;border-color: var(--border-color);&quot;&gt;&lt;b style=&quot;border-color: var(--border-color);&quot;&gt;&lt;font style=&quot;border-color: var(--border-color);&quot; color=&quot;#0000ff&quot;&gt;IncomingFermion&lt;br style=&quot;border-color: var(--border-color);&quot;&gt;&lt;/font&gt;&lt;/b&gt;Outer Edge" style="ellipse;whiteSpace=wrap;html=1;strokeWidth=2;fillColor=#f5f5f5;gradientColor=#9AC7BF;strokeColor=#666666;" parent="1" vertex="1">
+          <mxGeometry x="1030" y="700" width="120" height="80" as="geometry" />
+        </mxCell>
+        <mxCell id="KG5lhhUBjoQ79gfvQvIC-52" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;strokeWidth=2;" parent="1" source="KG5lhhUBjoQ79gfvQvIC-53" target="KG5lhhUBjoQ79gfvQvIC-47" edge="1">
+          <mxGeometry relative="1" as="geometry" />
+        </mxCell>
+        <mxCell id="KG5lhhUBjoQ79gfvQvIC-53" value="U(γ&lt;sub style=&quot;border-color: var(--border-color);&quot;&gt;2&lt;/sub&gt;)&lt;br style=&quot;border-color: var(--border-color);&quot;&gt;&lt;b style=&quot;border-color: var(--border-color);&quot;&gt;&lt;font style=&quot;border-color: var(--border-color);&quot; color=&quot;#0000ff&quot;&gt;OutgoingPhoton&lt;br style=&quot;border-color: var(--border-color);&quot;&gt;&lt;/font&gt;&lt;/b&gt;Outer Edge" style="ellipse;whiteSpace=wrap;html=1;strokeWidth=2;fillColor=#f5f5f5;gradientColor=#9AC7BF;strokeColor=#666666;" parent="1" vertex="1">
+          <mxGeometry x="910" y="700" width="120" height="80" as="geometry" />
+        </mxCell>
+        <mxCell id="KG5lhhUBjoQ79gfvQvIC-54" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;strokeWidth=2;" parent="1" source="KG5lhhUBjoQ79gfvQvIC-55" target="KG5lhhUBjoQ79gfvQvIC-45" edge="1">
+          <mxGeometry relative="1" as="geometry" />
+        </mxCell>
+        <mxCell id="KG5lhhUBjoQ79gfvQvIC-55" value="U(p&lt;sub style=&quot;border-color: var(--border-color);&quot;&gt;2&lt;/sub&gt;)&lt;br style=&quot;border-color: var(--border-color);&quot;&gt;&lt;font color=&quot;#0000ff&quot;&gt;&lt;b&gt;OutgoingFermion&lt;br&gt;&lt;/b&gt;&lt;/font&gt;Outer Edge" style="ellipse;whiteSpace=wrap;html=1;strokeWidth=2;fillColor=#f5f5f5;gradientColor=#9AC7BF;strokeColor=#666666;" parent="1" vertex="1">
+          <mxGeometry x="790" y="700" width="120" height="80" as="geometry" />
+        </mxCell>
+        <mxCell id="KG5lhhUBjoQ79gfvQvIC-56" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;strokeWidth=2;" parent="1" source="KG5lhhUBjoQ79gfvQvIC-57" target="KG5lhhUBjoQ79gfvQvIC-59" edge="1">
+          <mxGeometry relative="1" as="geometry" />
+        </mxCell>
+        <mxCell id="KG5lhhUBjoQ79gfvQvIC-57" value="V(γ&lt;sub&gt;1&lt;/sub&gt;, p&lt;span style=&quot;font-size: 10px;&quot;&gt;&lt;sub&gt;2&lt;/sub&gt;&lt;/span&gt;)&lt;br&gt;Result Particle:&lt;br&gt;q: &lt;b&gt;&lt;font color=&quot;#0000ff&quot;&gt;IncomingFermion&lt;/font&gt;&lt;/b&gt;" style="ellipse;whiteSpace=wrap;html=1;strokeWidth=2;fillColor=#f5f5f5;gradientColor=#9AC7BF;strokeColor=#666666;" parent="1" vertex="1">
+          <mxGeometry x="720" y="480" width="140" height="80" as="geometry" />
+        </mxCell>
+        <mxCell id="KG5lhhUBjoQ79gfvQvIC-58" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;strokeWidth=2;" parent="1" source="KG5lhhUBjoQ79gfvQvIC-59" target="KG5lhhUBjoQ79gfvQvIC-65" edge="1">
+          <mxGeometry relative="1" as="geometry" />
+        </mxCell>
+        <mxCell id="KG5lhhUBjoQ79gfvQvIC-59" value="&lt;b style=&quot;border-color: var(--border-color);&quot;&gt;&lt;font style=&quot;border-color: var(--border-color);&quot; color=&quot;#336600&quot;&gt;vertex&lt;/font&gt;&lt;/b&gt;&amp;nbsp;-&amp;gt;&lt;br&gt;AdjointBiSpinor * LorentzVector * &lt;br&gt;DiracMatrix&amp;nbsp;&lt;br&gt;=&amp;nbsp;&lt;b style=&quot;border-color: var(--border-color);&quot;&gt;&lt;font style=&quot;border-color: var(--border-color);&quot; color=&quot;#cc00cc&quot;&gt;AdjointBiSpinor&lt;/font&gt;&lt;/b&gt;" style="rounded=1;whiteSpace=wrap;html=1;strokeWidth=2;fillColor=#f5f5f5;gradientColor=#b3b3b3;strokeColor=#666666;" parent="1" vertex="1">
+          <mxGeometry x="730" y="360" width="120" height="80" as="geometry" />
+        </mxCell>
+        <mxCell id="KG5lhhUBjoQ79gfvQvIC-60" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;strokeWidth=2;" parent="1" source="KG5lhhUBjoQ79gfvQvIC-61" target="KG5lhhUBjoQ79gfvQvIC-63" edge="1">
+          <mxGeometry relative="1" as="geometry" />
+        </mxCell>
+        <mxCell id="KG5lhhUBjoQ79gfvQvIC-61" value="V(γ&lt;sub&gt;2&lt;/sub&gt;, p&lt;span style=&quot;font-size: 10px;&quot;&gt;&lt;sub&gt;1&lt;/sub&gt;&lt;/span&gt;)&lt;br&gt;Result Particle:&lt;br&gt;q&#39;: &lt;b&gt;&lt;font color=&quot;#0000ff&quot;&gt;OutgoingFermion&lt;/font&gt;&lt;/b&gt;" style="ellipse;whiteSpace=wrap;html=1;strokeWidth=2;fillColor=#f5f5f5;gradientColor=#9AC7BF;strokeColor=#666666;" parent="1" vertex="1">
+          <mxGeometry x="960" y="480" width="140" height="80" as="geometry" />
+        </mxCell>
+        <mxCell id="KG5lhhUBjoQ79gfvQvIC-62" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;strokeWidth=2;" parent="1" source="KG5lhhUBjoQ79gfvQvIC-63" target="KG5lhhUBjoQ79gfvQvIC-65" edge="1">
+          <mxGeometry relative="1" as="geometry">
+            <Array as="points">
+              <mxPoint x="1030" y="340" />
+              <mxPoint x="900" y="340" />
+            </Array>
+          </mxGeometry>
+        </mxCell>
+        <mxCell id="KG5lhhUBjoQ79gfvQvIC-63" value="&lt;b style=&quot;border-color: var(--border-color);&quot;&gt;&lt;font style=&quot;border-color: var(--border-color);&quot; color=&quot;#336600&quot;&gt;vertex&lt;/font&gt;&lt;/b&gt;&amp;nbsp;-&amp;gt;&lt;br&gt;LorentzVector * &lt;br&gt;DiracMatrix * &lt;br&gt;BiSpinor &lt;br&gt;=&amp;nbsp;&lt;b style=&quot;border-color: var(--border-color);&quot;&gt;&lt;font style=&quot;border-color: var(--border-color);&quot; color=&quot;#cc00cc&quot;&gt;BiSpinor&lt;/font&gt;&lt;/b&gt;" style="rounded=1;whiteSpace=wrap;html=1;strokeWidth=2;fillColor=#f5f5f5;gradientColor=#b3b3b3;strokeColor=#666666;" parent="1" vertex="1">
+          <mxGeometry x="970" y="360" width="120" height="80" as="geometry" />
+        </mxCell>
+        <mxCell id="KG5lhhUBjoQ79gfvQvIC-64" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;strokeWidth=2;" parent="1" source="KG5lhhUBjoQ79gfvQvIC-65" target="KG5lhhUBjoQ79gfvQvIC-66" edge="1">
+          <mxGeometry relative="1" as="geometry" />
+        </mxCell>
+        <mxCell id="KG5lhhUBjoQ79gfvQvIC-65" value="S2(q, q&#39;)&lt;br&gt;q == -q&#39;&lt;br&gt;&lt;b&gt;&lt;font color=&quot;#0000ff&quot;&gt;No Result Particle&lt;/font&gt;&lt;/b&gt;" style="ellipse;whiteSpace=wrap;html=1;strokeWidth=2;fillColor=#f5f5f5;gradientColor=#9AC7BF;strokeColor=#666666;" parent="1" vertex="1">
+          <mxGeometry x="840" y="240" width="120" height="80" as="geometry" />
+        </mxCell>
+        <mxCell id="KG5lhhUBjoQ79gfvQvIC-72" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;strokeWidth=2;" parent="1" source="KG5lhhUBjoQ79gfvQvIC-66" target="KG5lhhUBjoQ79gfvQvIC-70" edge="1">
+          <mxGeometry relative="1" as="geometry">
+            <Array as="points">
+              <mxPoint x="670" y="170" />
+            </Array>
+          </mxGeometry>
+        </mxCell>
+        <mxCell id="KG5lhhUBjoQ79gfvQvIC-66" value="&lt;b style=&quot;border-color: var(--border-color);&quot;&gt;&lt;font style=&quot;border-color: var(--border-color);&quot; color=&quot;#336600&quot;&gt;inner_edge&lt;/font&gt;&lt;/b&gt;&amp;nbsp;-&amp;gt;&lt;br&gt;AdjointBiSpinor * propagator(q) * BiSpinor =&amp;nbsp;&lt;b style=&quot;border-color: var(--border-color);&quot;&gt;&lt;font color=&quot;#cc00cc&quot;&gt;ComplexF64&lt;/font&gt;&lt;/b&gt;" style="rounded=1;whiteSpace=wrap;html=1;strokeWidth=2;fillColor=#f5f5f5;gradientColor=#b3b3b3;strokeColor=#666666;" parent="1" vertex="1">
+          <mxGeometry x="830" y="140" width="140" height="60" as="geometry" />
+        </mxCell>
+        <mxCell id="KG5lhhUBjoQ79gfvQvIC-70" value="&lt;font style=&quot;font-size: 32px;&quot;&gt;Σ&lt;/font&gt;" style="ellipse;whiteSpace=wrap;html=1;strokeWidth=2;fillColor=#ffcd28;strokeColor=#d79b00;gradientColor=#ffa500;" parent="1" vertex="1">
+          <mxGeometry x="610" y="20" width="120" height="80" as="geometry" />
+        </mxCell>
+        <mxCell id="KG5lhhUBjoQ79gfvQvIC-73" value="&lt;b&gt;&lt;font style=&quot;font-size: 22px;&quot;&gt;ValueAcc&lt;/font&gt;&lt;/b&gt;" style="text;html=1;strokeColor=none;fillColor=none;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;" parent="1" vertex="1">
+          <mxGeometry x="10" y="155" width="120" height="30" as="geometry" />
+        </mxCell>
+        <mxCell id="KG5lhhUBjoQ79gfvQvIC-74" value="&lt;b&gt;&lt;font style=&quot;font-size: 22px;&quot;&gt;ValueAcc&lt;/font&gt;&lt;/b&gt;" style="text;html=1;strokeColor=none;fillColor=none;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;" parent="1" vertex="1">
+          <mxGeometry x="10" y="385" width="120" height="30" as="geometry" />
+        </mxCell>
+        <mxCell id="KG5lhhUBjoQ79gfvQvIC-75" value="&lt;b&gt;&lt;font style=&quot;font-size: 22px;&quot;&gt;ValueAcc&lt;/font&gt;&lt;/b&gt;" style="text;html=1;strokeColor=none;fillColor=none;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;" parent="1" vertex="1">
+          <mxGeometry x="10" y="615" width="120" height="30" as="geometry" />
+        </mxCell>
+        <mxCell id="KG5lhhUBjoQ79gfvQvIC-76" value="&lt;b&gt;&lt;font style=&quot;font-size: 22px;&quot;&gt;Particle Propagation&lt;/font&gt;&lt;/b&gt;" style="text;html=1;strokeColor=none;fillColor=none;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;" parent="1" vertex="1">
+          <mxGeometry x="10" y="725" width="120" height="30" as="geometry" />
+        </mxCell>
+        <mxCell id="KG5lhhUBjoQ79gfvQvIC-77" value="&lt;b&gt;&lt;font style=&quot;font-size: 22px;&quot;&gt;Particle Propagation&lt;/font&gt;&lt;/b&gt;" style="text;html=1;strokeColor=none;fillColor=none;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;" parent="1" vertex="1">
+          <mxGeometry x="10" y="505" width="120" height="30" as="geometry" />
+        </mxCell>
+        <mxCell id="KG5lhhUBjoQ79gfvQvIC-78" value="&lt;b&gt;&lt;font style=&quot;font-size: 22px;&quot;&gt;Particle Propagation&lt;/font&gt;&lt;/b&gt;" style="text;html=1;strokeColor=none;fillColor=none;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;" parent="1" vertex="1">
+          <mxGeometry x="10" y="265" width="120" height="30" as="geometry" />
+        </mxCell>
+        <mxCell id="KG5lhhUBjoQ79gfvQvIC-79" value="" style="endArrow=none;dashed=1;html=1;dashPattern=1 3;strokeWidth=2;rounded=0;" parent="1" edge="1">
+          <mxGeometry width="50" height="50" relative="1" as="geometry">
+            <mxPoint y="220" as="sourcePoint" />
+            <mxPoint x="1160" y="220" as="targetPoint" />
+          </mxGeometry>
+        </mxCell>
+        <mxCell id="KG5lhhUBjoQ79gfvQvIC-80" value="" style="endArrow=none;dashed=1;html=1;dashPattern=1 3;strokeWidth=2;rounded=0;" parent="1" edge="1">
+          <mxGeometry width="50" height="50" relative="1" as="geometry">
+            <mxPoint y="340" as="sourcePoint" />
+            <mxPoint x="1160" y="340" as="targetPoint" />
+          </mxGeometry>
+        </mxCell>
+        <mxCell id="KG5lhhUBjoQ79gfvQvIC-81" value="" style="endArrow=none;dashed=1;html=1;dashPattern=1 3;strokeWidth=2;rounded=0;" parent="1" edge="1">
+          <mxGeometry width="50" height="50" relative="1" as="geometry">
+            <mxPoint y="460" as="sourcePoint" />
+            <mxPoint x="1160" y="460" as="targetPoint" />
+          </mxGeometry>
+        </mxCell>
+        <mxCell id="KG5lhhUBjoQ79gfvQvIC-82" value="" style="endArrow=none;dashed=1;html=1;dashPattern=1 3;strokeWidth=2;rounded=0;" parent="1" edge="1">
+          <mxGeometry width="50" height="50" relative="1" as="geometry">
+            <mxPoint y="120" as="sourcePoint" />
+            <mxPoint x="1160" y="120" as="targetPoint" />
+          </mxGeometry>
+        </mxCell>
+        <mxCell id="KG5lhhUBjoQ79gfvQvIC-83" value="" style="endArrow=none;dashed=1;html=1;dashPattern=1 3;strokeWidth=2;rounded=0;" parent="1" edge="1">
+          <mxGeometry width="50" height="50" relative="1" as="geometry">
+            <mxPoint y="580" as="sourcePoint" />
+            <mxPoint x="1160" y="580" as="targetPoint" />
+          </mxGeometry>
+        </mxCell>
+        <mxCell id="KG5lhhUBjoQ79gfvQvIC-84" value="" style="endArrow=none;dashed=1;html=1;dashPattern=1 3;strokeWidth=2;rounded=0;" parent="1" edge="1">
+          <mxGeometry width="50" height="50" relative="1" as="geometry">
+            <mxPoint y="680" as="sourcePoint" />
+            <mxPoint x="1160" y="680" as="targetPoint" />
+          </mxGeometry>
+        </mxCell>
+        <mxCell id="KG5lhhUBjoQ79gfvQvIC-85" value="" style="endArrow=none;dashed=1;html=1;dashPattern=1 3;strokeWidth=2;rounded=0;" parent="1" edge="1">
+          <mxGeometry width="50" height="50" relative="1" as="geometry">
+            <mxPoint y="800" as="sourcePoint" />
+            <mxPoint x="1160" y="800" as="targetPoint" />
+          </mxGeometry>
+        </mxCell>
+      </root>
+    </mxGraphModel>
+  </diagram>
+</mxfile>
diff --git a/docs/src/QED-DAG.drawio b/docs/src/QED-DAG.drawio
new file mode 100644
index 0000000..5da19bb
--- /dev/null
+++ b/docs/src/QED-DAG.drawio
@@ -0,0 +1,259 @@
+<mxfile host="Electron" modified="2023-11-27T18:44:21.892Z" agent="Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) draw.io/21.6.1 Chrome/114.0.5735.289 Electron/25.9.4 Safari/537.36" etag="jZTT8pDahJdWGF9zNYdY" version="21.6.1" type="device">
+  <diagram name="Page-1" id="pzz-rsbNjEFeZeQIA-38">
+    <mxGraphModel dx="2574" dy="1237" grid="1" gridSize="10" guides="1" tooltips="1" connect="1" arrows="1" fold="1" page="1" pageScale="1" pageWidth="500" pageHeight="900" math="0" shadow="0">
+      <root>
+        <mxCell id="0" />
+        <mxCell id="1" parent="0" />
+        <mxCell id="KG5lhhUBjoQ79gfvQvIC-19" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;strokeWidth=2;" parent="1" source="KG5lhhUBjoQ79gfvQvIC-6" target="KG5lhhUBjoQ79gfvQvIC-18" edge="1">
+          <mxGeometry relative="1" as="geometry" />
+        </mxCell>
+        <mxCell id="KG5lhhUBjoQ79gfvQvIC-6" value="&lt;b style=&quot;border-color: var(--border-color);&quot;&gt;&lt;font style=&quot;border-color: var(--border-color);&quot; color=&quot;#336600&quot;&gt;base_state&lt;/font&gt;&lt;/b&gt;&amp;nbsp;-&amp;gt;&lt;br&gt;&lt;b style=&quot;border-color: var(--border-color);&quot;&gt;&lt;font color=&quot;#cc00cc&quot;&gt;LorentzVector&lt;/font&gt;&lt;/b&gt;" style="rounded=1;whiteSpace=wrap;html=1;strokeWidth=2;fillColor=#f5f5f5;gradientColor=#b3b3b3;strokeColor=#666666;" parent="1" vertex="1">
+          <mxGeometry x="190" y="600" width="120" height="60" as="geometry" />
+        </mxCell>
+        <mxCell id="KG5lhhUBjoQ79gfvQvIC-20" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;strokeWidth=2;" parent="1" source="KG5lhhUBjoQ79gfvQvIC-7" target="KG5lhhUBjoQ79gfvQvIC-18" edge="1">
+          <mxGeometry relative="1" as="geometry" />
+        </mxCell>
+        <mxCell id="KG5lhhUBjoQ79gfvQvIC-7" value="&lt;b style=&quot;border-color: var(--border-color);&quot;&gt;&lt;font style=&quot;border-color: var(--border-color);&quot; color=&quot;#336600&quot;&gt;base_state&lt;/font&gt;&lt;/b&gt;&amp;nbsp;-&amp;gt;&lt;br&gt;&lt;b style=&quot;border-color: var(--border-color);&quot;&gt;&lt;font style=&quot;border-color: var(--border-color);&quot; color=&quot;#cc00cc&quot;&gt;BiSpinor&lt;/font&gt;&lt;/b&gt;" style="rounded=1;whiteSpace=wrap;html=1;strokeWidth=2;fillColor=#f5f5f5;gradientColor=#b3b3b3;strokeColor=#666666;" parent="1" vertex="1">
+          <mxGeometry x="310" y="600" width="120" height="60" as="geometry" />
+        </mxCell>
+        <mxCell id="KG5lhhUBjoQ79gfvQvIC-28" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;strokeWidth=2;" parent="1" source="KG5lhhUBjoQ79gfvQvIC-8" target="KG5lhhUBjoQ79gfvQvIC-26" edge="1">
+          <mxGeometry relative="1" as="geometry" />
+        </mxCell>
+        <mxCell id="KG5lhhUBjoQ79gfvQvIC-8" value="&lt;b style=&quot;border-color: var(--border-color);&quot;&gt;&lt;font style=&quot;border-color: var(--border-color);&quot; color=&quot;#336600&quot;&gt;base_state&lt;/font&gt;&lt;/b&gt;&amp;nbsp;-&amp;gt;&lt;br&gt;&lt;b style=&quot;border-color: var(--border-color);&quot;&gt;&lt;font style=&quot;border-color: var(--border-color);&quot; color=&quot;#cc00cc&quot;&gt;AdjointBiSpinor&lt;/font&gt;&lt;/b&gt;" style="rounded=1;whiteSpace=wrap;html=1;strokeWidth=2;fillColor=#f5f5f5;gradientColor=#b3b3b3;strokeColor=#666666;" parent="1" vertex="1">
+          <mxGeometry x="550" y="600" width="120" height="60" as="geometry" />
+        </mxCell>
+        <mxCell id="KG5lhhUBjoQ79gfvQvIC-29" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;strokeWidth=2;" parent="1" source="KG5lhhUBjoQ79gfvQvIC-9" target="KG5lhhUBjoQ79gfvQvIC-26" edge="1">
+          <mxGeometry relative="1" as="geometry" />
+        </mxCell>
+        <mxCell id="KG5lhhUBjoQ79gfvQvIC-9" value="&lt;b style=&quot;border-color: var(--border-color);&quot;&gt;&lt;font style=&quot;border-color: var(--border-color);&quot; color=&quot;#336600&quot;&gt;base_state&lt;/font&gt;&lt;/b&gt;&amp;nbsp;-&amp;gt;&lt;br&gt;&lt;b style=&quot;border-color: var(--border-color);&quot;&gt;&lt;font style=&quot;border-color: var(--border-color);&quot; color=&quot;#cc00cc&quot;&gt;LorentzVector&lt;/font&gt;&lt;/b&gt;" style="rounded=1;whiteSpace=wrap;html=1;strokeWidth=2;fillColor=#f5f5f5;gradientColor=#b3b3b3;strokeColor=#666666;" parent="1" vertex="1">
+          <mxGeometry x="430" y="600" width="120" height="60" as="geometry" />
+        </mxCell>
+        <mxCell id="KG5lhhUBjoQ79gfvQvIC-21" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;strokeWidth=2;" parent="1" source="KG5lhhUBjoQ79gfvQvIC-14" target="KG5lhhUBjoQ79gfvQvIC-6" edge="1">
+          <mxGeometry relative="1" as="geometry" />
+        </mxCell>
+        <mxCell id="KG5lhhUBjoQ79gfvQvIC-14" value="U(γ&lt;sub style=&quot;border-color: var(--border-color);&quot;&gt;1&lt;/sub&gt;)&lt;br style=&quot;border-color: var(--border-color);&quot;&gt;&lt;font color=&quot;#0000ff&quot;&gt;&lt;b&gt;IncomingPhoton&lt;/b&gt;&lt;/font&gt;&lt;br&gt;Outer Edge" style="ellipse;whiteSpace=wrap;html=1;strokeWidth=2;fillColor=#f5f5f5;gradientColor=#9AC7BF;strokeColor=#666666;" parent="1" vertex="1">
+          <mxGeometry x="190" y="700" width="120" height="80" as="geometry" />
+        </mxCell>
+        <mxCell id="KG5lhhUBjoQ79gfvQvIC-22" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;strokeWidth=2;" parent="1" source="KG5lhhUBjoQ79gfvQvIC-15" target="KG5lhhUBjoQ79gfvQvIC-7" edge="1">
+          <mxGeometry relative="1" as="geometry" />
+        </mxCell>
+        <mxCell id="KG5lhhUBjoQ79gfvQvIC-15" value="U(p&lt;sub style=&quot;border-color: var(--border-color);&quot;&gt;1&lt;/sub&gt;)&lt;br style=&quot;border-color: var(--border-color);&quot;&gt;&lt;b&gt;&lt;font color=&quot;#0000ff&quot;&gt;IncomingFermion&lt;br&gt;&lt;/font&gt;&lt;/b&gt;Outer Edge" style="ellipse;whiteSpace=wrap;html=1;strokeWidth=2;fillColor=#f5f5f5;gradientColor=#9AC7BF;strokeColor=#666666;" parent="1" vertex="1">
+          <mxGeometry x="310" y="700" width="120" height="80" as="geometry" />
+        </mxCell>
+        <mxCell id="KG5lhhUBjoQ79gfvQvIC-23" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;strokeWidth=2;" parent="1" source="KG5lhhUBjoQ79gfvQvIC-16" target="KG5lhhUBjoQ79gfvQvIC-9" edge="1">
+          <mxGeometry relative="1" as="geometry" />
+        </mxCell>
+        <mxCell id="KG5lhhUBjoQ79gfvQvIC-16" value="U(γ&lt;sub style=&quot;border-color: var(--border-color);&quot;&gt;2&lt;/sub&gt;)&lt;br style=&quot;border-color: var(--border-color);&quot;&gt;&lt;b&gt;&lt;font color=&quot;#0000ff&quot;&gt;OutgoingPhoton&lt;br&gt;&lt;/font&gt;&lt;/b&gt;Outer Edge" style="ellipse;whiteSpace=wrap;html=1;strokeWidth=2;fillColor=#f5f5f5;gradientColor=#9AC7BF;strokeColor=#666666;" parent="1" vertex="1">
+          <mxGeometry x="430" y="700" width="120" height="80" as="geometry" />
+        </mxCell>
+        <mxCell id="KG5lhhUBjoQ79gfvQvIC-24" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;strokeWidth=2;" parent="1" source="KG5lhhUBjoQ79gfvQvIC-17" target="KG5lhhUBjoQ79gfvQvIC-8" edge="1">
+          <mxGeometry relative="1" as="geometry" />
+        </mxCell>
+        <mxCell id="KG5lhhUBjoQ79gfvQvIC-17" value="U(p&lt;sub style=&quot;border-color: var(--border-color);&quot;&gt;2&lt;/sub&gt;)&lt;br style=&quot;border-color: var(--border-color);&quot;&gt;&lt;b&gt;&lt;font color=&quot;#0000ff&quot;&gt;OutgoingFermion&lt;br&gt;&lt;/font&gt;&lt;/b&gt;Outer Edge" style="ellipse;whiteSpace=wrap;html=1;strokeWidth=2;fillColor=#f5f5f5;gradientColor=#9AC7BF;strokeColor=#666666;" parent="1" vertex="1">
+          <mxGeometry x="550" y="700" width="120" height="80" as="geometry" />
+        </mxCell>
+        <mxCell id="KG5lhhUBjoQ79gfvQvIC-30" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;strokeWidth=2;" parent="1" source="KG5lhhUBjoQ79gfvQvIC-18" target="KG5lhhUBjoQ79gfvQvIC-25" edge="1">
+          <mxGeometry relative="1" as="geometry" />
+        </mxCell>
+        <mxCell id="KG5lhhUBjoQ79gfvQvIC-18" value="V(γ&lt;sub&gt;1&lt;/sub&gt;, p&lt;sub&gt;1&lt;/sub&gt;)&lt;br&gt;Result Particle:&lt;br&gt;q: &lt;font color=&quot;#0000ff&quot;&gt;&lt;b&gt;OutgoingFermion&lt;/b&gt;&lt;/font&gt;" style="ellipse;whiteSpace=wrap;html=1;strokeWidth=2;fillColor=#f5f5f5;gradientColor=#9AC7BF;strokeColor=#666666;" parent="1" vertex="1">
+          <mxGeometry x="240" y="480" width="140" height="80" as="geometry" />
+        </mxCell>
+        <mxCell id="KG5lhhUBjoQ79gfvQvIC-36" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;strokeWidth=2;" parent="1" source="KG5lhhUBjoQ79gfvQvIC-25" target="KG5lhhUBjoQ79gfvQvIC-35" edge="1">
+          <mxGeometry relative="1" as="geometry" />
+        </mxCell>
+        <mxCell id="KG5lhhUBjoQ79gfvQvIC-25" value="&lt;b&gt;&lt;font color=&quot;#336600&quot;&gt;vertex&lt;/font&gt;&lt;/b&gt; -&amp;gt;&lt;br&gt;LorentzVector * GammaMatrix * BiSpinor = &lt;br&gt;&lt;b style=&quot;border-color: var(--border-color);&quot;&gt;&lt;font color=&quot;#cc00cc&quot; style=&quot;border-color: var(--border-color);&quot;&gt;BiSpinor&lt;/font&gt;&lt;/b&gt;" style="rounded=1;whiteSpace=wrap;html=1;strokeWidth=2;fillColor=#f5f5f5;gradientColor=#b3b3b3;strokeColor=#666666;" parent="1" vertex="1">
+          <mxGeometry x="250" y="360" width="120" height="80" as="geometry" />
+        </mxCell>
+        <mxCell id="KG5lhhUBjoQ79gfvQvIC-32" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;strokeWidth=2;" parent="1" source="KG5lhhUBjoQ79gfvQvIC-26" target="KG5lhhUBjoQ79gfvQvIC-27" edge="1">
+          <mxGeometry relative="1" as="geometry" />
+        </mxCell>
+        <mxCell id="KG5lhhUBjoQ79gfvQvIC-26" value="V(γ&lt;sub&gt;2&lt;/sub&gt;, p&lt;sub&gt;2&lt;/sub&gt;)&lt;br&gt;Result Particle:&lt;br&gt;q&#39;: &lt;b&gt;&lt;font color=&quot;#0000ff&quot;&gt;IncomingFermion&lt;/font&gt;&lt;/b&gt;" style="ellipse;whiteSpace=wrap;html=1;strokeWidth=2;fillColor=#f5f5f5;gradientColor=#9AC7BF;strokeColor=#666666;" parent="1" vertex="1">
+          <mxGeometry x="480" y="480" width="140" height="80" as="geometry" />
+        </mxCell>
+        <mxCell id="KG5lhhUBjoQ79gfvQvIC-37" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;strokeWidth=2;" parent="1" source="KG5lhhUBjoQ79gfvQvIC-27" target="KG5lhhUBjoQ79gfvQvIC-35" edge="1">
+          <mxGeometry relative="1" as="geometry">
+            <Array as="points">
+              <mxPoint x="550" y="340" />
+              <mxPoint x="420" y="340" />
+            </Array>
+          </mxGeometry>
+        </mxCell>
+        <mxCell id="KG5lhhUBjoQ79gfvQvIC-27" value="&lt;b style=&quot;border-color: var(--border-color);&quot;&gt;&lt;font style=&quot;border-color: var(--border-color);&quot; color=&quot;#336600&quot;&gt;vertex&lt;/font&gt;&lt;/b&gt;&amp;nbsp;-&amp;gt;&lt;br&gt;AdjointBiSpinor * LorentzVector * GammaMatrix =&amp;nbsp;&lt;b style=&quot;border-color: var(--border-color);&quot;&gt;&lt;font color=&quot;#cc00cc&quot; style=&quot;border-color: var(--border-color);&quot;&gt;AdjointBiSpinor&lt;/font&gt;&lt;/b&gt;" style="rounded=1;whiteSpace=wrap;html=1;strokeWidth=2;fillColor=#f5f5f5;gradientColor=#b3b3b3;strokeColor=#666666;" parent="1" vertex="1">
+          <mxGeometry x="490" y="360" width="120" height="80" as="geometry" />
+        </mxCell>
+        <mxCell id="KG5lhhUBjoQ79gfvQvIC-39" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;strokeWidth=2;" parent="1" source="KG5lhhUBjoQ79gfvQvIC-35" target="KG5lhhUBjoQ79gfvQvIC-38" edge="1">
+          <mxGeometry relative="1" as="geometry" />
+        </mxCell>
+        <mxCell id="KG5lhhUBjoQ79gfvQvIC-35" value="S2(q, q&#39;)&lt;br&gt;q == -q&#39;&lt;br&gt;&lt;b&gt;&lt;font color=&quot;#0000ff&quot;&gt;No Result Particle&lt;/font&gt;&lt;/b&gt;" style="ellipse;whiteSpace=wrap;html=1;strokeWidth=2;fillColor=#f5f5f5;gradientColor=#9AC7BF;strokeColor=#666666;" parent="1" vertex="1">
+          <mxGeometry x="360" y="240" width="120" height="80" as="geometry" />
+        </mxCell>
+        <mxCell id="KG5lhhUBjoQ79gfvQvIC-71" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;strokeWidth=2;" parent="1" source="KG5lhhUBjoQ79gfvQvIC-38" target="KG5lhhUBjoQ79gfvQvIC-70" edge="1">
+          <mxGeometry relative="1" as="geometry">
+            <Array as="points">
+              <mxPoint x="670" y="170" />
+            </Array>
+          </mxGeometry>
+        </mxCell>
+        <mxCell id="KG5lhhUBjoQ79gfvQvIC-38" value="&lt;b style=&quot;&quot;&gt;&lt;font color=&quot;#336600&quot;&gt;inner_edge&lt;/font&gt;&lt;/b&gt; -&amp;gt;&lt;br&gt;AdjointBiSpinor * propagator(q) * BiSpinor =&amp;nbsp;&lt;b style=&quot;border-color: var(--border-color);&quot;&gt;&lt;font style=&quot;border-color: var(--border-color);&quot; color=&quot;#cc00cc&quot;&gt;ComplexF64&lt;/font&gt;&lt;/b&gt;" style="rounded=1;whiteSpace=wrap;html=1;strokeWidth=2;fillColor=#f5f5f5;gradientColor=#b3b3b3;strokeColor=#666666;" parent="1" vertex="1">
+          <mxGeometry x="350" y="140" width="140" height="60" as="geometry" />
+        </mxCell>
+        <mxCell id="KG5lhhUBjoQ79gfvQvIC-40" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;strokeWidth=2;" parent="1" source="KG5lhhUBjoQ79gfvQvIC-41" target="KG5lhhUBjoQ79gfvQvIC-57" edge="1">
+          <mxGeometry relative="1" as="geometry" />
+        </mxCell>
+        <mxCell id="KG5lhhUBjoQ79gfvQvIC-41" value="&lt;b style=&quot;border-color: var(--border-color);&quot;&gt;&lt;font style=&quot;border-color: var(--border-color);&quot; color=&quot;#336600&quot;&gt;base_state&lt;/font&gt;&lt;/b&gt;&amp;nbsp;-&amp;gt;&lt;br&gt;&lt;b style=&quot;border-color: var(--border-color);&quot;&gt;&lt;font style=&quot;border-color: var(--border-color);&quot; color=&quot;#cc00cc&quot;&gt;LorentzVector&lt;/font&gt;&lt;/b&gt;" style="rounded=1;whiteSpace=wrap;html=1;strokeWidth=2;fillColor=#f5f5f5;gradientColor=#b3b3b3;strokeColor=#666666;" parent="1" vertex="1">
+          <mxGeometry x="670" y="600" width="120" height="60" as="geometry" />
+        </mxCell>
+        <mxCell id="KG5lhhUBjoQ79gfvQvIC-68" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;strokeWidth=2;" parent="1" source="KG5lhhUBjoQ79gfvQvIC-43" target="KG5lhhUBjoQ79gfvQvIC-61" edge="1">
+          <mxGeometry relative="1" as="geometry" />
+        </mxCell>
+        <mxCell id="KG5lhhUBjoQ79gfvQvIC-43" value="&lt;b style=&quot;&quot;&gt;&lt;font color=&quot;#336600&quot;&gt;base_state&lt;/font&gt;&lt;/b&gt; -&amp;gt;&lt;br&gt;&lt;b style=&quot;border-color: var(--border-color);&quot;&gt;&lt;font style=&quot;border-color: var(--border-color);&quot; color=&quot;#cc00cc&quot;&gt;BiSpinor&lt;/font&gt;&lt;/b&gt;" style="rounded=1;whiteSpace=wrap;html=1;strokeWidth=2;fillColor=#f5f5f5;gradientColor=#b3b3b3;strokeColor=#666666;" parent="1" vertex="1">
+          <mxGeometry x="1030" y="600" width="120" height="60" as="geometry" />
+        </mxCell>
+        <mxCell id="KG5lhhUBjoQ79gfvQvIC-67" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;strokeWidth=2;" parent="1" source="KG5lhhUBjoQ79gfvQvIC-45" target="KG5lhhUBjoQ79gfvQvIC-57" edge="1">
+          <mxGeometry relative="1" as="geometry" />
+        </mxCell>
+        <mxCell id="KG5lhhUBjoQ79gfvQvIC-45" value="&lt;b style=&quot;border-color: var(--border-color);&quot;&gt;&lt;font style=&quot;border-color: var(--border-color);&quot; color=&quot;#336600&quot;&gt;base_state&lt;/font&gt;&lt;/b&gt;&amp;nbsp;-&amp;gt;&lt;br&gt;&lt;b style=&quot;border-color: var(--border-color);&quot;&gt;&lt;font style=&quot;border-color: var(--border-color);&quot; color=&quot;#cc00cc&quot;&gt;AdjointBiSpinor&lt;/font&gt;&lt;/b&gt;" style="rounded=1;whiteSpace=wrap;html=1;strokeWidth=2;fillColor=#f5f5f5;gradientColor=#b3b3b3;strokeColor=#666666;" parent="1" vertex="1">
+          <mxGeometry x="790" y="600" width="120" height="60" as="geometry" />
+        </mxCell>
+        <mxCell id="KG5lhhUBjoQ79gfvQvIC-46" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;strokeWidth=2;" parent="1" source="KG5lhhUBjoQ79gfvQvIC-47" target="KG5lhhUBjoQ79gfvQvIC-61" edge="1">
+          <mxGeometry relative="1" as="geometry" />
+        </mxCell>
+        <mxCell id="KG5lhhUBjoQ79gfvQvIC-47" value="&lt;b style=&quot;border-color: var(--border-color);&quot;&gt;&lt;font style=&quot;border-color: var(--border-color);&quot; color=&quot;#336600&quot;&gt;base_state&lt;/font&gt;&lt;/b&gt;&amp;nbsp;-&amp;gt;&lt;br&gt;&lt;b style=&quot;border-color: var(--border-color);&quot;&gt;&lt;font style=&quot;border-color: var(--border-color);&quot; color=&quot;#cc00cc&quot;&gt;LorentzVector&lt;/font&gt;&lt;/b&gt;" style="rounded=1;whiteSpace=wrap;html=1;strokeWidth=2;fillColor=#f5f5f5;gradientColor=#b3b3b3;strokeColor=#666666;" parent="1" vertex="1">
+          <mxGeometry x="910" y="600" width="120" height="60" as="geometry" />
+        </mxCell>
+        <mxCell id="KG5lhhUBjoQ79gfvQvIC-48" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;strokeWidth=2;" parent="1" source="KG5lhhUBjoQ79gfvQvIC-49" target="KG5lhhUBjoQ79gfvQvIC-41" edge="1">
+          <mxGeometry relative="1" as="geometry" />
+        </mxCell>
+        <mxCell id="KG5lhhUBjoQ79gfvQvIC-49" value="U(γ&lt;sub style=&quot;border-color: var(--border-color);&quot;&gt;1&lt;/sub&gt;)&lt;br style=&quot;border-color: var(--border-color);&quot;&gt;&lt;font style=&quot;border-color: var(--border-color);&quot; color=&quot;#0000ff&quot;&gt;&lt;b style=&quot;border-color: var(--border-color);&quot;&gt;IncomingPhoton&lt;/b&gt;&lt;/font&gt;&lt;br style=&quot;border-color: var(--border-color);&quot;&gt;Outer Edge" style="ellipse;whiteSpace=wrap;html=1;strokeWidth=2;fillColor=#f5f5f5;gradientColor=#9AC7BF;strokeColor=#666666;" parent="1" vertex="1">
+          <mxGeometry x="670" y="700" width="120" height="80" as="geometry" />
+        </mxCell>
+        <mxCell id="KG5lhhUBjoQ79gfvQvIC-69" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;strokeWidth=2;" parent="1" source="KG5lhhUBjoQ79gfvQvIC-51" target="KG5lhhUBjoQ79gfvQvIC-43" edge="1">
+          <mxGeometry relative="1" as="geometry" />
+        </mxCell>
+        <mxCell id="KG5lhhUBjoQ79gfvQvIC-51" value="U(p&lt;sub style=&quot;border-color: var(--border-color);&quot;&gt;1&lt;/sub&gt;)&lt;br style=&quot;border-color: var(--border-color);&quot;&gt;&lt;b style=&quot;border-color: var(--border-color);&quot;&gt;&lt;font style=&quot;border-color: var(--border-color);&quot; color=&quot;#0000ff&quot;&gt;IncomingFermion&lt;br style=&quot;border-color: var(--border-color);&quot;&gt;&lt;/font&gt;&lt;/b&gt;Outer Edge" style="ellipse;whiteSpace=wrap;html=1;strokeWidth=2;fillColor=#f5f5f5;gradientColor=#9AC7BF;strokeColor=#666666;" parent="1" vertex="1">
+          <mxGeometry x="1030" y="700" width="120" height="80" as="geometry" />
+        </mxCell>
+        <mxCell id="KG5lhhUBjoQ79gfvQvIC-52" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;strokeWidth=2;" parent="1" source="KG5lhhUBjoQ79gfvQvIC-53" target="KG5lhhUBjoQ79gfvQvIC-47" edge="1">
+          <mxGeometry relative="1" as="geometry" />
+        </mxCell>
+        <mxCell id="KG5lhhUBjoQ79gfvQvIC-53" value="U(γ&lt;sub style=&quot;border-color: var(--border-color);&quot;&gt;2&lt;/sub&gt;)&lt;br style=&quot;border-color: var(--border-color);&quot;&gt;&lt;b style=&quot;border-color: var(--border-color);&quot;&gt;&lt;font style=&quot;border-color: var(--border-color);&quot; color=&quot;#0000ff&quot;&gt;OutgoingPhoton&lt;br style=&quot;border-color: var(--border-color);&quot;&gt;&lt;/font&gt;&lt;/b&gt;Outer Edge" style="ellipse;whiteSpace=wrap;html=1;strokeWidth=2;fillColor=#f5f5f5;gradientColor=#9AC7BF;strokeColor=#666666;" parent="1" vertex="1">
+          <mxGeometry x="910" y="700" width="120" height="80" as="geometry" />
+        </mxCell>
+        <mxCell id="KG5lhhUBjoQ79gfvQvIC-54" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;strokeWidth=2;" parent="1" source="KG5lhhUBjoQ79gfvQvIC-55" target="KG5lhhUBjoQ79gfvQvIC-45" edge="1">
+          <mxGeometry relative="1" as="geometry" />
+        </mxCell>
+        <mxCell id="KG5lhhUBjoQ79gfvQvIC-55" value="U(p&lt;sub style=&quot;border-color: var(--border-color);&quot;&gt;2&lt;/sub&gt;)&lt;br style=&quot;border-color: var(--border-color);&quot;&gt;&lt;font color=&quot;#0000ff&quot;&gt;&lt;b&gt;OutgoingFermion&lt;br&gt;&lt;/b&gt;&lt;/font&gt;Outer Edge" style="ellipse;whiteSpace=wrap;html=1;strokeWidth=2;fillColor=#f5f5f5;gradientColor=#9AC7BF;strokeColor=#666666;" parent="1" vertex="1">
+          <mxGeometry x="790" y="700" width="120" height="80" as="geometry" />
+        </mxCell>
+        <mxCell id="KG5lhhUBjoQ79gfvQvIC-56" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;strokeWidth=2;" parent="1" source="KG5lhhUBjoQ79gfvQvIC-57" target="KG5lhhUBjoQ79gfvQvIC-59" edge="1">
+          <mxGeometry relative="1" as="geometry" />
+        </mxCell>
+        <mxCell id="KG5lhhUBjoQ79gfvQvIC-57" value="V(γ&lt;sub&gt;1&lt;/sub&gt;, p&lt;span style=&quot;font-size: 10px;&quot;&gt;&lt;sub&gt;2&lt;/sub&gt;&lt;/span&gt;)&lt;br&gt;Result Particle:&lt;br&gt;q: &lt;b&gt;&lt;font color=&quot;#0000ff&quot;&gt;IncomingFermion&lt;/font&gt;&lt;/b&gt;" style="ellipse;whiteSpace=wrap;html=1;strokeWidth=2;fillColor=#f5f5f5;gradientColor=#9AC7BF;strokeColor=#666666;" parent="1" vertex="1">
+          <mxGeometry x="720" y="480" width="140" height="80" as="geometry" />
+        </mxCell>
+        <mxCell id="KG5lhhUBjoQ79gfvQvIC-58" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;strokeWidth=2;" parent="1" source="KG5lhhUBjoQ79gfvQvIC-59" target="KG5lhhUBjoQ79gfvQvIC-65" edge="1">
+          <mxGeometry relative="1" as="geometry" />
+        </mxCell>
+        <mxCell id="KG5lhhUBjoQ79gfvQvIC-59" value="&lt;b style=&quot;border-color: var(--border-color);&quot;&gt;&lt;font style=&quot;border-color: var(--border-color);&quot; color=&quot;#336600&quot;&gt;vertex&lt;/font&gt;&lt;/b&gt;&amp;nbsp;-&amp;gt;&lt;br&gt;AdjointBiSpinor * LorentzVector * GammaMatrix =&amp;nbsp;&lt;b style=&quot;border-color: var(--border-color);&quot;&gt;&lt;font style=&quot;border-color: var(--border-color);&quot; color=&quot;#cc00cc&quot;&gt;AdjointBiSpinor&lt;/font&gt;&lt;/b&gt;" style="rounded=1;whiteSpace=wrap;html=1;strokeWidth=2;fillColor=#f5f5f5;gradientColor=#b3b3b3;strokeColor=#666666;" parent="1" vertex="1">
+          <mxGeometry x="730" y="360" width="120" height="80" as="geometry" />
+        </mxCell>
+        <mxCell id="KG5lhhUBjoQ79gfvQvIC-60" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;strokeWidth=2;" parent="1" source="KG5lhhUBjoQ79gfvQvIC-61" target="KG5lhhUBjoQ79gfvQvIC-63" edge="1">
+          <mxGeometry relative="1" as="geometry" />
+        </mxCell>
+        <mxCell id="KG5lhhUBjoQ79gfvQvIC-61" value="V(γ&lt;sub&gt;2&lt;/sub&gt;, p&lt;span style=&quot;font-size: 10px;&quot;&gt;&lt;sub&gt;1&lt;/sub&gt;&lt;/span&gt;)&lt;br&gt;Result Particle:&lt;br&gt;q&#39;: &lt;b&gt;&lt;font color=&quot;#0000ff&quot;&gt;OutgoingFermion&lt;/font&gt;&lt;/b&gt;" style="ellipse;whiteSpace=wrap;html=1;strokeWidth=2;fillColor=#f5f5f5;gradientColor=#9AC7BF;strokeColor=#666666;" parent="1" vertex="1">
+          <mxGeometry x="960" y="480" width="140" height="80" as="geometry" />
+        </mxCell>
+        <mxCell id="KG5lhhUBjoQ79gfvQvIC-62" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;strokeWidth=2;" parent="1" source="KG5lhhUBjoQ79gfvQvIC-63" target="KG5lhhUBjoQ79gfvQvIC-65" edge="1">
+          <mxGeometry relative="1" as="geometry">
+            <Array as="points">
+              <mxPoint x="1030" y="340" />
+              <mxPoint x="900" y="340" />
+            </Array>
+          </mxGeometry>
+        </mxCell>
+        <mxCell id="KG5lhhUBjoQ79gfvQvIC-63" value="&lt;b style=&quot;border-color: var(--border-color);&quot;&gt;&lt;font style=&quot;border-color: var(--border-color);&quot; color=&quot;#336600&quot;&gt;vertex&lt;/font&gt;&lt;/b&gt;&amp;nbsp;-&amp;gt;&lt;br&gt;LorentzVector * GammaMatrix * BiSpinor = &lt;br&gt;&lt;b style=&quot;border-color: var(--border-color);&quot;&gt;&lt;font style=&quot;border-color: var(--border-color);&quot; color=&quot;#cc00cc&quot;&gt;BiSpinor&lt;/font&gt;&lt;/b&gt;" style="rounded=1;whiteSpace=wrap;html=1;strokeWidth=2;fillColor=#f5f5f5;gradientColor=#b3b3b3;strokeColor=#666666;" parent="1" vertex="1">
+          <mxGeometry x="970" y="360" width="120" height="80" as="geometry" />
+        </mxCell>
+        <mxCell id="KG5lhhUBjoQ79gfvQvIC-64" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;strokeWidth=2;" parent="1" source="KG5lhhUBjoQ79gfvQvIC-65" target="KG5lhhUBjoQ79gfvQvIC-66" edge="1">
+          <mxGeometry relative="1" as="geometry" />
+        </mxCell>
+        <mxCell id="KG5lhhUBjoQ79gfvQvIC-65" value="S2(q, q&#39;)&lt;br&gt;q == -q&#39;&lt;br&gt;&lt;b&gt;&lt;font color=&quot;#0000ff&quot;&gt;No Result Particle&lt;/font&gt;&lt;/b&gt;" style="ellipse;whiteSpace=wrap;html=1;strokeWidth=2;fillColor=#f5f5f5;gradientColor=#9AC7BF;strokeColor=#666666;" parent="1" vertex="1">
+          <mxGeometry x="840" y="240" width="120" height="80" as="geometry" />
+        </mxCell>
+        <mxCell id="KG5lhhUBjoQ79gfvQvIC-72" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;strokeWidth=2;" parent="1" source="KG5lhhUBjoQ79gfvQvIC-66" target="KG5lhhUBjoQ79gfvQvIC-70" edge="1">
+          <mxGeometry relative="1" as="geometry">
+            <Array as="points">
+              <mxPoint x="670" y="170" />
+            </Array>
+          </mxGeometry>
+        </mxCell>
+        <mxCell id="KG5lhhUBjoQ79gfvQvIC-66" value="&lt;b style=&quot;border-color: var(--border-color);&quot;&gt;&lt;font style=&quot;border-color: var(--border-color);&quot; color=&quot;#336600&quot;&gt;inner_edge&lt;/font&gt;&lt;/b&gt;&amp;nbsp;-&amp;gt;&lt;br&gt;AdjointBiSpinor * propagator(q) * BiSpinor =&amp;nbsp;&lt;b style=&quot;border-color: var(--border-color);&quot;&gt;&lt;font color=&quot;#cc00cc&quot;&gt;ComplexF64&lt;/font&gt;&lt;/b&gt;" style="rounded=1;whiteSpace=wrap;html=1;strokeWidth=2;fillColor=#f5f5f5;gradientColor=#b3b3b3;strokeColor=#666666;" parent="1" vertex="1">
+          <mxGeometry x="830" y="140" width="140" height="60" as="geometry" />
+        </mxCell>
+        <mxCell id="KG5lhhUBjoQ79gfvQvIC-70" value="&lt;font style=&quot;font-size: 32px;&quot;&gt;Σ&lt;/font&gt;" style="ellipse;whiteSpace=wrap;html=1;strokeWidth=2;fillColor=#ffcd28;strokeColor=#d79b00;gradientColor=#ffa500;" parent="1" vertex="1">
+          <mxGeometry x="610" y="20" width="120" height="80" as="geometry" />
+        </mxCell>
+        <mxCell id="KG5lhhUBjoQ79gfvQvIC-73" value="&lt;b&gt;&lt;font style=&quot;font-size: 22px;&quot;&gt;ValueAcc&lt;/font&gt;&lt;/b&gt;" style="text;html=1;strokeColor=none;fillColor=none;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;" parent="1" vertex="1">
+          <mxGeometry x="10" y="155" width="120" height="30" as="geometry" />
+        </mxCell>
+        <mxCell id="KG5lhhUBjoQ79gfvQvIC-74" value="&lt;b&gt;&lt;font style=&quot;font-size: 22px;&quot;&gt;ValueAcc&lt;/font&gt;&lt;/b&gt;" style="text;html=1;strokeColor=none;fillColor=none;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;" parent="1" vertex="1">
+          <mxGeometry x="10" y="385" width="120" height="30" as="geometry" />
+        </mxCell>
+        <mxCell id="KG5lhhUBjoQ79gfvQvIC-75" value="&lt;b&gt;&lt;font style=&quot;font-size: 22px;&quot;&gt;ValueAcc&lt;/font&gt;&lt;/b&gt;" style="text;html=1;strokeColor=none;fillColor=none;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;" parent="1" vertex="1">
+          <mxGeometry x="10" y="615" width="120" height="30" as="geometry" />
+        </mxCell>
+        <mxCell id="KG5lhhUBjoQ79gfvQvIC-76" value="&lt;b&gt;&lt;font style=&quot;font-size: 22px;&quot;&gt;Particle Propagation&lt;/font&gt;&lt;/b&gt;" style="text;html=1;strokeColor=none;fillColor=none;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;" parent="1" vertex="1">
+          <mxGeometry x="10" y="725" width="120" height="30" as="geometry" />
+        </mxCell>
+        <mxCell id="KG5lhhUBjoQ79gfvQvIC-77" value="&lt;b&gt;&lt;font style=&quot;font-size: 22px;&quot;&gt;Particle Propagation&lt;/font&gt;&lt;/b&gt;" style="text;html=1;strokeColor=none;fillColor=none;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;" parent="1" vertex="1">
+          <mxGeometry x="10" y="505" width="120" height="30" as="geometry" />
+        </mxCell>
+        <mxCell id="KG5lhhUBjoQ79gfvQvIC-78" value="&lt;b&gt;&lt;font style=&quot;font-size: 22px;&quot;&gt;Particle Propagation&lt;/font&gt;&lt;/b&gt;" style="text;html=1;strokeColor=none;fillColor=none;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;" parent="1" vertex="1">
+          <mxGeometry x="10" y="265" width="120" height="30" as="geometry" />
+        </mxCell>
+        <mxCell id="KG5lhhUBjoQ79gfvQvIC-79" value="" style="endArrow=none;dashed=1;html=1;dashPattern=1 3;strokeWidth=2;rounded=0;" parent="1" edge="1">
+          <mxGeometry width="50" height="50" relative="1" as="geometry">
+            <mxPoint y="220" as="sourcePoint" />
+            <mxPoint x="1160" y="220" as="targetPoint" />
+          </mxGeometry>
+        </mxCell>
+        <mxCell id="KG5lhhUBjoQ79gfvQvIC-80" value="" style="endArrow=none;dashed=1;html=1;dashPattern=1 3;strokeWidth=2;rounded=0;" parent="1" edge="1">
+          <mxGeometry width="50" height="50" relative="1" as="geometry">
+            <mxPoint y="340" as="sourcePoint" />
+            <mxPoint x="1160" y="340" as="targetPoint" />
+          </mxGeometry>
+        </mxCell>
+        <mxCell id="KG5lhhUBjoQ79gfvQvIC-81" value="" style="endArrow=none;dashed=1;html=1;dashPattern=1 3;strokeWidth=2;rounded=0;" parent="1" edge="1">
+          <mxGeometry width="50" height="50" relative="1" as="geometry">
+            <mxPoint y="460" as="sourcePoint" />
+            <mxPoint x="1160" y="460" as="targetPoint" />
+          </mxGeometry>
+        </mxCell>
+        <mxCell id="KG5lhhUBjoQ79gfvQvIC-82" value="" style="endArrow=none;dashed=1;html=1;dashPattern=1 3;strokeWidth=2;rounded=0;" parent="1" edge="1">
+          <mxGeometry width="50" height="50" relative="1" as="geometry">
+            <mxPoint y="120" as="sourcePoint" />
+            <mxPoint x="1160" y="120" as="targetPoint" />
+          </mxGeometry>
+        </mxCell>
+        <mxCell id="KG5lhhUBjoQ79gfvQvIC-83" value="" style="endArrow=none;dashed=1;html=1;dashPattern=1 3;strokeWidth=2;rounded=0;" parent="1" edge="1">
+          <mxGeometry width="50" height="50" relative="1" as="geometry">
+            <mxPoint y="580" as="sourcePoint" />
+            <mxPoint x="1160" y="580" as="targetPoint" />
+          </mxGeometry>
+        </mxCell>
+        <mxCell id="KG5lhhUBjoQ79gfvQvIC-84" value="" style="endArrow=none;dashed=1;html=1;dashPattern=1 3;strokeWidth=2;rounded=0;" parent="1" edge="1">
+          <mxGeometry width="50" height="50" relative="1" as="geometry">
+            <mxPoint y="680" as="sourcePoint" />
+            <mxPoint x="1160" y="680" as="targetPoint" />
+          </mxGeometry>
+        </mxCell>
+        <mxCell id="KG5lhhUBjoQ79gfvQvIC-85" value="" style="endArrow=none;dashed=1;html=1;dashPattern=1 3;strokeWidth=2;rounded=0;" parent="1" edge="1">
+          <mxGeometry width="50" height="50" relative="1" as="geometry">
+            <mxPoint y="800" as="sourcePoint" />
+            <mxPoint x="1160" y="800" as="targetPoint" />
+          </mxGeometry>
+        </mxCell>
+      </root>
+    </mxGraphModel>
+  </diagram>
+</mxfile>
diff --git a/src/MetagraphOptimization.jl b/src/MetagraphOptimization.jl
index 3df3ac1..bbf31ec 100644
--- a/src/MetagraphOptimization.jl
+++ b/src/MetagraphOptimization.jl
@@ -175,10 +175,10 @@ include("models/abc/print.jl")
 include("models/qed/types.jl")
 include("models/qed/particle.jl")
 include("models/qed/compute.jl")
-#include("models/qed/create.jl")
-#include("models/qed/properties.jl")
-#include("models/qed/parse.jl")
-#include("models/qed/print.jl")
+include("models/qed/create.jl")
+include("models/qed/properties.jl")
+include("models/qed/parse.jl")
+include("models/qed/print.jl")
 
 include("devices/measure.jl")
 include("devices/detect.jl")
diff --git a/src/code_gen/main.jl b/src/code_gen/main.jl
index 944ccb6..ba99523 100644
--- a/src/code_gen/main.jl
+++ b/src/code_gen/main.jl
@@ -61,13 +61,11 @@ function gen_input_assignment_code(
 
     assignInputs = Vector{Expr}()
     for (name, symbols) in inputSymbols
-        type = type_from_name(name)
-        index = parse(Int, name[2:end])
-
+        (type, index) = type_index_from_name(model(processDescription), name)
         p = nothing
 
-        if (index > in_particles(processDescription)[type])
-            index -= in_particles(processDescription)[type]
+        if (index > get(in_particles(processDescription), type, 0))
+            index -= get(in_particles(processDescription), type, 0)
             @assert index <= out_particles(processDescription)[type] "Too few particles of type $type in input particles for this process"
 
             p = "filter(x -> typeof(x) <: $type, out_particles($(processInputSymbol)))[$(index)]"
@@ -79,7 +77,7 @@ function gen_input_assignment_code(
             # TODO: how to get the "default" cpu device?
             device = entry_device(machine)
             evalExpr = eval(gen_access_expr(device, symbol))
-            push!(assignInputs, Meta.parse("$(evalExpr)::ParticleValue{$type} = ParticleValue($p, 1.0)"))
+            push!(assignInputs, Meta.parse("$(evalExpr)::ParticleValue{$type} = ParticleValue($p, one(ComplexF64))"))
         end
     end
 
diff --git a/src/models/abc/compute.jl b/src/models/abc/compute.jl
index 13bcffa..6f1857d 100644
--- a/src/models/abc/compute.jl
+++ b/src/models/abc/compute.jl
@@ -34,7 +34,7 @@ function compute(
     data1::ABCParticleValue{P1},
     data2::ABCParticleValue{P2},
 )::ABCParticleValue where {P1 <: ABCParticle, P2 <: ABCParticle}
-    p3 = ABC_preserve_momentum(data1.p, data2.p)
+    p3 = ABC_conserve_momentum(data1.p, data2.p)
     dataOut = ABCParticleValue{typeof(p3)}(p3, data1.v * ABC_vertex() * data2.v)
     return dataOut
 end
diff --git a/src/models/abc/create.jl b/src/models/abc/create.jl
index 00e1f9c..0d5f844 100644
--- a/src/models/abc/create.jl
+++ b/src/models/abc/create.jl
@@ -62,137 +62,3 @@ function gen_process_input(processDescription::ABCProcessDescription)
 
     return return processInput
 end
-
-####################
-# CODE FROM HERE BORROWED FROM SOURCE: https://codebase.helmholtz.cloud/qedsandbox/QEDphasespaces.jl/
-# use qedphasespaces directly once released
-#
-# quick and dirty implementation of the RAMBO algorithm
-#
-# reference: 
-# * https://cds.cern.ch/record/164736/files/198601282.pdf
-# * https://www.sciencedirect.com/science/article/pii/0010465586901190
-####################
-
-function generate_initial_moms(ss, masses)
-    E1 = (ss^2 + masses[1]^2 - masses[2]^2) / (2 * ss)
-    E2 = (ss^2 + masses[2]^2 - masses[1]^2) / (2 * ss)
-
-    rho1 = sqrt(E1^2 - masses[1]^2)
-    rho2 = sqrt(E2^2 - masses[2]^2)
-
-    return [SFourMomentum(E1, 0, 0, rho1), SFourMomentum(E2, 0, 0, -rho2)]
-end
-
-
-Random.rand(rng::AbstractRNG, ::Random.SamplerType{SFourMomentum}) = SFourMomentum(rand(rng, 4))
-Random.rand(rng::AbstractRNG, ::Random.SamplerType{NTuple{N, Float64}}) where {N} = Tuple(rand(rng, N))
-
-
-function _transform_uni_to_mom(u1, u2, u3, u4)
-    cth = 2 * u1 - 1
-    sth = sqrt(1 - cth^2)
-    phi = 2 * pi * u2
-    q0 = -log(u3 * u4)
-    qx = q0 * sth * cos(phi)
-    qy = q0 * sth * sin(phi)
-    qz = q0 * cth
-
-    return SFourMomentum(q0, qx, qy, qz)
-end
-
-function _transform_uni_to_mom!(uni_mom, dest)
-    u1, u2, u3, u4 = Tuple(uni_mom)
-    cth = 2 * u1 - 1
-    sth = sqrt(1 - cth^2)
-    phi = 2 * pi * u2
-    q0 = -log(u3 * u4)
-    qx = q0 * sth * cos(phi)
-    qy = q0 * sth * sin(phi)
-    qz = q0 * cth
-
-    return dest = SFourMomentum(q0, qx, qy, qz)
-end
-
-_transform_uni_to_mom(u1234::Tuple) = _transform_uni_to_mom(u1234...)
-_transform_uni_to_mom(u1234::SFourMomentum) = _transform_uni_to_mom(Tuple(u1234))
-
-function generate_massless_moms(rng, n::Int)
-    a = Vector{SFourMomentum}(undef, n)
-    rand!(rng, a)
-    return map(_transform_uni_to_mom, a)
-end
-
-function generate_physical_massless_moms(rng, ss, n)
-    r_moms = generate_massless_moms(rng, n)
-    Q = sum(r_moms)
-    M = sqrt(Q * Q)
-    fac = -1 / M
-    Qx = getX(Q)
-    Qy = getY(Q)
-    Qz = getZ(Q)
-    bx = fac * Qx
-    by = fac * Qy
-    bz = fac * Qz
-    gamma = getT(Q) / M
-    a = 1 / (1 + gamma)
-    x = ss / M
-
-    i = 1
-    while i <= n
-        mom = r_moms[i]
-        mom0 = getT(mom)
-        mom1 = getX(mom)
-        mom2 = getY(mom)
-        mom3 = getZ(mom)
-
-        bq = bx * mom1 + by * mom2 + bz * mom3
-
-        p0 = x * (gamma * mom0 + bq)
-        px = x * (mom1 + bx * mom0 + a * bq * bx)
-        py = x * (mom2 + by * mom0 + a * bq * by)
-        pz = x * (mom3 + bz * mom0 + a * bq * bz)
-
-        r_moms[i] = SFourMomentum(p0, px, py, pz)
-        i += 1
-    end
-    return r_moms
-end
-
-function _to_be_solved(xi, masses, p0s, ss)
-    sum = 0.0
-    for (i, E) in enumerate(p0s)
-        sum += sqrt(masses[i]^2 + xi^2 * E^2)
-    end
-    return sum - ss
-end
-
-function _build_massive_momenta(xi, masses, massless_moms)
-    vec = SFourMomentum[]
-    i = 1
-    while i <= length(massless_moms)
-        massless_mom = massless_moms[i]
-        k0 = sqrt(getT(massless_mom)^2 * xi^2 + masses[i]^2)
-
-        kx = xi * getX(massless_mom)
-        ky = xi * getY(massless_mom)
-        kz = xi * getZ(massless_mom)
-
-        push!(vec, SFourMomentum(k0, kx, ky, kz))
-
-        i += 1
-    end
-    return vec
-end
-
-first_derivative(func) = x -> ForwardDiff.derivative(func, float(x))
-
-
-function generate_physical_massive_moms(rng, ss, masses; x0 = 0.1)
-    n = length(masses)
-    massless_moms = generate_physical_massless_moms(rng, ss, n)
-    energies = getT.(massless_moms)
-    f = x -> _to_be_solved(x, masses, energies, ss)
-    xi = find_zero((f, first_derivative(f)), x0, Roots.Newton())
-    return _build_massive_momenta(xi, masses, massless_moms)
-end
diff --git a/src/models/abc/particle.jl b/src/models/abc/particle.jl
index f374ed0..8769eaf 100644
--- a/src/models/abc/particle.jl
+++ b/src/models/abc/particle.jl
@@ -66,7 +66,7 @@ struct ABCProcessInput <: AbstractProcessInput
     outParticles::Vector{ABCParticle}
 end
 
-ABCParticleValue{ParticleType <: ABCParticle} = ParticleValue{ParticleType, Float64}
+ABCParticleValue{ParticleType <: ABCParticle} = ParticleValue{ParticleType, ComplexF64}
 
 """
     PARTICLE_MASSES
@@ -154,30 +154,28 @@ function ABC_vertex()
 end
 
 """
-    ABC_preserve_momentum(p1::ABCParticle, p2::ABCParticle)
+    ABC_conserve_momentum(p1::ABCParticle, p2::ABCParticle)
 
 Calculate and return a new particle from two given interacting ones at a vertex.
 
 Takes 4 effective FLOP.
 """
-function ABC_preserve_momentum(p1::ABCParticle, p2::ABCParticle)
+function ABC_conserve_momentum(p1::ABCParticle, p2::ABCParticle)
     t3 = interaction_result(typeof(p1), typeof(p2))
     p3 = t3(p1.momentum + p2.momentum)
     return p3
 end
 
-"""
-    type_from_name(name::String)
+model(::ABCProcessDescription) = ABCModel()
+model(::ABCProcessInput) = ABCModel()
 
-For a name of a particle, return the particle's [`Type`].
-"""
-function type_from_name(name::String)
+function type_index_from_name(::ABCModel, name::String)
     if startswith(name, "A")
-        return ParticleA
+        return (ParticleA, parse(Int, name[2:end]))
     elseif startswith(name, "B")
-        return ParticleB
+        return (ParticleB, parse(Int, name[2:end]))
     elseif startswith(name, "C")
-        return ParticleC
+        return (ParticleC, parse(Int, name[2:end]))
     else
         throw("Invalid name for a particle in the ABC model")
     end
diff --git a/src/models/abc/properties.jl b/src/models/abc/properties.jl
index 3da8599..538e187 100644
--- a/src/models/abc/properties.jl
+++ b/src/models/abc/properties.jl
@@ -128,15 +128,6 @@ Return the number of children of a ComputeTaskABC_Sum.
 """
 children(t::ComputeTaskABC_Sum) = t.children_number
 
-"""
-    children(t::FusedComputeTask)
-
-Return the number of children of a FusedComputeTask.
-"""
-function children(t::FusedComputeTask)
-    return length(union(Set(t.t1_inputs), Set(t.t2_inputs)))
-end
-
 function add_child!(t::ComputeTaskABC_Sum)
     t.children_number += 1
     return nothing
diff --git a/src/models/interface.jl b/src/models/interface.jl
index e1bf51f..ca30152 100644
--- a/src/models/interface.jl
+++ b/src/models/interface.jl
@@ -95,3 +95,18 @@ Interface function that must be implemented for every specific [`AbstractProcess
 Returns a randomly generated and valid corresponding `ProcessInput`.
 """
 function gen_process_input end
+
+"""
+    model(::AbstractProcessDescription)
+    model(::AbstarctProcessInput)
+
+Return the model of this process description or input.
+"""
+function model end
+
+"""
+    type_from_name(model::AbstractModel, name::String)
+
+For a name of a particle in the given [`AbstractModel`](@ref), return the particle's [`Type`] and index as a tuple. The input string can be expetced to be of the form \"<name><index>\".
+"""
+function type_index_from_name end
diff --git a/src/models/qed/compute.jl b/src/models/qed/compute.jl
index 59a3384..06c71f4 100644
--- a/src/models/qed/compute.jl
+++ b/src/models/qed/compute.jl
@@ -14,10 +14,11 @@ end
 
 Compute an outer edge. Return the particle value with the same particle and the value multiplied by an outer_edge factor.
 """
-function compute(::ComputeTaskQED_U, data::QEDParticleValue{P})::QEDParticleValue{P} where {P <: QEDParticle}
-    return QEDParticleValue{P}(
+function compute(::ComputeTaskQED_U, data::PV) where {P <: QEDParticle, PV <: QEDParticleValue{P}}
+    state = base_state(particle(data.p), direction(data.p), momentum(data.p), spin_or_pol(data.p))
+    return ParticleValue{P, typeof(state)}(
         data.p,
-        base_state(particle(data.p), direction(data.p), momentum(data.p), spin_or_pol(data.p)), # will return a SLorentzVector{ComplexF64}, BiSpinor or AdjointBiSpinor
+        state, # will return a SLorentzVector{ComplexF64}, BiSpinor or AdjointBiSpinor
     )
 end
 
@@ -28,13 +29,25 @@ Compute a vertex. Preserve momentum and particle types (e + gamma->p etc.) to cr
 """
 function compute(
     ::ComputeTaskQED_V,
-    data1::QEDParticleValue{P1},
-    data2::QEDParticleValue{P2},
-)::QEDParticleValue where {P1 <: QEDParticle, P2 <: QEDParticle}
-    p3 = QED_preserve_momentum(data1.p, data2.p)
+    data1::PV1,
+    data2::PV2,
+) where {P1 <: QEDParticle, P2 <: QEDParticle, PV1 <: QEDParticleValue{P1}, PV2 <: QEDParticleValue{P2}}
+    p3 = QED_conserve_momentum(data1.p, data2.p)
     P3 = interaction_result(P1, P2)
-    # TODO: which of data1 and data2 is left and right might depend on their types?
-    dataOut = QEDParticleValue{P3}(P3(p3), data1.v * ABC_vertex() * data2.v)
+
+    state = QED_vertex()
+    if (typeof(data1.v) <: AdjointBiSpinor)
+        state = data1.v * state
+    else
+        state = state * data1.v
+    end
+    if (typeof(data2.v) <: AdjointBiSpinor)
+        state = data2.v * state
+    else
+        state = state * data2.v
+    end
+
+    dataOut = ParticleValue{P3, typeof(state)}(P3(p3), state)
     return dataOut
 end
 
@@ -51,10 +64,29 @@ function compute(
     ::ComputeTaskQED_S2,
     data1::ParticleValue{P1},
     data2::ParticleValue{P2},
-)::ComplexF64 where {P1 <: QEDParticle, P2 <: QEDParticle}
-    @assert issame(P1, propagation_result(P2))
-    # TODO: assert that data1 and data2
+)::ComplexF64 where {
+    P1 <: Union{AntiFermionStateful, FermionStateful},
+    P2 <: Union{AntiFermionStateful, FermionStateful},
+}
+    # TODO: assert that data1 and data2 are opposites
     inner = QED_inner_edge(data1.p)
+    # inner edge is just a scalar, data1 and data2 are bispinor/adjointbispinnor, need to keep correct order
+    if typeof(data1.v) <: BiSpinor
+        return data2.v * inner * data1.v
+    else
+        return data1.v * inner * data2.v
+    end
+end
+
+# TODO: S2 when the particles are photons?
+function compute(
+    ::ComputeTaskQED_S2,
+    data1::ParticleValue{P1},
+    data2::ParticleValue{P2},
+)::ComplexF64 where {P1 <: PhotonStateful, P2 <: PhotonStateful}
+    # TODO: assert that data1 and data2 are opposites
+    inner = QED_inner_edge(data1.p)
+    # inner edge is just a scalar, data1 and data2 are photon states that are just Complex numbers here
     return data1.v * inner * data2.v
 end
 
@@ -66,18 +98,95 @@ Compute inner edge (1 input particle, 1 output particle).
 11 FLOP.
 """
 function compute(::ComputeTaskQED_S1, data::QEDParticleValue{P})::QEDParticleValue where {P <: QEDParticle}
-    # TODO invert P for result (incoming becomes outgoing, outgoing becomes incoming)
     newP = propagation_result(P)
+    # inner edge is just a scalar, can multiply from either side
     return QEDParticleValue{newP}(newP(data.p), data.v * QED_inner_edge(data.p))
 end
 
 """
-    compute(::ComputeTaskQED_Sum, data::Vector{Float64})
+    compute(::ComputeTaskQED_Sum, data::Vector{ComplexF64})
 
 Compute a sum over the vector. Use an algorithm that accounts for accumulated errors in long sums with potentially large differences in magnitude of the summands.
 
 Linearly many FLOP with growing data.
 """
-function compute(::ComputeTaskQED_Sum, data::Vector{Float64})::Float64
+function compute(::ComputeTaskQED_Sum, data::Vector{ComplexF64})::ComplexF64
     return sum_kbn(data)
 end
+
+"""
+    get_expression(::ComputeTaskQED_P, device::AbstractDevice, inExprs::Vector{Expr}, outExpr::Expr)
+
+Generate and return code evaluating [`ComputeTaskQED_P`](@ref) on `inSyms`, providing the output on `outSym`.
+"""
+function get_expression(::ComputeTaskQED_P, device::AbstractDevice, inExprs::Vector, outExpr)
+    in = [eval(inExprs[1])]
+    out = eval(outExpr)
+
+    return Meta.parse("$out = compute(ComputeTaskQED_P(), $(in[1]))")
+end
+
+"""
+    get_expression(::ComputeTaskQED_U, device::AbstractDevice, inExprs::Vector{Expr}, outExpr::Expr)
+
+Generate code evaluating [`ComputeTaskQED_U`](@ref) on `inSyms`, providing the output on `outSym`.
+`inSyms` should be of type [`QEDParticleValue`](@ref), `outSym` will be of type [`QEDParticleValue`](@ref).
+"""
+function get_expression(::ComputeTaskQED_U, device::AbstractDevice, inExprs::Vector, outExpr)
+    in = [eval(inExprs[1])]
+    out = eval(outExpr)
+
+    return Meta.parse("$out = compute(ComputeTaskQED_U(), $(in[1]))")
+end
+
+"""
+    get_expression(::ComputeTaskQED_V, device::AbstractDevice, inExprs::Vector{Expr}, outExpr::Expr)
+
+Generate code evaluating [`ComputeTaskQED_V`](@ref) on `inSyms`, providing the output on `outSym`.
+`inSym[1]` and `inSym[2]` should be of type [`QEDParticleValue`](@ref), `outSym` will be of type [`QEDParticleValue`](@ref).
+"""
+function get_expression(::ComputeTaskQED_V, device::AbstractDevice, inExprs::Vector, outExpr)
+    in = [eval(inExprs[1]), eval(inExprs[2])]
+    out = eval(outExpr)
+
+    return Meta.parse("$out = compute(ComputeTaskQED_V(), $(in[1]), $(in[2]))")
+end
+
+"""
+    get_expression(::ComputeTaskQED_S2, device::AbstractDevice, inExprs::Vector{Expr}, outExpr::Expr)
+
+Generate code evaluating [`ComputeTaskQED_S2`](@ref) on `inSyms`, providing the output on `outSym`.
+`inSyms[1]` and `inSyms[2]` should be of type [`QEDParticleValue`](@ref), `outSym` will be of type `Float64`.
+"""
+function get_expression(::ComputeTaskQED_S2, device::AbstractDevice, inExprs::Vector, outExpr)
+    in = [eval(inExprs[1]), eval(inExprs[2])]
+    out = eval(outExpr)
+
+    return Meta.parse("$out = compute(ComputeTaskQED_S2(), $(in[1]), $(in[2]))")
+end
+
+"""
+    get_expression(::ComputeTaskQED_S1, device::AbstractDevice, inExprs::Vector{Expr}, outExpr::Expr)
+
+Generate code evaluating [`ComputeTaskQED_S1`](@ref) on `inSyms`, providing the output on `outSym`.
+`inSyms` should be of type [`QEDParticleValue`](@ref), `outSym` will be of type [`QEDParticleValue`](@ref).
+"""
+function get_expression(::ComputeTaskQED_S1, device::AbstractDevice, inExprs::Vector, outExpr)
+    in = [eval(inExprs[1])]
+    out = eval(outExpr)
+
+    return Meta.parse("$out = compute(ComputeTaskQED_S1(), $(in[1]))")
+end
+
+"""
+    get_expression(::ComputeTaskQED_Sum, device::AbstractDevice, inExprs::Vector{Expr}, outExpr::Expr)
+
+Generate code evaluating [`ComputeTaskQED_Sum`](@ref) on `inSyms`, providing the output on `outSym`.
+`inSyms` should be of type [`Float64`], `outSym` will be of type [`Float64`].
+"""
+function get_expression(::ComputeTaskQED_Sum, device::AbstractDevice, inExprs::Vector, outExpr)
+    in = eval.(inExprs)
+    out = eval(outExpr)
+
+    return Meta.parse("$out = compute(ComputeTaskQED_Sum(), [$(unroll_symbol_vector(in))])")
+end
diff --git a/src/models/qed/create.jl b/src/models/qed/create.jl
new file mode 100644
index 0000000..cdaa1c6
--- /dev/null
+++ b/src/models/qed/create.jl
@@ -0,0 +1,55 @@
+
+"""
+    gen_process_input(processDescription::QEDProcessDescription)
+
+Return a ProcessInput of randomly generated [`QEDParticle`](@ref)s from a [`QEDProcessDescription`](@ref). The process description can be created manually or parsed from a string using [`parse_process`](@ref).
+
+Note: This uses RAMBO to create a valid process with conservation of momentum and energy.
+"""
+function gen_process_input(processDescription::QEDProcessDescription)
+    massSum = 0
+    inputMasses = Vector{Float64}()
+    for (particle, n) in processDescription.inParticles
+        for _ in 1:n
+            massSum += mass(particle)
+            push!(inputMasses, mass(particle))
+        end
+    end
+    outputMasses = Vector{Float64}()
+    for (particle, n) in processDescription.outParticles
+        for _ in 1:n
+            massSum += mass(particle)
+            push!(outputMasses, mass(particle))
+        end
+    end
+
+    # add some extra random mass to allow for some momentum
+    massSum += rand(rng[threadid()]) * (length(inputMasses) + length(outputMasses))
+
+
+    inputParticles = Vector{QEDParticle}()
+    initialMomenta = generate_initial_moms(massSum, inputMasses)
+    index = 1
+    for (particle, n) in processDescription.inParticles
+        for _ in 1:n
+            mom = initialMomenta[index]
+            push!(inputParticles, particle(mom))
+            index += 1
+        end
+    end
+
+    outputParticles = Vector{QEDParticle}()
+    final_momenta = generate_physical_massive_moms(rng[threadid()], massSum, outputMasses)
+    index = 1
+    for (particle, n) in processDescription.outParticles
+        for _ in 1:n
+            mom = final_momenta[index]
+            push!(outputParticles, particle(SFourMomentum(-mom.E, mom.px, mom.py, mom.pz)))
+            index += 1
+        end
+    end
+
+    processInput = QEDProcessInput(processDescription, inputParticles, outputParticles)
+
+    return return processInput
+end
diff --git a/src/models/qed/parse.jl b/src/models/qed/parse.jl
new file mode 100644
index 0000000..ffcac74
--- /dev/null
+++ b/src/models/qed/parse.jl
@@ -0,0 +1,44 @@
+
+"""
+    parse_process(string::AbstractString, model::QEDModel)
+
+Parse a string representation of a process, such as "ke->ke" into the corresponding [`QEDProcessDescription`](@ref).
+"""
+function parse_process(str::AbstractString, model::QEDModel)
+    inParticles = Dict{Type, Int}()
+    outParticles = Dict{Type, Int}()
+
+    if !(contains(str, "->"))
+        throw("Did not find -> while parsing process \"$str\"")
+    end
+
+    (inStr, outStr) = split(str, "->")
+
+    if (isempty(inStr) || isempty(outStr))
+        throw("Process (\"$str\") input or output part is empty!")
+    end
+
+    for t in types(model)
+        if (isincoming(t))
+            inCount = count(x -> x == String(t)[1], inStr)
+
+            if inCount != 0
+                inParticles[t] = inCount
+            end
+        end
+        if (isoutgoing(t))
+            outCount = count(x -> x == String(t)[1], outStr)
+            if outCount != 0
+                outParticles[t] = outCount
+            end
+        end
+    end
+
+    if length(inStr) != sum(values(inParticles))
+        throw("Encountered unknown characters in the input part of process \"$str\"")
+    elseif length(outStr) != sum(values(outParticles))
+        throw("Encountered unknown characters in the output part of process \"$str\"")
+    end
+
+    return QEDProcessDescription(inParticles, outParticles)
+end
diff --git a/src/models/qed/particle.jl b/src/models/qed/particle.jl
index c165f1c..f900c6f 100644
--- a/src/models/qed/particle.jl
+++ b/src/models/qed/particle.jl
@@ -43,8 +43,13 @@ struct QEDProcessInput <: AbstractProcessInput
     outParticles::Vector{QEDParticle}
 end
 
-QEDParticleValue{ParticleType <: QEDParticle} =
-    ParticleValue{ParticleType, <:Union{BiSpinor, AdjointBiSpinor, DiracMatrix, SLorentzVector{ComplexF64}, ComplexF64}}
+QEDParticleValue{ParticleType <: QEDParticle} = Union{
+    ParticleValue{ParticleType, BiSpinor},
+    ParticleValue{ParticleType, AdjointBiSpinor},
+    ParticleValue{ParticleType, DiracMatrix},
+    ParticleValue{ParticleType, SLorentzVector{Float64}},
+    ParticleValue{ParticleType, ComplexF64},
+}
 
 """
     PhotonStateful <: QEDParticle
@@ -58,7 +63,7 @@ struct PhotonStateful{Direction <: ParticleDirection} <: QEDParticle{Direction}
 end
 
 PhotonStateful{Direction}(mom::SFourMomentum) where {Direction <: ParticleDirection} =
-    PhotonStateful{Direction}(mom, AllPolarization())
+    PhotonStateful{Direction}(mom, PolX()) # TODO: make allpol possible
 
 PhotonStateful{Dir1}(ph::PhotonStateful{Dir2}) where {Dir1 <: ParticleDirection, Dir2 <: ParticleDirection} =
     PhotonStateful{Dir1}(ph.momentum, ph.polarization)
@@ -71,10 +76,11 @@ A fermion of the [`QEDModel`](@ref) with its state.
 struct FermionStateful{Direction <: ParticleDirection} <: QEDParticle{Direction}
     momentum::SFourMomentum
     spin::AbstractSpin
+    # TODO: mass for electron/muon/tauon representation?
 end
 
 FermionStateful{Direction}(mom::SFourMomentum) where {Direction <: ParticleDirection} =
-    FermionStateful{Direction}(mom, AllSpin())
+    FermionStateful{Direction}(mom, SpinUp()) # TODO: make allspin possible
 
 FermionStateful{Dir1}(f::FermionStateful{Dir2}) where {Dir1 <: ParticleDirection, Dir2 <: ParticleDirection} =
     FermionStateful{Dir1}(f.momentum, f.spin)
@@ -87,10 +93,11 @@ An anti-fermion of the [`QEDModel`](@ref) with its state.
 struct AntiFermionStateful{Direction <: ParticleDirection} <: QEDParticle{Direction}
     momentum::SFourMomentum
     spin::AbstractSpin
+    # TODO: mass for electron/muon/tauon representation?
 end
 
 AntiFermionStateful{Direction}(mom::SFourMomentum) where {Direction <: ParticleDirection} =
-    AntiFermionStateful{Direction}(mom, AllSpin())
+    AntiFermionStateful{Direction}(mom, SpinUp()) # TODO: make allspin possible
 
 AntiFermionStateful{Dir1}(f::AntiFermionStateful{Dir2}) where {Dir1 <: ParticleDirection, Dir2 <: ParticleDirection} =
     AntiFermionStateful{Dir1}(f.momentum, f.spin)
@@ -144,30 +151,37 @@ propagation_result(::Type{PhotonStateful{Outgoing}}) = PhotonStateful{Incoming}
 Return a Vector of the possible types of particle in the [`QEDModel`](@ref).
 """
 function types(::QEDModel)
-    return [PhotonStateful, FermionStateful, AntiFermionStateful]
+    return [
+        PhotonStateful{Incoming},
+        PhotonStateful{Outgoing},
+        FermionStateful{Incoming},
+        FermionStateful{Outgoing},
+        AntiFermionStateful{Incoming},
+        AntiFermionStateful{Outgoing},
+    ]
 end
 
 # type piracy?
 String(::Type{Incoming}) = "Incoming"
 String(::Type{Outgoing}) = "Outgoing"
 
-function String(::Type{PhotonStateful{Dir}}) where {Dir <: ParticleDirection}
-    return "Photon" * String(Dir)
+function String(::Type{<:PhotonStateful})
+    return "k"
 end
-function String(::Type{FermionStateful{Dir}}) where {Dir <: ParticleDirection}
-    return "Fermion" * String(Dir)
+function String(::Type{<:FermionStateful})
+    return "e"
 end
-function String(::Type{AntiFermionStateful{Dir}}) where {Dir <: ParticleDirection}
-    return "Anti-Fermion" * String(Dir)
+function String(::Type{<:AntiFermionStateful})
+    return "p"
 end
 
 @inline particle(::PhotonStateful) = Photon()
-@inline particle(::FermionStateful) = Fermion()
-@inline particle(::AntiFermionStateful) = AntiFermion()
+@inline particle(::FermionStateful) = Electron()
+@inline particle(::AntiFermionStateful) = Positron()
 
-@inline momentum(p::PhotonStateful)::SFourMomentum{ComplexF64} = p.momentum
-@inline momentum(p::FermionStateful)::SFourMomentum{ComplexF64} = p.momentum
-@inline momentum(p::AntiFermionStateful)::SFourMomentum{ComplexF64} = p.momentum
+@inline momentum(p::PhotonStateful)::SFourMomentum = p.momentum
+@inline momentum(p::FermionStateful)::SFourMomentum = p.momentum
+@inline momentum(p::AntiFermionStateful)::SFourMomentum = p.momentum
 
 @inline spin_or_pol(p::PhotonStateful)::AbstractPolarization = p.polarization
 @inline spin_or_pol(p::FermionStateful)::AbstractSpin = p.spin
@@ -177,6 +191,20 @@ end
 @inline direction(::FermionStateful{Dir}) where {Dir <: ParticleDirection} = Dir()
 @inline direction(::AntiFermionStateful{Dir}) where {Dir <: ParticleDirection} = Dir()
 
+@inline isincoming(::QEDParticle{Incoming}) = true
+@inline isincoming(::QEDParticle{Outgoing}) = false
+@inline isoutgoing(::QEDParticle{Incoming}) = false
+@inline isoutgoing(::QEDParticle{Outgoing}) = true
+
+@inline isincoming(::Type{<:QEDParticle{Incoming}}) = true
+@inline isincoming(::Type{<:QEDParticle{Outgoing}}) = false
+@inline isoutgoing(::Type{<:QEDParticle{Incoming}}) = false
+@inline isoutgoing(::Type{<:QEDParticle{Outgoing}}) = true
+
+@inline mass(::Type{<:FermionStateful}) = 1.0
+@inline mass(::Type{<:AntiFermionStateful}) = 1.0
+@inline mass(::Type{<:PhotonStateful}) = 0.0
+
 """
     caninteract(T1::Type{<:QEDParticle}, T2::Type{<:QEDParticle})
 
@@ -204,6 +232,24 @@ function caninteract(T1::Type{<:QEDParticle}, T2::Type{<:QEDParticle})
     return true
 end
 
+function type_index_from_name(::QEDModel, name::String)
+    if startswith(name, "ki")
+        return (PhotonStateful{Incoming}, parse(Int, name[3:end]))
+    elseif startswith(name, "ko")
+        return (PhotonStateful{Outgoing}, parse(Int, name[3:end]))
+    elseif startswith(name, "ei")
+        return (FermionStateful{Incoming}, parse(Int, name[3:end]))
+    elseif startswith(name, "eo")
+        return (FermionStateful{Outgoing}, parse(Int, name[3:end]))
+    elseif startswith(name, "pi")
+        return (AntiFermionStateful{Incoming}, parse(Int, name[3:end]))
+    elseif startswith(name, "po")
+        return (AntiFermionStateful{Outgoing}, parse(Int, name[3:end]))
+    else
+        throw("Invalid name for a particle in the QED model")
+    end
+end
+
 """
     issame(T1::Type{<:QEDParticle}, T2::Type{<:QEDParticle})
 
@@ -224,14 +270,46 @@ Return the factor of a vertex in a QED feynman diagram.
     return ComplexF64(0, 1) * gamma()
 end
 
+@inline function QED_inner_edge(p::QEDParticle)
+    # TODO: doesn't exist yet in QEDprocesses
+    return one(ComplexF64)
+end
+
 """
-    QED_preserve_momentum(p1::QEDParticle, p2::QEDParticle)
+    QED_conserve_momentum(p1::QEDParticle, p2::QEDParticle)
 
 Calculate and return a new particle from two given interacting ones at a vertex.
 """
-function QED_preserve_momentum(p1::QEDParticle, p2::QEDParticle)
+function QED_conserve_momentum(p1::QEDParticle, p2::QEDParticle)
     T3 = interaction_result(typeof(p1), typeof(p2))
     # TODO: probably also need to do something about the spin/pol
     p3 = T3(p1.momentum + p2.momentum)
     return p3
 end
+
+"""
+    model(::AbstractProcessDescription)
+
+Return the model of this process description.
+"""
+model(::QEDProcessDescription) = QEDModel()
+model(::QEDProcessInput) = QEDModel()
+
+==(p1::QEDProcessDescription, p2::QEDProcessDescription) =
+    p1.inParticles == p2.inParticles && p1.outParticles == p2.outParticles
+
+function in_particles(process::QEDProcessDescription)
+    return process.inParticles
+end
+
+function in_particles(input::QEDProcessInput)
+    return input.inParticles
+end
+
+function out_particles(process::QEDProcessDescription)
+    return process.outParticles
+end
+
+function out_particles(input::QEDProcessInput)
+    return input.outParticles
+end
diff --git a/src/models/qed/print.jl b/src/models/qed/print.jl
new file mode 100644
index 0000000..1d8cad8
--- /dev/null
+++ b/src/models/qed/print.jl
@@ -0,0 +1,61 @@
+
+"""
+    show(io::IO, process::QEDProcessDescription)
+
+Pretty print an [`QEDProcessDescription`](@ref) (no newlines).
+
+```jldoctest
+julia> using MetagraphOptimization
+
+julia> print(parse_process("ke->ke", QEDModel()))
+QED Process: 'ke->ke'
+
+julia> print(parse_process("kk->ep", QEDModel()))
+QED Process: 'kk->ep'
+```
+"""
+function show(io::IO, process::QEDProcessDescription)
+    # types() gives the types in order (QED) instead of random like keys() would
+    print(io, "QED Process: \'")
+    for type in types(QEDModel())
+        for _ in 1:get(process.inParticles, type, 0)
+            print(io, String(type))
+        end
+    end
+    print(io, "->")
+    for type in types(QEDModel())
+        for _ in 1:get(process.outParticles, type, 0)
+            print(io, String(type))
+        end
+    end
+    print(io, "'")
+    return nothing
+end
+
+"""
+    show(io::IO, processInput::QEDProcessInput)
+
+Pretty print an [`QEDProcessInput`](@ref) (with newlines).
+"""
+function show(io::IO, processInput::QEDProcessInput)
+    println(io, "Input for $(processInput.process):")
+    println(io, "  $(length(processInput.inParticles)) Incoming particles:")
+    for particle in processInput.inParticles
+        println(io, "    $particle")
+    end
+    println(io, "  $(length(processInput.outParticles)) Outgoing Particles:")
+    for particle in processInput.outParticles
+        println(io, "    $particle")
+    end
+    return nothing
+end
+
+"""
+    show(io::IO, particle::T) where {T <: QEDParticle}
+
+Pretty print an [`QEDParticle`](@ref) (no newlines).
+"""
+function show(io::IO, particle::T) where {T <: QEDParticle}
+    print(io, "$(String(typeof(particle))): $(particle.momentum)")
+    return nothing
+end
diff --git a/src/models/qed/properties.jl b/src/models/qed/properties.jl
new file mode 100644
index 0000000..995e69c
--- /dev/null
+++ b/src/models/qed/properties.jl
@@ -0,0 +1,135 @@
+# TODO use correct numbers
+
+"""
+    compute_effort(t::ComputeTaskQED_S1)
+
+Return the compute effort of an S1 task.
+"""
+compute_effort(t::ComputeTaskQED_S1)::Float64 = 11.0
+
+"""
+    compute_effort(t::ComputeTaskQED_S2)
+
+Return the compute effort of an S2 task.
+"""
+compute_effort(t::ComputeTaskQED_S2)::Float64 = 12.0
+
+"""
+    compute_effort(t::ComputeTaskQED_U)
+
+Return the compute effort of a U task.
+"""
+compute_effort(t::ComputeTaskQED_U)::Float64 = 1.0
+
+"""
+    compute_effort(t::ComputeTaskQED_V)
+
+Return the compute effort of a V task.
+"""
+compute_effort(t::ComputeTaskQED_V)::Float64 = 6.0
+
+"""
+    compute_effort(t::ComputeTaskQED_P)
+
+Return the compute effort of a P task.
+"""
+compute_effort(t::ComputeTaskQED_P)::Float64 = 0.0
+
+"""
+    compute_effort(t::ComputeTaskQED_Sum)
+
+Return the compute effort of a Sum task. 
+
+Note: This is a constant compute effort, even though sum scales with the number of its inputs. Since there is only ever a single sum node in a graph generated from the QED-Model,
+this doesn't matter.
+"""
+compute_effort(t::ComputeTaskQED_Sum)::Float64 = 1.0
+
+"""
+    show(io::IO, t::ComputeTaskQED_S1)
+
+Print the S1 task to io.
+"""
+show(io::IO, t::ComputeTaskQED_S1) = print(io, "ComputeS1")
+
+"""
+    show(io::IO, t::ComputeTaskQED_S2)
+
+Print the S2 task to io.
+"""
+show(io::IO, t::ComputeTaskQED_S2) = print(io, "ComputeS2")
+
+"""
+    show(io::IO, t::ComputeTaskQED_P)
+
+Print the P task to io.
+"""
+show(io::IO, t::ComputeTaskQED_P) = print(io, "ComputeP")
+
+"""
+    show(io::IO, t::ComputeTaskQED_U)
+
+Print the U task to io.
+"""
+show(io::IO, t::ComputeTaskQED_U) = print(io, "ComputeU")
+
+"""
+    show(io::IO, t::ComputeTaskQED_V)
+
+Print the V task to io.
+"""
+show(io::IO, t::ComputeTaskQED_V) = print(io, "ComputeV")
+
+"""
+    show(io::IO, t::ComputeTaskQED_Sum)
+
+Print the sum task to io.
+"""
+show(io::IO, t::ComputeTaskQED_Sum) = print(io, "ComputeSum")
+
+"""
+    children(::ComputeTaskQED_S1)
+
+Return the number of children of a ComputeTaskQED_S1 (always 1).
+"""
+children(::ComputeTaskQED_S1) = 1
+
+"""
+    children(::ComputeTaskQED_S2)
+
+Return the number of children of a ComputeTaskQED_S2 (always 2).
+"""
+children(::ComputeTaskQED_S2) = 2
+
+"""
+    children(::ComputeTaskQED_P)
+
+Return the number of children of a ComputeTaskQED_P (always 1).
+"""
+children(::ComputeTaskQED_P) = 1
+
+"""
+    children(::ComputeTaskQED_U)
+
+Return the number of children of a ComputeTaskQED_U (always 1).
+"""
+children(::ComputeTaskQED_U) = 1
+
+"""
+    children(::ComputeTaskQED_V)
+
+Return the number of children of a ComputeTaskQED_V (always 2).
+"""
+children(::ComputeTaskQED_V) = 2
+
+"""
+    children(::ComputeTaskQED_Sum)
+
+Return the number of children of a ComputeTaskQED_Sum.
+"""
+children(t::ComputeTaskQED_Sum) = t.children_number
+
+function add_child!(t::ComputeTaskQED_Sum)
+    t.children_number += 1
+    return nothing
+end
diff --git a/src/task/properties.jl b/src/task/properties.jl
index ad9efe5..53eef11 100644
--- a/src/task/properties.jl
+++ b/src/task/properties.jl
@@ -72,6 +72,15 @@ Return the number of children of a data task (always 1).
 """
 children(::DataTask) = 1
 
+"""
+    children(t::FusedComputeTask)
+
+Return the number of children of a FusedComputeTask.
+"""
+function children(t::FusedComputeTask)
+    return length(union(Set(t.t1_inputs), Set(t.t2_inputs)))
+end
+
 """
     data(t::AbstractComputeTask)
 
diff --git a/src/utility.jl b/src/utility.jl
index 38328d1..55e6df3 100644
--- a/src/utility.jl
+++ b/src/utility.jl
@@ -103,3 +103,139 @@ function unroll_symbol_vector(vec::Vector)
     end
     return result
 end
+
+
+
+####################
+# CODE FROM HERE BORROWED FROM SOURCE: https://codebase.helmholtz.cloud/qedsandbox/QEDphasespaces.jl/
+# use qedphasespaces directly once released
+#
+# quick and dirty implementation of the RAMBO algorithm
+#
+# reference: 
+# * https://cds.cern.ch/record/164736/files/198601282.pdf
+# * https://www.sciencedirect.com/science/article/pii/0010465586901190
+####################
+
+function generate_initial_moms(ss, masses)
+    E1 = (ss^2 + masses[1]^2 - masses[2]^2) / (2 * ss)
+    E2 = (ss^2 + masses[2]^2 - masses[1]^2) / (2 * ss)
+
+    rho1 = sqrt(E1^2 - masses[1]^2)
+    rho2 = sqrt(E2^2 - masses[2]^2)
+
+    return [SFourMomentum(E1, 0, 0, rho1), SFourMomentum(E2, 0, 0, -rho2)]
+end
+
+
+Random.rand(rng::AbstractRNG, ::Random.SamplerType{SFourMomentum}) = SFourMomentum(rand(rng, 4))
+Random.rand(rng::AbstractRNG, ::Random.SamplerType{NTuple{N, Float64}}) where {N} = Tuple(rand(rng, N))
+
+
+function _transform_uni_to_mom(u1, u2, u3, u4)
+    cth = 2 * u1 - 1
+    sth = sqrt(1 - cth^2)
+    phi = 2 * pi * u2
+    q0 = -log(u3 * u4)
+    qx = q0 * sth * cos(phi)
+    qy = q0 * sth * sin(phi)
+    qz = q0 * cth
+
+    return SFourMomentum(q0, qx, qy, qz)
+end
+
+function _transform_uni_to_mom!(uni_mom, dest)
+    u1, u2, u3, u4 = Tuple(uni_mom)
+    cth = 2 * u1 - 1
+    sth = sqrt(1 - cth^2)
+    phi = 2 * pi * u2
+    q0 = -log(u3 * u4)
+    qx = q0 * sth * cos(phi)
+    qy = q0 * sth * sin(phi)
+    qz = q0 * cth
+
+    return dest = SFourMomentum(q0, qx, qy, qz)
+end
+
+_transform_uni_to_mom(u1234::Tuple) = _transform_uni_to_mom(u1234...)
+_transform_uni_to_mom(u1234::SFourMomentum) = _transform_uni_to_mom(Tuple(u1234))
+
+function generate_massless_moms(rng, n::Int)
+    a = Vector{SFourMomentum}(undef, n)
+    rand!(rng, a)
+    return map(_transform_uni_to_mom, a)
+end
+
+function generate_physical_massless_moms(rng, ss, n)
+    r_moms = generate_massless_moms(rng, n)
+    Q = sum(r_moms)
+    M = sqrt(Q * Q)
+    fac = -1 / M
+    Qx = getX(Q)
+    Qy = getY(Q)
+    Qz = getZ(Q)
+    bx = fac * Qx
+    by = fac * Qy
+    bz = fac * Qz
+    gamma = getT(Q) / M
+    a = 1 / (1 + gamma)
+    x = ss / M
+
+    i = 1
+    while i <= n
+        mom = r_moms[i]
+        mom0 = getT(mom)
+        mom1 = getX(mom)
+        mom2 = getY(mom)
+        mom3 = getZ(mom)
+
+        bq = bx * mom1 + by * mom2 + bz * mom3
+
+        p0 = x * (gamma * mom0 + bq)
+        px = x * (mom1 + bx * mom0 + a * bq * bx)
+        py = x * (mom2 + by * mom0 + a * bq * by)
+        pz = x * (mom3 + bz * mom0 + a * bq * bz)
+
+        r_moms[i] = SFourMomentum(p0, px, py, pz)
+        i += 1
+    end
+    return r_moms
+end
+
+function _to_be_solved(xi, masses, p0s, ss)
+    sum = 0.0
+    for (i, E) in enumerate(p0s)
+        sum += sqrt(masses[i]^2 + xi^2 * E^2)
+    end
+    return sum - ss
+end
+
+function _build_massive_momenta(xi, masses, massless_moms)
+    vec = SFourMomentum[]
+    i = 1
+    while i <= length(massless_moms)
+        massless_mom = massless_moms[i]
+        k0 = sqrt(getT(massless_mom)^2 * xi^2 + masses[i]^2)
+
+        kx = xi * getX(massless_mom)
+        ky = xi * getY(massless_mom)
+        kz = xi * getZ(massless_mom)
+
+        push!(vec, SFourMomentum(k0, kx, ky, kz))
+
+        i += 1
+    end
+    return vec
+end
+
+first_derivative(func) = x -> ForwardDiff.derivative(func, float(x))
+
+
+function generate_physical_massive_moms(rng, ss, masses; x0 = 0.1)
+    n = length(masses)
+    massless_moms = generate_physical_massless_moms(rng, ss, n)
+    energies = getT.(massless_moms)
+    f = x -> _to_be_solved(x, masses, energies, ss)
+    xi = find_zero((f, first_derivative(f)), x0, Roots.Newton())
+    return _build_massive_momenta(xi, masses, massless_moms)
+end
diff --git a/test/Project.toml b/test/Project.toml
index 666301a..ebd4fc0 100644
--- a/test/Project.toml
+++ b/test/Project.toml
@@ -3,4 +3,5 @@ AccurateArithmetic = "22286c92-06ac-501d-9306-4abd417d9753"
 QEDbase = "10e22c08-3ccb-4172-bfcf-7d7aa3d04d93"
 Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c"
 SafeTestsets = "1bc83da4-3b8d-516f-aca4-4fe02f6d838f"
+StatsBase = "2913bbd2-ae8a-5f71-8c99-4fb6c76f3a91"
 Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40"
diff --git a/test/unit_tests_qedmodel.jl b/test/unit_tests_qedmodel.jl
index c4341f9..d9070d2 100644
--- a/test/unit_tests_qedmodel.jl
+++ b/test/unit_tests_qedmodel.jl
@@ -1,5 +1,6 @@
 using MetagraphOptimization
 using QEDbase
+using StatsBase # for countmap
 
 import MetagraphOptimization.caninteract
 import MetagraphOptimization.issame
@@ -44,3 +45,142 @@ end
         @test direction(propagation_result(p)(def_momentum)) != direction(p(def_momentum))
     end
 end
+
+@testset "Parse Process" begin
+    @testset "Order invariance" begin
+        @test parse_process("ke->ke", QEDModel()) == parse_process("ek->ke", QEDModel())
+        @test parse_process("ke->ke", QEDModel()) == parse_process("ek->ek", QEDModel())
+        @test parse_process("ke->ke", QEDModel()) == parse_process("ke->ek", QEDModel())
+
+        @test parse_process("kkke->eep", QEDModel()) == parse_process("kkek->epe", QEDModel())
+    end
+
+    @testset "Known processes" begin
+        compton_process = QEDProcessDescription(
+            Dict{Type, Int}(PhotonStateful{Incoming} => 1, FermionStateful{Incoming} => 1),
+            Dict{Type, Int}(PhotonStateful{Outgoing} => 1, FermionStateful{Outgoing} => 1),
+        )
+
+        @test parse_process("ke->ke", QEDModel()) == compton_process
+
+        positron_compton_process = QEDProcessDescription(
+            Dict{Type, Int}(PhotonStateful{Incoming} => 1, AntiFermionStateful{Incoming} => 1),
+            Dict{Type, Int}(PhotonStateful{Outgoing} => 1, AntiFermionStateful{Outgoing} => 1),
+        )
+
+        @test parse_process("kp->kp", QEDModel()) == positron_compton_process
+
+        trident_process = QEDProcessDescription(
+            Dict{Type, Int}(PhotonStateful{Incoming} => 1, FermionStateful{Incoming} => 1),
+            Dict{Type, Int}(FermionStateful{Outgoing} => 2, AntiFermionStateful{Outgoing} => 1),
+        )
+
+        @test parse_process("ke->eep", QEDModel()) == trident_process
+
+        pair_production_process = QEDProcessDescription(
+            Dict{Type, Int}(PhotonStateful{Incoming} => 2),
+            Dict{Type, Int}(FermionStateful{Outgoing} => 1, AntiFermionStateful{Outgoing} => 1),
+        )
+
+        @test parse_process("kk->pe", QEDModel()) == pair_production_process
+
+        pair_annihilation_process = QEDProcessDescription(
+            Dict{Type, Int}(FermionStateful{Incoming} => 1, AntiFermionStateful{Incoming} => 1),
+            Dict{Type, Int}(PhotonStateful{Outgoing} => 2),
+        )
+
+        @test parse_process("pe->kk", QEDModel()) == pair_annihilation_process
+    end
+end
+
+@testset "Generate Process Inputs" begin
+    @testset "Process $proc_str" for proc_str in ["ke->ke", "kp->kp", "kk->ep", "ep->kk"]
+        # currently can only generate for 2->2 processes
+        process = parse_process(proc_str, QEDModel())
+
+        for i in 1:100
+            input = gen_process_input(process)
+            @test countmap(typeof.(input.inParticles)) == process.inParticles
+            @test countmap(typeof.(input.outParticles)) == process.outParticles
+
+            @test isapprox(
+                sum(getfield.(input.inParticles, :momentum)) + sum(getfield.(input.outParticles, :momentum)),
+                SFourMomentum(0.0, 0.0, 0.0, 0.0);
+                atol = sqrt(eps()),
+            )
+        end
+    end
+end
+
+@testset "Compton" begin
+    import MetagraphOptimization.insert_node!
+    import MetagraphOptimization.insert_edge!
+    import MetagraphOptimization.make_node
+
+    model = QEDModel()
+    process = parse_process("ke->ke", model)
+    machine = get_machine_info()
+
+    graph = MetagraphOptimization.DAG()
+
+    # manually build a graph for compton
+    graph = DAG()
+
+    # s to output (exit node)
+    d_exit = insert_node!(graph, make_node(DataTask(16)), track = false)
+
+    # final s compute
+    s0 = insert_node!(graph, make_node(ComputeTaskQED_S2()), track = false)
+
+    # data from v0 and v1 to s0
+    d_v0_s0 = insert_node!(graph, make_node(DataTask(96)), track = false)
+    d_v1_s0 = insert_node!(graph, make_node(DataTask(96)), track = false)
+
+    # v0 and v1 compute
+    v0 = insert_node!(graph, make_node(ComputeTaskQED_V()), track = false)
+    v1 = insert_node!(graph, make_node(ComputeTaskQED_V()), track = false)
+
+    # data from uPhIn, uPhOut, uElIn, uElOut
+    d_uPhIn_v0 = insert_node!(graph, make_node(DataTask(96)), track = false)
+    d_uElIn_v0 = insert_node!(graph, make_node(DataTask(96)), track = false)
+    d_uPhOut_v1 = insert_node!(graph, make_node(DataTask(96)), track = false)
+    d_uElOut_v1 = insert_node!(graph, make_node(DataTask(96)), track = false)
+
+    # uPhIn, uPhOut, uElIn and uElOut computes
+    uPhIn = insert_node!(graph, make_node(ComputeTaskQED_U()), track = false)
+    uPhOut = insert_node!(graph, make_node(ComputeTaskQED_U()), track = false)
+    uElIn = insert_node!(graph, make_node(ComputeTaskQED_U()), track = false)
+    uElOut = insert_node!(graph, make_node(ComputeTaskQED_U()), track = false)
+
+    # data into U
+    d_uPhIn = insert_node!(graph, make_node(DataTask(16), "ki1"), track = false)
+    d_uPhOut = insert_node!(graph, make_node(DataTask(16), "ko1"), track = false)
+    d_uElIn = insert_node!(graph, make_node(DataTask(16), "ei1"), track = false)
+    d_uElOut = insert_node!(graph, make_node(DataTask(16), "eo1"), track = false)
+
+    # now for all the edges
+    insert_edge!(graph, d_uPhIn, uPhIn, track = false)
+    insert_edge!(graph, d_uPhOut, uPhOut, track = false)
+    insert_edge!(graph, d_uElIn, uElIn, track = false)
+    insert_edge!(graph, d_uElOut, uElOut, track = false)
+
+    insert_edge!(graph, uPhIn, d_uPhIn_v0, track = false)
+    insert_edge!(graph, uPhOut, d_uPhOut_v1, track = false)
+    insert_edge!(graph, uElIn, d_uElIn_v0, track = false)
+    insert_edge!(graph, uElOut, d_uElOut_v1, track = false)
+
+    insert_edge!(graph, d_uPhIn_v0, v0, track = false)
+    insert_edge!(graph, d_uPhOut_v1, v1, track = false)
+    insert_edge!(graph, d_uElIn_v0, v0, track = false)
+    insert_edge!(graph, d_uElOut_v1, v1, track = false)
+
+    insert_edge!(graph, v0, d_v0_s0, track = false)
+    insert_edge!(graph, v1, d_v1_s0, track = false)
+
+    insert_edge!(graph, d_v0_s0, s0, track = false)
+    insert_edge!(graph, d_v1_s0, s0, track = false)
+
+    insert_edge!(graph, s0, d_exit, track = false)
+
+    compton_function = get_compute_function(graph, process, machine)
+end