51 Commits

Author SHA1 Message Date
5e5e29dc69 Add generated qed compton graph to execution test 2023-12-07 00:49:30 +01:00
86799644c4 Make diagram generation faster, add tests for it, update some notebooks 2023-12-05 17:32:05 +01:00
f78cde613a Put diagram generation in qed-model and fix things 2023-11-30 17:08:42 +01:00
3ca24f76e1 Work on diagram generation and feynman diagram representation 2023-11-30 03:50:31 +01:00
6314539f2c Correct qed implementation and test compton 2023-11-29 16:43:47 +01:00
ba0c75c8dc Add momentum conservation tests; Debug result against groundtruth 2023-11-28 15:50:18 +01:00
aa18430d29 Delete duplicated drawio 2023-11-28 12:16:36 +01:00
268841990e Work on QED Model execution 2023-11-27 19:45:51 +01:00
7ad5e78b3b Add diagram generation notebook draft 2023-11-27 15:45:42 +01:00
afec3f6e70 Add some todos, add issame and caninteract to module instead of test 2023-11-24 19:37:16 +01:00
62d572adbf Add propagation results and tests 2023-11-24 19:20:23 +01:00
c2687cdc01 Add model, particles etc., add interaction_result and tests for it, add compute task types 2023-11-24 19:20:23 +01:00
fcb7c992da Renaming of ABC Model things, add QEDprocesses/QEDbase types and use them 2023-11-24 19:20:23 +01:00
938bf216e5 Improve actions workflow by removing prepare step (#23)
Reviewed-on: Rubydragon/MetagraphOptimization.jl#23
Co-authored-by: Anton Reinhard <anton.reinhard@proton.me>
Co-committed-by: Anton Reinhard <anton.reinhard@proton.me>
2023-11-24 19:20:05 +01:00
04d5673b44 Use SafeTestsets for testing (#22)
Fixes issue #18

Reviewed-on: Rubydragon/MetagraphOptimization.jl#22
Co-authored-by: Anton Reinhard <anton.reinhard@proton.me>
Co-committed-by: Anton Reinhard <anton.reinhard@proton.me>
2023-11-22 16:01:17 +01:00
b7560685d4 Optimizer interface and sample implementation (#19)
Reviewed-on: Rubydragon/MetagraphOptimization.jl#19
Co-authored-by: Anton Reinhard <anton.reinhard@proton.me>
Co-committed-by: Anton Reinhard <anton.reinhard@proton.me>
2023-11-22 13:51:54 +01:00
16274919e4 Cost Estimation interface (#14)
See issue #13

Reviewed-on: Rubydragon/MetagraphOptimization.jl#14
Co-authored-by: Anton Reinhard <anton.reinhard@proton.me>
Co-committed-by: Anton Reinhard <anton.reinhard@proton.me>
2023-11-17 01:31:31 +01:00
2709eeb3dc Fix the types, add some profiling examples (#15)
Reviewed-on: Rubydragon/MetagraphOptimization.jl#15
Co-authored-by: Anton Reinhard <anton.reinhard@proton.me>
Co-committed-by: Anton Reinhard <anton.reinhard@proton.me>
2023-11-13 12:55:02 +01:00
5a30f57e1f Add scheduling, machine info, caching strategies and devices (#9)
Some checks failed
MetagraphOptimization_CI / prepare (push) Has been cancelled
MetagraphOptimization_CI / test (push) Has been cancelled
MetagraphOptimization_CI / docs (push) Has been cancelled
Reviewed-on: Rubydragon/MetagraphOptimization.jl#9
Co-authored-by: Anton Reinhard <anton.reinhard@proton.me>
Co-committed-by: Anton Reinhard <anton.reinhard@proton.me>
2023-10-12 17:51:03 +02:00
bd6c54c1ae Merge pull request 'Code Generation' (#8) from code-gen into main
Reviewed-on: Rubydragon/MetagraphOptimization.jl#8
2023-09-17 14:35:46 +02:00
62791ab422 Fix docs
Some checks failed
MetagraphOptimization_CI / prepare (push) Has been cancelled
MetagraphOptimization_CI / test (push) Has been cancelled
MetagraphOptimization_CI / docs (push) Has been cancelled
2023-09-17 12:40:11 +02:00
4c452dce98 Add execution test 2023-09-17 10:32:43 +02:00
27c4b8ba34 Use real ABC-Model compute effort and data transfer numbers 2023-09-07 18:46:41 +02:00
e59d24ebe5 Add code gen documentation 2023-09-07 18:23:36 +02:00
d1666de432 Add accurate arithmetic for summation, fix order of input particles 2023-09-07 16:49:44 +02:00
0f78053ccf Fix topoligical ordering on the graph 2023-09-05 12:14:41 +02:00
7a1a97dac8 Add basic execution function 2023-09-01 16:22:16 +02:00
f1edce258a Start adding code generation 2023-08-31 18:24:48 +02:00
32fcd069d7 Merge pull request 'Property Caching' (#7) from feature/property-tracking into main
Reviewed-on: Rubydragon/MetagraphOptimization.jl#7
2023-08-29 15:35:51 +02:00
e09ab7c77b Add tests 2023-08-29 13:09:33 +02:00
7387fa86b1 Add GraphProperties and property caching 2023-08-29 13:08:02 +02:00
065236be22 Add documentation to every function and automatic doc html building (#6)
Reviewed-on: Rubydragon/MetagraphOptimization.jl#6
Co-authored-by: Anton Reinhard <anton.reinhard@proton.me>
Co-committed-by: Anton Reinhard <anton.reinhard@proton.me>
2023-08-29 12:57:46 +02:00
8014bbffcd Merge pull request 'More Validation' (#5) from test into main
Reviewed-on: Rubydragon/MetagraphOptimization.jl#5
2023-08-25 11:05:17 +02:00
ae1345d547 Add formatter
Some checks failed
Test / test (push) Has been cancelled
2023-08-25 10:48:22 +02:00
dbcd569967 Update Julia in CI and dependencies 2023-08-25 10:24:37 +02:00
0f5f475cb4 Shuffle files and functions around for more consistent naming and smaller files 2023-08-24 15:11:54 +02:00
1b4030d633 Add validity checks to tests 2023-08-24 14:44:21 +02:00
383c92ec47 Merge pull request 'Performance Improvements' (#4) from performance into main
Reviewed-on: Rubydragon/MetagraphOptimization.jl#4
2023-08-24 11:33:06 +02:00
15fe8ed0f5 Add *.mem files to gitignore
Some checks failed
Test / test (push) Has been cancelled
2023-08-23 22:48:24 +02:00
c365233ea4 Rework node operations storage, remove make_edge from insert_edge calls 2023-08-23 19:28:45 +02:00
a81aafbf20 Merge pull request 'Add node reduction tests' (#3) from test into main
Reviewed-on: Rubydragon/MetagraphOptimization.jl#3
2023-08-23 13:56:43 +02:00
e44ef77ba4 Move input text files 2023-08-23 13:38:02 +02:00
92f59110ed Add node reduction unit test and fix bugs 2023-08-23 12:51:28 +02:00
569949d5c7 Merge pull request 'Performance Improvements and Multi-Threading' (#2) from performance into main
Reviewed-on: Rubydragon/MetagraphOptimization.jl#2
2023-08-23 10:47:33 +02:00
3454370a37 Multithreaded Node Reduction inserttion 2023-08-22 13:26:24 +02:00
45e35dd526 Add bench script 2023-08-22 10:29:59 +02:00
a7fb15c95b Multithreading for Node Reductions 2023-08-21 16:56:27 +02:00
2e96e6520e Some file reordering and parallelization work 2023-08-21 12:54:45 +02:00
895e4b2a12 Start multithreading 2023-08-21 10:29:00 +02:00
9cac6e76be Improve parsing performance and get_operations 2023-08-18 17:18:01 +02:00
1d0511ecb7 Merge pull request 'Refactor' (#1) from refactoring into main
Reviewed-on: Rubydragon/MetagraphOptimization.jl#1
2023-08-18 12:17:27 +02:00
150 changed files with 11589 additions and 1762 deletions

13
.JuliaFormatter.toml Normal file
View File

@ -0,0 +1,13 @@
indent = 4
margin = 120
always_for_in = true
for_in_replacement = "in"
whitespace_typedefs = true
whitespace_ops_in_indices = true
long_to_short_function_def = false
always_use_return = true
whitespace_in_kwargs = true
conditional_to_if = true
normalize_line_endings = "unix"
overwrite = true

4
.gitattributes vendored
View File

@ -1,2 +1,2 @@
examples/AB->ABBBBBBB.txt filter=lfs diff=lfs merge=lfs -text
examples/AB->ABBBBBBBBB.txt filter=lfs diff=lfs merge=lfs -text
input/AB->ABBBBBBBBB.txt filter=lfs diff=lfs merge=lfs -text
input/AB->ABBBBBBB.txt filter=lfs diff=lfs merge=lfs -text

View File

@ -1,33 +1,78 @@
name: Test
name: MetagraphOptimization_CI
on: [push]
env:
# keep the depot directly in the repository for the cache
JULIA_DEPOT_PATH: './.julia'
jobs:
test:
runs-on: arch-latest
runs-on: ubuntu-22.04
steps:
#- name: Get git-lfs
# run: apt-get update && apt-get install git-lfs
- name: Checkout repository
uses: actions/checkout@v3
with:
fetch-depth: 0
#- name: Checkout LFS objects
# run: git lfs checkout
- name: Setup Julia environment
uses: https://github.com/julia-actions/setup-julia@v1.9.1
uses: https://github.com/julia-actions/setup-julia@v1.9.2
with:
version: '1.9.1'
version: '1.9.2'
- name: Install dependencies
run: julia --project -e 'import Pkg; Pkg.instantiate()'
- name: Instantiate
run: julia --project=./ -e 'using Pkg; Pkg.instantiate()'
- name: Format check
run: |
julia --project=./ -e 'using JuliaFormatter; format(".", verbose=true, ignore=[".julia/*"])'
julia --project=./ -e '
out = Cmd(`git diff --name-only`) |> read |> String
if out == ""
exit(0)
else
@error "Some files have not been formatted !!!"
write(stdout, out)
exit(1)
end'
- name: Run tests
run: julia --project -e 'import Pkg; Pkg.test()'
run: julia --project=./ -t 4 -e 'using Pkg; Pkg.test()' -O0
- name: Run examples
run: julia --project=examples/ -e 'import Pkg; Pkg.develop(Pkg.PackageSpec(path=pwd())); Pkg.instantiate(); include("examples/import_bench.jl")'
run: |
julia --project=examples/ -e 'using Pkg; Pkg.develop(Pkg.PackageSpec(path=pwd())); Pkg.instantiate(); Pkg.precompile()'
julia --project=examples/ -t 4 -e 'include("examples/import_bench.jl")' -O3
docs:
runs-on: ubuntu-22.04
steps:
- name: Checkout repository
uses: actions/checkout@v3
with:
fetch-depth: 0
- name: Setup Julia environment
uses: https://github.com/julia-actions/setup-julia@v1.9.2
with:
version: '1.9.2'
- name: Build docs
run: |
julia --project=docs/ -e 'using Pkg; Pkg.develop(Pkg.PackageSpec(path=pwd())); Pkg.instantiate(); Pkg.precompile()'
julia --project=docs/ docs/make.jl
- name: Upload artifacts
uses: actions/upload-artifact@v3
with:
name: web-doc
path: docs/build/
#- name: Webhook Trigger
# uses: https://github.com/zzzze/webhook-trigger@master
# continue-on-error: true
# with:
# data: "{\"event\":\"action_completed\", \"download_url\":\"deckardcain.local:8099/something\"}"
# webhook_url: ${{ secrets.WEBHOOK_URL }}

9
.gitignore vendored
View File

@ -1,10 +1,10 @@
# ---> Julia
# Files generated by invoking Julia with --code-coverage
*.jl.cov
*.jl.*.cov
*.cov
*.cov
# Files generated by invoking Julia with --track-allocation
*.jl.mem
*.mem
# System-specific files and directories generated by the BinaryProvider and BinDeps packages
# They contain absolute paths specific to the host computer, and so should not be committed
@ -26,3 +26,6 @@ Manifest.toml
# vscode workspace directory
.vscode
.julia
**/.ipynb_checkpoints/
*.bkp

View File

@ -4,9 +4,17 @@ authors = ["Anton Reinhard <anton.reinhard@proton.me>"]
version = "0.1.0"
[deps]
AccurateArithmetic = "22286c92-06ac-501d-9306-4abd417d9753"
CUDA = "052768ef-5323-5732-b1bb-66c8b64840ba"
DataStructures = "864edb3b-99cc-5e75-8d2d-829cb0a9cfe8"
Printf = "de0858da-6303-5e67-8744-51eddeeeb8d7"
ForwardDiff = "f6369f11-7733-5829-9624-2563aa707210"
JuliaFormatter = "98e50ef6-434e-11e9-1051-2b60c6c9e899"
KernelAbstractions = "63c18a36-062a-441e-b654-da1e3ab1ce7c"
NumaAllocators = "21436f30-1b4a-4f08-87af-e26101bb5379"
QEDbase = "10e22c08-3ccb-4172-bfcf-7d7aa3d04d93"
QEDprocesses = "46de9c38-1bb3-4547-a1ec-da24d767fdad"
Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c"
Roots = "f2b01f46-fcfa-551c-844a-d8ac1e96c665"
UUIDs = "cf7118a7-6976-5b1a-9a39-7adc72f591a4"
[extras]

View File

@ -4,15 +4,17 @@ Directed Acyclic Graph optimization for QED
## Usage
For all the julia calls, use `-t n` to give julia `n` threads.
Instantiate the project first:
`julia --project -e 'import Pkg; Pkg.instantiate()'`
`julia --project=./ -e 'import Pkg; Pkg.instantiate()'`
### Run Tests
To run all tests, run
`julia --project=. -e 'import Pkg; Pkg.test()'`
`julia --project=./ -e 'import Pkg; Pkg.test()' -O0`
### Run Examples
@ -22,7 +24,7 @@ Get the correct environment for the examples folder:
Then execute a specific example:
`julia --project=examples examples/<file>.jl`
`julia --project=examples examples/<file>.jl -O3`
## Concepts
@ -40,7 +42,7 @@ Problems:
- Lots of testing required because mistakes will propagate and multiply.
## Other TODOs
- Reduce memory footprint of the graph, are the UUIDs too large?
- Reduce memory footprint of the graph
- Memory layout of Nodes? They should lie linearly in memory, right now probably on heap?
- Add scaling functions
@ -48,18 +50,18 @@ Problems:
For graphs AB->AB^n:
- Number of Sums should always be 1
- Number of ComputeTaskS2 should always be (n+1)!
- Number of ComputeTaskU should always be (n+3)
- Number of ComputeTaskABC_S2 should always be (n+1)!
- Number of ComputeTaskABC_U should always be (n+3)
Times are from my home machine: AMD Ryzen 7900X3D, 64GB DDR5 RAM @ 6000MHz
Times are from my home machine: AMD Ryzen 7900X3D, 64GB DDR5 RAM @ 6000MHz (not necessarily up to date, check Jupyter Notebooks in `notebooks/` instead)
```
$ julia --project examples/import_bench.jl
AB->AB:
Graph:
Nodes: Total: 34, DataTask: 19, ComputeTaskP: 4,
ComputeTaskS2: 2, ComputeTaskV: 4, ComputeTaskU: 4,
ComputeTaskSum: 1
Nodes: Total: 34, DataTask: 19, ComputeTaskABC_P: 4,
ComputeTaskABC_S2: 2, ComputeTaskABC_V: 4, ComputeTaskABC_U: 4,
ComputeTaskABC_Sum: 1
Edges: 37
Total Compute Effort: 185
Total Data Transfer: 102
@ -69,9 +71,9 @@ Graph:
AB->ABBB:
Graph:
Nodes: Total: 280, DataTask: 143, ComputeTaskP: 6,
ComputeTaskS2: 24, ComputeTaskV: 64, ComputeTaskU: 6,
ComputeTaskSum: 1, ComputeTaskS1: 36
Nodes: Total: 280, DataTask: 143, ComputeTaskABC_P: 6,
ComputeTaskABC_S2: 24, ComputeTaskABC_V: 64, ComputeTaskABC_U: 6,
ComputeTaskABC_Sum: 1, ComputeTaskABC_S1: 36
Edges: 385
Total Compute Effort: 2007
Total Data Transfer: 828
@ -81,9 +83,9 @@ Graph:
AB->ABBBBB:
Graph:
Nodes: Total: 7854, DataTask: 3931, ComputeTaskP: 8,
ComputeTaskS2: 720, ComputeTaskV: 1956, ComputeTaskU: 8,
ComputeTaskSum: 1, ComputeTaskS1: 1230
Nodes: Total: 7854, DataTask: 3931, ComputeTaskABC_P: 8,
ComputeTaskABC_S2: 720, ComputeTaskABC_V: 1956, ComputeTaskABC_U: 8,
ComputeTaskABC_Sum: 1, ComputeTaskABC_S1: 1230
Edges: 11241
Total Compute Effort: 58789
Total Data Transfer: 23244
@ -93,9 +95,9 @@ Graph:
AB->ABBBBBBB:
Graph:
Nodes: Total: 438436, DataTask: 219223, ComputeTaskP: 10,
ComputeTaskS2: 40320, ComputeTaskV: 109600, ComputeTaskU: 10,
ComputeTaskSum: 1, ComputeTaskS1: 69272
Nodes: Total: 438436, DataTask: 219223, ComputeTaskABC_P: 10,
ComputeTaskABC_S2: 40320, ComputeTaskABC_V: 109600, ComputeTaskABC_U: 10,
ComputeTaskABC_Sum: 1, ComputeTaskABC_S1: 69272
Edges: 628665
Total Compute Effort: 3288131
Total Data Transfer: 1297700
@ -105,7 +107,7 @@ Graph:
AB->ABBBBBBBBB:
Graph:
Nodes: Total: 39456442, DataTask: 19728227, ComputeTaskS1: 6235290, ComputeTaskP: 12, ComputeTaskU: 12, ComputeTaskV: 9864100, ComputeTaskS2: 3628800, ComputeTaskSum: 1
Nodes: Total: 39456442, DataTask: 19728227, ComputeTaskABC_S1: 6235290, ComputeTaskABC_P: 12, ComputeTaskABC_U: 12, ComputeTaskABC_V: 9864100, ComputeTaskABC_S2: 3628800, ComputeTaskABC_Sum: 1
Edges: 56578129
Total Compute Effort: 295923153
Total Data Transfer: 175407750
@ -114,9 +116,9 @@ Graph:
ABAB->ABAB:
Graph:
Nodes: Total: 3218, DataTask: 1613, ComputeTaskP: 8,
ComputeTaskS2: 288, ComputeTaskV: 796, ComputeTaskU: 8,
ComputeTaskSum: 1, ComputeTaskS1: 504
Nodes: Total: 3218, DataTask: 1613, ComputeTaskABC_P: 8,
ComputeTaskABC_S2: 288, ComputeTaskABC_V: 796, ComputeTaskABC_U: 8,
ComputeTaskABC_Sum: 1, ComputeTaskABC_S1: 504
Edges: 4581
Total Compute Effort: 24009
Total Data Transfer: 9494
@ -126,9 +128,9 @@ Graph:
ABAB->ABC:
Graph:
Nodes: Total: 817, DataTask: 412, ComputeTaskP: 7,
ComputeTaskS2: 72, ComputeTaskV: 198, ComputeTaskU: 7,
ComputeTaskSum: 1, ComputeTaskS1: 120
Nodes: Total: 817, DataTask: 412, ComputeTaskABC_P: 7,
ComputeTaskABC_S2: 72, ComputeTaskABC_V: 198, ComputeTaskABC_U: 7,
ComputeTaskABC_Sum: 1, ComputeTaskABC_S1: 120
Edges: 1151
Total Compute Effort: 6028
Total Data Transfer: 2411

4
docs/Project.toml Normal file
View File

@ -0,0 +1,4 @@
[deps]
Documenter = "e30172f5-a6a5-5a46-863b-614d45cd2de4"
DocumenterTools = "35a29f4d-8980-5a13-9543-d66fff28ecb8"
MetagraphOptimization = "3e869610-d48d-4942-ba70-c1b702a33ca4"

34
docs/make.jl Normal file
View File

@ -0,0 +1,34 @@
using Documenter
using MetagraphOptimization
makedocs(
#format = Documenter.LaTeX(platform=""),
root = "docs",
source = "src",
build = "build",
warnonly = true,
clean = true,
doctest = true,
modules = Module[MetagraphOptimization],
#repo = "https://code.woubery.com/Rubydragon/MetagraphOptimization.jl/src/branch/{commit}{path}#L{line}",
remotes = nothing,
sitename = "MetagraphOptimization.jl",
pages = [
"index.md",
"Manual" => "manual.md",
"Library" => [
"Public" => "lib/public.md",
"Graph" => "lib/internals/graph.md",
"Node" => "lib/internals/node.md",
"Task" => "lib/internals/task.md",
"Operation" => "lib/internals/operation.md",
"Models" => "lib/internals/models.md",
"Diff" => "lib/internals/diff.md",
"Utility" => "lib/internals/utility.md",
"Code Generation" => "lib/internals/code_gen.md",
"Devices" => "lib/internals/devices.md",
],
"Contribution" => "contribution.md",
],
)

View File

@ -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>

View File

@ -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>

3
docs/src/contribution.md Normal file
View File

@ -0,0 +1,3 @@
# Contribution
This is currently in development for a diploma thesis and is therefore private and impossible to contribute to.

75
docs/src/flowchart.drawio Normal file
View File

@ -0,0 +1,75 @@
<mxfile host="Electron" modified="2023-09-17T13:34:45.840Z" agent="Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) draw.io/21.6.1 Chrome/114.0.5735.134 Electron/25.6.0 Safari/537.36" etag="e0c8qLevhaP_q_R2fyC9" version="21.6.1" type="device">
<diagram name="Page-1" id="Vy0cA1nkMPfy-3cC5ahA">
<mxGraphModel dx="1185" dy="707" 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="yG8qeggDCLqQ8GwY7ugi-5" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;shadow=1;" edge="1" parent="1" source="yG8qeggDCLqQ8GwY7ugi-1" target="yG8qeggDCLqQ8GwY7ugi-2">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="yG8qeggDCLqQ8GwY7ugi-1" value="Process Generator Script" style="rounded=1;whiteSpace=wrap;html=1;shadow=1;" vertex="1" parent="1">
<mxGeometry x="180" y="120" width="120" height="60" as="geometry" />
</mxCell>
<mxCell id="yG8qeggDCLqQ8GwY7ugi-11" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;shadow=1;" edge="1" parent="1" source="yG8qeggDCLqQ8GwY7ugi-2" target="yG8qeggDCLqQ8GwY7ugi-3">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="yG8qeggDCLqQ8GwY7ugi-2" value="Process Parser" style="rounded=1;whiteSpace=wrap;html=1;shadow=1;" vertex="1" parent="1">
<mxGeometry x="180" y="220" width="120" height="60" as="geometry" />
</mxCell>
<mxCell id="yG8qeggDCLqQ8GwY7ugi-8" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=1;exitY=0.25;exitDx=0;exitDy=0;entryX=0;entryY=0.25;entryDx=0;entryDy=0;shadow=1;" edge="1" parent="1" source="yG8qeggDCLqQ8GwY7ugi-3" target="yG8qeggDCLqQ8GwY7ugi-6">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="yG8qeggDCLqQ8GwY7ugi-14" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;shadow=1;" edge="1" parent="1" source="yG8qeggDCLqQ8GwY7ugi-3" target="yG8qeggDCLqQ8GwY7ugi-12">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="yG8qeggDCLqQ8GwY7ugi-3" value="Optimizer" style="rounded=1;whiteSpace=wrap;html=1;shadow=1;" vertex="1" parent="1">
<mxGeometry x="180" y="320" width="120" height="60" as="geometry" />
</mxCell>
<mxCell id="yG8qeggDCLqQ8GwY7ugi-9" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;entryX=1;entryY=0.75;entryDx=0;entryDy=0;exitX=0;exitY=0.75;exitDx=0;exitDy=0;shadow=1;" edge="1" parent="1" source="yG8qeggDCLqQ8GwY7ugi-6" target="yG8qeggDCLqQ8GwY7ugi-3">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="yG8qeggDCLqQ8GwY7ugi-6" value="Fast Cost Estimator&lt;br&gt;(Global Metrics)" style="rounded=1;whiteSpace=wrap;html=1;shadow=1;" vertex="1" parent="1">
<mxGeometry x="340" y="320" width="120" height="60" as="geometry" />
</mxCell>
<mxCell id="yG8qeggDCLqQ8GwY7ugi-15" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;shadow=1;" edge="1" parent="1" source="yG8qeggDCLqQ8GwY7ugi-12" target="yG8qeggDCLqQ8GwY7ugi-13">
<mxGeometry relative="1" as="geometry">
<Array as="points">
<mxPoint x="80" y="450" />
</Array>
</mxGeometry>
</mxCell>
<mxCell id="yG8qeggDCLqQ8GwY7ugi-12" value="Scheduler" style="rounded=1;whiteSpace=wrap;html=1;shadow=1;" vertex="1" parent="1">
<mxGeometry x="180" y="420" width="120" height="60" as="geometry" />
</mxCell>
<mxCell id="yG8qeggDCLqQ8GwY7ugi-16" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;entryX=0;entryY=0.5;entryDx=0;entryDy=0;shadow=1;" edge="1" parent="1" source="yG8qeggDCLqQ8GwY7ugi-13" target="yG8qeggDCLqQ8GwY7ugi-3">
<mxGeometry relative="1" as="geometry">
<mxPoint x="120" y="380" as="targetPoint" />
<Array as="points">
<mxPoint x="80" y="350" />
</Array>
</mxGeometry>
</mxCell>
<mxCell id="yG8qeggDCLqQ8GwY7ugi-19" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.5;exitY=1;exitDx=0;exitDy=0;shadow=1;" edge="1" parent="1" source="yG8qeggDCLqQ8GwY7ugi-12" target="yG8qeggDCLqQ8GwY7ugi-18">
<mxGeometry relative="1" as="geometry">
<Array as="points">
<mxPoint x="240" y="500" />
<mxPoint x="240" y="500" />
</Array>
</mxGeometry>
</mxCell>
<mxCell id="yG8qeggDCLqQ8GwY7ugi-13" value="Accurate Cost Estimator&lt;br&gt;(Machine Specific)" style="rounded=1;whiteSpace=wrap;html=1;shadow=1;" vertex="1" parent="1">
<mxGeometry x="20" y="370" width="120" height="60" as="geometry" />
</mxCell>
<mxCell id="yG8qeggDCLqQ8GwY7ugi-21" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;shadow=1;" edge="1" parent="1" source="yG8qeggDCLqQ8GwY7ugi-18" target="yG8qeggDCLqQ8GwY7ugi-20">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="yG8qeggDCLqQ8GwY7ugi-18" value="Code Generator" style="rounded=1;whiteSpace=wrap;html=1;shadow=1;" vertex="1" parent="1">
<mxGeometry x="180" y="520" width="120" height="60" as="geometry" />
</mxCell>
<mxCell id="yG8qeggDCLqQ8GwY7ugi-20" value="Executor" style="rounded=1;whiteSpace=wrap;html=1;shadow=1;" vertex="1" parent="1">
<mxGeometry x="180" y="620" width="120" height="60" as="geometry" />
</mxCell>
</root>
</mxGraphModel>
</diagram>
</mxfile>

26
docs/src/index.md Normal file
View File

@ -0,0 +1,26 @@
# MetagraphOptimization.jl
*A domain-specific DAG-optimizer*
## Package Features
- Read a DAG from a file
- Analyze its properties
- Mute the graph using the operations NodeFusion, NodeReduction and NodeSplit
## Coming Soon:
- Add Code Generation from finished DAG
- Add optimization algorithms and strategies
## Library Outline
```@contents
Pages = [
"lib/public.md",
"lib/internals.md"
]
```
### [Index](@id main-index)
```@index
Pages = ["lib/public.md"]
```

View File

@ -0,0 +1,8 @@
# Code Generation
## Main
```@autodocs
Modules = [MetagraphOptimization]
Pages = ["code_gen/main.jl"]
Order = [:function]
```

View File

@ -0,0 +1,59 @@
# Devices
## Interface
```@autodocs
Modules = [MetagraphOptimization]
Pages = ["devices/interface.jl"]
Order = [:type, :constant, :function]
```
## Detect
```@autodocs
Modules = [MetagraphOptimization]
Pages = ["devices/detect.jl"]
Order = [:function]
```
## Measure
```@autodocs
Modules = [MetagraphOptimization]
Pages = ["devices/measure.jl"]
Order = [:function]
```
## Implementations
### General
```@autodocs
Modules = [MetagraphOptimization]
Pages = ["devices/impl.jl"]
Order = [:type, :function]
```
### NUMA
```@autodocs
Modules = [MetagraphOptimization]
Pages = ["devices/numa/impl.jl"]
Order = [:type, :function]
```
### CUDA
```@autodocs
Modules = [MetagraphOptimization]
Pages = ["devices/cuda/impl.jl"]
Order = [:type, :function]
```
### ROCm
```@autodocs
Modules = [MetagraphOptimization]
Pages = ["devices/rocm/impl.jl"]
Order = [:type, :function]
```
### oneAPI
```@autodocs
Modules = [MetagraphOptimization]
Pages = ["devices/oneapi/impl.jl"]
Order = [:type, :function]
```

View File

@ -0,0 +1,22 @@
# Diff
## Type
```@autodocs
Modules = [MetagraphOptimization]
Pages = ["diff/type.jl"]
Order = [:type]
```
## Properties
```@autodocs
Modules = [MetagraphOptimization]
Pages = ["diff/properties.jl"]
Order = [:function]
```
## Printing
```@autodocs
Modules = [MetagraphOptimization]
Pages = ["diff/print.jl"]
Order = [:function]
```

View File

@ -0,0 +1,21 @@
# Estimation
## Interface
The interface that has to be implemented for an estimator.
```@autodocs
Modules = [MetagraphOptimization]
Pages = ["estimator/interafce.jl"]
Order = [:type, :constant, :function]
```
## Global Metric Estimator
Implementation of a global metric estimator. It uses the graph properties compute effort, data transfer, and compute intensity.
```@autodocs
Modules = [MetagraphOptimization]
Pages = ["estimator/global_metric.jl"]
Order = [:type, :function]
```

View File

@ -0,0 +1,50 @@
# Graph
## Type
```@autodocs
Modules = [MetagraphOptimization]
Pages = ["graph/type.jl"]
Order = [:type]
```
## Interface
```@autodocs
Modules = [MetagraphOptimization]
Pages = ["graph/interface.jl"]
Order = [:function]
```
## Compare
```@autodocs
Modules = [MetagraphOptimization]
Pages = ["graph/compare.jl"]
Order = [:function]
```
## Mute
```@autodocs
Modules = [MetagraphOptimization]
Pages = ["graph/mute.jl"]
Order = [:function]
```
## Print
```@autodocs
Modules = [MetagraphOptimization]
Pages = ["graph/print.jl"]
Order = [:function]
```
## Properties
```@autodocs
Modules = [MetagraphOptimization]
Pages = ["graph/properties.jl"]
Order = [:function]
```
## Validate
```@autodocs
Modules = [MetagraphOptimization]
Pages = ["graph/validate.jl"]
Order = [:function]
```

View File

@ -0,0 +1,126 @@
# Models
## Interface
The interface that has to be implemented for a model to be usable is defined in `src/models/interface.jl`.
```@autodocs
Modules = [MetagraphOptimization]
Pages = ["models/interface.jl"]
Order = [:type, :constant, :function]
```
```@autodocs
Modules = [MetagraphOptimization]
Pages = ["models/print.jl"]
Order = [:function]
```
## ABC-Model
### Types
```@autodocs
Modules = [MetagraphOptimization]
Pages = ["models/abc/types.jl"]
Order = [:type, :constant]
```
### Particle
```@autodocs
Modules = [MetagraphOptimization]
Pages = ["models/abc/particle.jl"]
Order = [:type, :constant, :function]
```
### Parse
```@autodocs
Modules = [MetagraphOptimization]
Pages = ["models/abc/parse.jl"]
Order = [:function]
```
### Properties
```@autodocs
Modules = [MetagraphOptimization]
Pages = ["models/abc/properties.jl"]
Order = [:function]
```
### Create
```@autodocs
Modules = [MetagraphOptimization]
Pages = ["models/abc/create.jl"]
Order = [:function]
```
### Compute
```@autodocs
Modules = [MetagraphOptimization]
Pages = ["models/abc/compute.jl"]
Order = [:function]
```
### Print
```@autodocs
Modules = [MetagraphOptimization]
Pages = ["models/abc/print.jl"]
Order = [:function]
```
## QED-Model
### Feynman Diagrams
```@autodocs
Modules = [MetagraphOptimization]
Pages = ["models/qed/diagrams.jl"]
Order = [:type, :function, :constant]
```
### Types
```@autodocs
Modules = [MetagraphOptimization]
Pages = ["models/qed/types.jl"]
Order = [:type, :constant]
```
### Particle
```@autodocs
Modules = [MetagraphOptimization]
Pages = ["models/qed/particle.jl"]
Order = [:type, :constant, :function]
```
### Parse
```@autodocs
Modules = [MetagraphOptimization]
Pages = ["models/qed/parse.jl"]
Order = [:function]
```
### Properties
```@autodocs
Modules = [MetagraphOptimization]
Pages = ["models/qed/properties.jl"]
Order = [:function]
```
### Create
```@autodocs
Modules = [MetagraphOptimization]
Pages = ["models/qed/create.jl"]
Order = [:function]
```
### Compute
```@autodocs
Modules = [MetagraphOptimization]
Pages = ["models/qed/compute.jl"]
Order = [:function]
```
### Print
```@autodocs
Modules = [MetagraphOptimization]
Pages = ["models/qed/print.jl"]
Order = [:function]
```

View File

@ -0,0 +1,43 @@
# Node
## Type
```@autodocs
Modules = [MetagraphOptimization]
Pages = ["node/type.jl"]
Order = [:type]
```
## Create
```@autodocs
Modules = [MetagraphOptimization]
Pages = ["node/create.jl"]
Order = [:function]
```
## Compare
```@autodocs
Modules = [MetagraphOptimization]
Pages = ["node/compare.jl"]
Order = [:function]
```
## Properties
```@autodocs
Modules = [MetagraphOptimization]
Pages = ["node/properties.jl"]
Order = [:function]
```
## Print
```@autodocs
Modules = [MetagraphOptimization]
Pages = ["node/print.jl"]
Order = [:function]
```
## Validate
```@autodocs
Modules = [MetagraphOptimization]
Pages = ["node/validate.jl"]
Order = [:function]
```

View File

@ -0,0 +1,57 @@
# Operation
## Types
```@autodocs
Modules = [MetagraphOptimization]
Pages = ["operation/type.jl"]
Order = [:type]
```
## Find
```@autodocs
Modules = [MetagraphOptimization]
Pages = ["operation/find.jl"]
Order = [:function]
```
## Apply
```@autodocs
Modules = [MetagraphOptimization]
Pages = ["operation/apply.jl"]
Order = [:function]
```
## Get
```@autodocs
Modules = [MetagraphOptimization]
Pages = ["operation/get.jl"]
Order = [:function]
```
## Clean
```@autodocs
Modules = [MetagraphOptimization]
Pages = ["operation/clean.jl"]
Order = [:function]
```
## Utility
```@autodocs
Modules = [MetagraphOptimization]
Pages = ["operation/utility.jl"]
Order = [:function]
```
## Print
```@autodocs
Modules = [MetagraphOptimization]
Pages = ["operation/print.jl"]
Order = [:function]
```
## Validate
```@autodocs
Modules = [MetagraphOptimization]
Pages = ["operation/validate.jl"]
Order = [:function]
```

View File

@ -0,0 +1,41 @@
# Optimization
## Interface
The interface that has to be implemented for an optimization algorithm.
```@autodocs
Modules = [MetagraphOptimization]
Pages = ["optimization/interafce.jl"]
Order = [:type, :constant, :function]
```
## Random Walk Optimizer
Implementation of a random walk algorithm.
```@autodocs
Modules = [MetagraphOptimization]
Pages = ["estimator/random_walk.jl"]
Order = [:type, :function]
```
## Reduction Optimizer
Implementation of a an optimizer that reduces as far as possible.
```@autodocs
Modules = [MetagraphOptimization]
Pages = ["estimator/reduce.jl"]
Order = [:type, :function]
```
## Greedy Optimizer
Implementation of a greedy optimization algorithm.
```@autodocs
Modules = [MetagraphOptimization]
Pages = ["estimator/greedy.jl"]
Order = [:type, :function]
```

View File

@ -0,0 +1,22 @@
# Properties
## Type
```@autodocs
Modules = [MetagraphOptimization]
Pages = ["properties/type.jl"]
Order = [:type]
```
## Create
```@autodocs
Modules = [MetagraphOptimization]
Pages = ["properties/create.jl"]
Order = [:function]
```
## Utility
```@autodocs
Modules = [MetagraphOptimization]
Pages = ["properties/utility.jl"]
Order = [:function]
```

View File

@ -0,0 +1,15 @@
# Scheduler
## Interface
```@autodocs
Modules = [MetagraphOptimization]
Pages = ["scheduler/interface.jl"]
Order = [:type, :function]
```
## Greedy
```@autodocs
Modules = [MetagraphOptimization]
Pages = ["scheduler/greedy.jl"]
Order = [:type, :function]
```

View File

@ -0,0 +1,43 @@
# Task
## Type
```@autodocs
Modules = [MetagraphOptimization]
Pages = ["task/type.jl"]
Order = [:type]
```
## Create
```@autodocs
Modules = [MetagraphOptimization]
Pages = ["task/create.jl"]
Order = [:function]
```
## Compare
```@autodocs
Modules = [MetagraphOptimization]
Pages = ["task/compare.jl"]
Order = [:function]
```
## Compute
```@autodocs
Modules = [MetagraphOptimization]
Pages = ["task/compute.jl"]
Order = [:function]
```
## Properties
```@autodocs
Modules = [MetagraphOptimization]
Pages = ["task/properties.jl"]
Order = [:function]
```
## Print
```@autodocs
Modules = [MetagraphOptimization]
Pages = ["task/print.jl"]
Order = [:function]
```

View File

@ -0,0 +1,17 @@
# Utility
## Helper Functions
```@autodocs
Modules = [MetagraphOptimization]
Pages = ["./utility.jl"]
Order = [:type, :function]
```
## Trie Helper
This is a simple implementation of a [Trie Data Structure](https://en.wikipedia.org/wiki/Trie) to greatly improve the performance of the Node Reduction search.
```@autodocs
Modules = [MetagraphOptimization]
Pages = ["trie.jl"]
Order = [:type, :function]
```

24
docs/src/lib/public.md Normal file
View File

@ -0,0 +1,24 @@
# Public Documentation
Documentation for `MetagraphOptimization.jl`'s public interface.
See the Internals section of the manual for documentation of everything else.
```@autodocs
Modules = [MetagraphOptimization]
Pages = ["MetagraphOptimization.jl"]
Order = [:module]
```
## Contents
```@contents
Pages = ["public.md"]
Depth = 2
```
## Index
```@index
Pages = ["public.md"]
```

7
docs/src/manual.md Normal file
View File

@ -0,0 +1,7 @@
# Manual
## Jupyter Notebooks
In the `notebooks` directory are notebooks containing some examples of the usage of this repository.
- `abc_model_showcase`: A simple showcase of the intended usage of the ABC Model implementation.

File diff suppressed because one or more lines are too long

Binary file not shown.

View File

@ -1,5 +1,3 @@
[deps]
BenchmarkTools = "6e4b80f9-dd63-53aa-95a3-0cdb28fa8baf"
MetagraphOptimization = "3e869610-d48d-4942-ba70-c1b702a33ca4"
Plots = "91a5bcdd-55d7-5caf-9e0b-520d859cae80"
ProfileView = "c46f51b8-102a-5cf2-8d2c-8597cb0e0da7"

33
examples/ab5.jl Normal file
View File

@ -0,0 +1,33 @@
using MetagraphOptimization
using BenchmarkTools
println("Getting machine info")
@time machine = get_machine_info()
println("Making model")
@time model = ABCModel()
println("Making process")
process_str = "AB->ABBBBB"
@time process = parse_process(process_str, model)
println("Parsing DAG")
@time graph = parse_dag("input/$process_str.txt", model)
println("Generating input data")
@time input_data = [gen_process_input(process) for _ in 1:1000]
println("Reducing graph")
@time optimize_to_fixpoint!(ReductionOptimizer(), graph)
println("Generating compute function")
@time compute_func = get_compute_function(graph, process, machine)
println("First run, single argument")
@time compute_func(input_data[1])
println("\nBenchmarking function, 1 input")
display(@benchmark compute_func($(input_data[1])))
println("\nBenchmarking function, 1000 inputs")
display(@benchmark compute_func.($input_data))

33
examples/ab7.jl Normal file
View File

@ -0,0 +1,33 @@
using MetagraphOptimization
using BenchmarkTools
println("Getting machine info")
@time machine = get_machine_info()
println("Making model")
@time model = ABCModel()
println("Making process")
process_str = "AB->ABBBBBBB"
@time process = parse_process(process_str, model)
println("Parsing DAG")
@time graph = parse_dag("input/$process_str.txt", model)
println("Generating input data")
@time input_data = [gen_process_input(process) for _ in 1:1000]
println("Reducing graph")
@time optimize_to_fixpoint!(ReductionOptimizer(), graph)
println("Generating compute function")
@time compute_func = get_compute_function(graph, process, machine)
println("First run, single argument")
@time compute_func(input_data[1])
println("\nBenchmarking function, 1 input")
display(@benchmark compute_func($(input_data[1])))
println("\nBenchmarking function, 1000 inputs")
display(@benchmark compute_func.($input_data))

View File

@ -7,21 +7,26 @@ function bench_txt(filepath::String, bench::Bool = true)
name = basename(filepath)
name, _ = splitext(name)
filepath = joinpath(@__DIR__, filepath)
filepath = joinpath(@__DIR__, "../input/", filepath)
if !isfile(filepath)
println("File ", filepath, " does not exist, skipping bench")
return
end
model = ABCModel()
println(name, ":")
g = parse_abc(filepath)
g = parse_dag(filepath, model)
print(g)
println(" Graph size in memory: ", bytes_to_human_readable(Base.summarysize(g)))
println(" Graph size in memory: ", bytes_to_human_readable(MetagraphOptimization.mem(g)))
if (bench)
@btime parse_abc($filepath)
println()
@btime parse_dag($filepath, $model)
end
println(" Get Operations: ")
@time get_operations(g)
return println()
end
function import_bench()
@ -29,9 +34,9 @@ function import_bench()
bench_txt("AB->ABBB.txt")
bench_txt("AB->ABBBBB.txt")
bench_txt("AB->ABBBBBBB.txt")
#bench_txt("AB->ABBBBBBBBB.txt", false)
#bench_txt("AB->ABBBBBBBBB.txt")
bench_txt("ABAB->ABAB.txt")
bench_txt("ABAB->ABC.txt")
return bench_txt("ABAB->ABC.txt")
end
import_bench()

View File

@ -6,13 +6,13 @@ function gen_plot(filepath)
name = basename(filepath)
name, _ = splitext(name)
filepath = joinpath(@__DIR__, filepath)
filepath = joinpath(@__DIR__, "../input/", filepath)
if !isfile(filepath)
println("File ", filepath, " does not exist, skipping")
return
end
g = parse_abc(filepath)
g = parse_dag(filepath, ABCModel())
Random.seed!(1)
@ -21,7 +21,7 @@ function gen_plot(filepath)
x = Vector{Float64}()
y = Vector{Float64}()
for i = 1:30
for i in 1:30
print("\r", i)
# push
opt = get_operations(g)
@ -38,23 +38,23 @@ function gen_plot(filepath)
push_operation!(g, rand(collect(opt.nodeSplits)))
println("NS")
else
i = i-1
i = i - 1
end
props = graph_properties(g)
props = get_properties(g)
push!(x, props.data)
push!(y, props.compute_effort)
push!(y, props.computeEffort)
end
println("\rDone.")
plot([x[1], x[2]], [y[1], y[2]], linestyle = :solid, linewidth = 1, color = :red, legend=false)
plot([x[1], x[2]], [y[1], y[2]], linestyle = :solid, linewidth = 1, color = :red, legend = false)
# Create lines connecting the reference point to each data point
for i in 3:length(x)
plot!([x[i-1], x[i]], [y[i-1], y[i]], linestyle = :solid, linewidth = 1, color = :red)
plot!([x[i - 1], x[i]], [y[i - 1], y[i]], linestyle = :solid, linewidth = 1, color = :red)
end
gui()
return gui()
end
gen_plot("AB->ABBB.txt")

View File

@ -6,19 +6,19 @@ function gen_plot(filepath)
name = basename(filepath)
name, _ = splitext(name)
filepath = joinpath(@__DIR__, filepath)
filepath = joinpath(@__DIR__, "../input/", filepath)
if !isfile(filepath)
println("File ", filepath, " does not exist, skipping")
return
end
g = parse_abc(filepath)
g = parse_dag(filepath, ABCModel())
Random.seed!(1)
println("Random Walking... ")
for i = 1:30
for i in 1:30
print("\r", i)
# push
opt = get_operations(g)
@ -35,7 +35,7 @@ function gen_plot(filepath)
push_operation!(g, rand(collect(opt.nodeSplits)))
println("NS")
else
i = i-1
i = i - 1
end
end
@ -44,9 +44,9 @@ function gen_plot(filepath)
props = graph_properties(g)
props = get_properties(g)
x0 = props.data
y0 = props.compute_effort
y0 = props.computeEffort
x = Vector{Float64}()
y = Vector{Float64}()
@ -55,33 +55,33 @@ function gen_plot(filepath)
opt = get_operations(g)
for op in opt.nodeFusions
push_operation!(g, op)
props = graph_properties(g)
props = get_properties(g)
push!(x, props.data)
push!(y, props.compute_effort)
push!(y, props.computeEffort)
pop_operation!(g)
push!(names, "NF: (" * string(props.data) * ", " * string(props.compute_effort) * ")")
push!(names, "NF: (" * string(props.data) * ", " * string(props.computeEffort) * ")")
end
for op in opt.nodeReductions
push_operation!(g, op)
props = graph_properties(g)
props = get_properties(g)
push!(x, props.data)
push!(y, props.compute_effort)
push!(y, props.computeEffort)
pop_operation!(g)
push!(names, "NR: (" * string(props.data) * ", " * string(props.compute_effort) * ")")
push!(names, "NR: (" * string(props.data) * ", " * string(props.computeEffort) * ")")
end
for op in opt.nodeSplits
push_operation!(g, op)
props = graph_properties(g)
props = get_properties(g)
push!(x, props.data)
push!(y, props.compute_effort)
push!(y, props.computeEffort)
pop_operation!(g)
push!(names, "NS: (" * string(props.data) * ", " * string(props.compute_effort) * ")")
push!(names, "NS: (" * string(props.data) * ", " * string(props.computeEffort) * ")")
end
plot([x0, x[1]], [y0, y[1]], linestyle = :solid, linewidth = 1, color = :red, legend=false)
plot([x0, x[1]], [y0, y[1]], linestyle = :solid, linewidth = 1, color = :red, legend = false)
# Create lines connecting the reference point to each data point
for i in 2:length(x)
plot!([x0, x[i]], [y0, y[i]], linestyle = :solid, linewidth = 1, color = :red)
@ -90,7 +90,7 @@ function gen_plot(filepath)
print(names)
gui()
return gui()
end
gen_plot("AB->ABBB.txt")

View File

@ -1,36 +0,0 @@
function test_random_walk(g::DAG, n::Int64)
# the purpose here is to do "random" operations and reverse them again and validate that the graph stays the same and doesn't diverge
reset_graph!(g)
properties = graph_properties(g)
for i = 1:n
# choose push or pop
if rand(Bool)
# push
opt = get_operations(g)
# choose one of fuse/split/reduce
option = rand(1:3)
if option == 1 && !isempty(opt.nodeFusions)
push_operation!(g, rand(collect(opt.nodeFusions)))
elseif option == 2 && !isempty(opt.nodeReductions)
push_operation!(g, rand(collect(opt.nodeReductions)))
elseif option == 3 && !isempty(opt.nodeSplits)
push_operation!(g, rand(collect(opt.nodeSplits)))
else
i = i - 1
end
else
# pop
if (can_pop(g))
pop_operation!(g)
else
i = i - 1
end
end
end
reset_graph!(g)
end

BIN
input/AB->ABBBBBBBBB.txt (Stored with Git LFS) Normal file

Binary file not shown.

View File

@ -0,0 +1,429 @@
{
"cells": [
{
"cell_type": "code",
"execution_count": 1,
"metadata": {},
"outputs": [],
"source": [
"using MetagraphOptimization"
]
},
{
"cell_type": "code",
"execution_count": 11,
"metadata": {},
"outputs": [],
"source": [
"# Get machine and set dictionary caching strategy\n",
"machine = get_machine_info()\n",
"MetagraphOptimization.set_cache_strategy(machine.devices[1], MetagraphOptimization.LocalVariables())"
]
},
{
"cell_type": "code",
"execution_count": 12,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Graph:\n",
" Nodes: Total: 7854, DataTask: 3931, ComputeTaskABC_S1: 1230, \n",
" ComputeTaskABC_Sum: 1, ComputeTaskABC_U: 8, ComputeTaskABC_P: 8, \n",
" ComputeTaskABC_V: 1956, ComputeTaskABC_S2: 720\n",
" Edges: 11241\n",
" Total Compute Effort: 33915.0\n",
" Total Data Transfer: 322464.0\n",
" Total Compute Intensity: 0.10517453111044954\n"
]
}
],
"source": [
"model = ABCModel()\n",
"process_str = \"AB->ABBBBB\"\n",
"process = parse_process(process_str, model)\n",
"graph = parse_dag(\"../input/$process_str.txt\", model)\n",
"print(graph)"
]
},
{
"cell_type": "code",
"execution_count": 13,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"compute__8bced4be_8f2e_11ee_37d9_3f851690d249 (generic function with 1 method)"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"compute_AB_AB5 = get_compute_function(graph, process, machine)"
]
},
{
"cell_type": "code",
"execution_count": 14,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
" 0.184484 seconds (2.75 M allocations: 153.561 MiB, 15.46% gc time)\n",
"Graph:\n",
" Nodes: Total: 4998, DataTask: 2503, ComputeTaskABC_S1: 516, \n",
" ComputeTaskABC_Sum: 1, ComputeTaskABC_U: 8, ComputeTaskABC_P: 8, \n",
" ComputeTaskABC_V: 1242, ComputeTaskABC_S2: 720\n",
" Edges: 7671\n",
" Total Compute Effort: 21777.0\n",
" Total Data Transfer: 253920.0\n",
" Total Compute Intensity: 0.0857632325141777\n"
]
}
],
"source": [
"@time optimize_to_fixpoint!(ReductionOptimizer(), graph)\n",
"print(graph)"
]
},
{
"cell_type": "code",
"execution_count": 15,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
" 0.822702 seconds (574.85 k allocations: 48.098 MiB, 0.90% gc time)\n"
]
},
{
"data": {
"text/plain": [
"compute__8dffb17a_8f2e_11ee_2d70_13a063f6b2e1 (generic function with 1 method)"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"@time compute_AB_AB5_reduced = get_compute_function(graph, process, machine)"
]
},
{
"cell_type": "code",
"execution_count": 16,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
" 0.054193 seconds (108.22 k allocations: 6.222 MiB, 92.26% compilation time)\n"
]
},
{
"data": {
"text/plain": [
"1000-element Vector{ABCProcessInput}:\n",
" Input for ABC Process: 'AB->ABBBBB':\n",
" 2 Incoming particles:\n",
" A: [5.53824935935883, 0.0, 0.0, 5.447220021849539]\n",
" B: [5.53824935935883, 0.0, 0.0, -5.447220021849539]\n",
" 6 Outgoing Particles:\n",
" A: [-1.3103925957044282, 0.7331872395687581, 0.24174619498761993, 0.34802873993327305]\n",
" B: [-1.7235347423723115, -0.9221216475500805, -0.5368654338299067, 0.9121618174658171]\n",
" B: [-3.2983236636246445, -1.4122494078132704, -0.264394674616116, -2.7954581120438933]\n",
" B: [-1.4663199369248787, -0.21617929792622487, -0.41022326537895987, 0.9669940750145931]\n",
" B: [-1.1596695896410607, 0.40971989086421784, 0.1871290088754596, -0.3767570864705371]\n",
" B: [-2.118258190450336, 1.4076432228565998, 0.7826081699619032, 0.945030566100747]\n",
"\n",
" Input for ABC Process: 'AB->ABBBBB':\n",
" 2 Incoming particles:\n",
" A: [6.406766539805908, 0.0, 0.0, 6.328242844232241]\n",
" B: [6.406766539805908, 0.0, 0.0, -6.328242844232241]\n",
" 6 Outgoing Particles:\n",
" A: [-1.6009185206411505, -0.5320720115654639, 1.09590848570997, -0.2807562558330809]\n",
" B: [-3.146359037361951, -0.17028519968266745, 1.7773008494544373, -2.389933018577465]\n",
" B: [-1.010135923448664, 0.06427364329577855, -0.1146419285663243, -0.05568402673627389]\n",
" B: [-3.6289281421436512, 0.6465018878980286, -0.8216898266580996, 3.328059584585744]\n",
" B: [-1.3592677632187082, 0.8038563415980269, -0.35192233894694247, -0.27852199472993183]\n",
" B: [-2.06792369279769, -0.8122746615437029, -1.5849552409930403, -0.323164288708993]\n",
"\n",
" Input for ABC Process: 'AB->ABBBBB':\n",
" 2 Incoming particles:\n",
" A: [4.592675400586894, 0.0, 0.0, 4.482484504731276]\n",
" B: [4.592675400586894, 0.0, 0.0, -4.482484504731276]\n",
" 6 Outgoing Particles:\n",
" A: [-1.1473149674649585, -0.35076892712815855, -0.170139004859497, -0.4053955023873595]\n",
" B: [-2.058220554606089, -0.8121547455466859, -1.4272449393744948, 0.7346076529133699]\n",
" B: [-2.0024960896606476, 1.3172479417787402, 0.7582221815549833, -0.8366286944540325]\n",
" B: [-1.0179814720237987, 0.162899519872391, -0.09860388948222289, -0.0052246328160273445]\n",
" B: [-1.834456765054589, -0.0990687609983643, 1.3606293642672649, 0.7100033355854413]\n",
" B: [-1.1248809523637056, -0.2181550279779225, -0.42286371210603335, -0.19736215884139197]\n",
"\n",
" Input for ABC Process: 'AB->ABBBBB':\n",
" 2 Incoming particles:\n",
" A: [4.037101162257922, 0.0, 0.0, 3.9112895308714055]\n",
" B: [4.037101162257922, 0.0, 0.0, -3.9112895308714055]\n",
" 6 Outgoing Particles:\n",
" A: [-1.7053110482506162, -0.23947337333507246, -1.2744970749813946, 0.47581034101100217]\n",
" B: [-1.3631569288619594, 0.7221467297219651, 0.42638713494656166, -0.3935669251960867]\n",
" B: [-1.0326521624735496, -0.11131042747240362, 0.20341304874809626, 0.11226579619908084]\n",
" B: [-1.195196392865049, -0.5445059949974184, -0.16637078706558947, 0.32299907142385453]\n",
" B: [-1.1830550739590457, 0.24824882865433953, -0.423307203181585, -0.39850073880304915]\n",
" B: [-1.5948307181056223, -0.07510576257141027, 1.2343748815339113, -0.11900754463480165]\n",
"\n",
" Input for ABC Process: 'AB->ABBBBB':\n",
" 2 Incoming particles:\n",
" A: [7.636716907339512, 0.0, 0.0, 7.57096064729207]\n",
" B: [7.636716907339512, 0.0, 0.0, -7.57096064729207]\n",
" 6 Outgoing Particles:\n",
" A: [-1.8228350224036067, -0.22313230508453247, 0.05829362440621317, -1.5064997001932685]\n",
" B: [-2.467409891320565, 1.6506915327402656, -0.771321444516658, 1.3298091083892047]\n",
" B: [-3.7191367050304223, 1.01401048234514, -0.8448690579747132, -3.3301586819963456]\n",
" B: [-1.086062092991359, 0.018065163049532738, 0.4218324659828878, 0.035523096142663795]\n",
" B: [-3.708627500490809, -3.0248517041401413, 1.3840072581447456, 1.2995052961646025]\n",
" B: [-2.4693626024422626, 0.5652168310897357, -0.24794284604247502, 2.171820881493144]\n",
"\n",
" Input for ABC Process: 'AB->ABBBBB':\n",
" 2 Incoming particles:\n",
" A: [4.844757462595395, 0.0, 0.0, 4.740429819264681]\n",
" B: [4.844757462595395, 0.0, 0.0, -4.740429819264681]\n",
" 6 Outgoing Particles:\n",
" A: [-1.3377157678137663, -0.44312783214029056, -0.34462836811169034, -0.6887325226333468]\n",
" B: [-1.0287552354600262, 0.10884372468923921, -0.0798214909694111, 0.20029704855940197]\n",
" B: [-1.237602042094568, -0.1707812371296387, -0.708500409075891, -0.02279811352743621]\n",
" B: [-1.2285767946957649, -0.45314793159826366, 0.5376309116329622, -0.12251895938933055]\n",
" B: [-2.3944375695065316, 0.5631279933752329, -1.4234056115727505, 1.5460060162511446]\n",
" B: [-2.4624275156201336, 0.3950852828037212, 2.0187249680967807, -0.9122534692604332]\n",
"\n",
" Input for ABC Process: 'AB->ABBBBB':\n",
" 2 Incoming particles:\n",
" A: [6.914095647194839, 0.0, 0.0, 6.841397417089481]\n",
" B: [6.914095647194839, 0.0, 0.0, -6.841397417089481]\n",
" 6 Outgoing Particles:\n",
" A: [-1.8747539146164607, -1.15195487912761, 1.0796978964166692, -0.14817101368775237]\n",
" B: [-2.0219963752169967, -0.8963094934108238, -1.380862038576808, 0.6150761447412909]\n",
" B: [-2.4839643051342004, -0.5463241040770312, 0.28470426735854887, -2.1887329948244236]\n",
" B: [-1.0870998264481033, 0.03306160941873628, 0.20168848226668348, -0.3741854069403313]\n",
" B: [-2.4584897964753116, 0.9082805780526032, -1.8726214974559325, -0.844089567623928]\n",
" B: [-3.9018870764986056, 1.6532462891441266, 1.6873928899908393, 2.9401028383351444]\n",
"\n",
" Input for ABC Process: 'AB->ABBBBB':\n",
" 2 Incoming particles:\n",
" A: [4.882838018892802, 0.0, 0.0, 4.77934170349275]\n",
" B: [4.882838018892802, 0.0, 0.0, -4.77934170349275]\n",
" 6 Outgoing Particles:\n",
" A: [-1.3368922715636002, -0.024254114235374817, -0.17993280734873465, 0.8685141729118435]\n",
" B: [-1.336032053759296, 0.44580739433740213, 0.4009862518446777, -0.6522633223307408]\n",
" B: [-1.1917158881102905, 0.11587748600254362, 0.21032579337862262, -0.6020981870524788]\n",
" B: [-1.8590179700604674, -0.4659878149612763, 1.4629321849562218, 0.3140582613697155]\n",
" B: [-1.2740128533657533, -0.3900331968801154, 0.6651639498517544, 0.16893719451393388]\n",
" B: [-2.7680050009261956, 0.3185902457368207, -2.559475372682542, -0.09714811941227354]\n",
"\n",
" Input for ABC Process: 'AB->ABBBBB':\n",
" 2 Incoming particles:\n",
" A: [4.215107110349817, 0.0, 0.0, 4.094768363622244]\n",
" B: [4.215107110349817, 0.0, 0.0, -4.094768363622244]\n",
" 6 Outgoing Particles:\n",
" A: [-1.3241447475687065, 0.7510738166043768, -0.3909856211208319, 0.19072933335458914]\n",
" B: [-1.7731907344857587, 0.036019000265901324, 1.4622797510086056, -0.06816114931690141]\n",
" B: [-1.019387957593508, 0.014655316462798782, 0.19300767940790514, -0.04104954903058491]\n",
" B: [-1.6169881803397028, 0.04956396056952302, -1.0323879934365006, -0.7391679242087841]\n",
" B: [-1.6537900060652204, -1.1032956801849205, -0.08849835738509954, 0.7140924778952892]\n",
" B: [-1.0427125946467377, 0.2519835862823207, -0.14341545847407883, -0.056443188693607704]\n",
"\n",
" Input for ABC Process: 'AB->ABBBBB':\n",
" 2 Incoming particles:\n",
" A: [7.2720657357811564, 0.0, 0.0, 7.202981331748843]\n",
" B: [7.2720657357811564, 0.0, 0.0, -7.202981331748843]\n",
" 6 Outgoing Particles:\n",
" A: [-1.110939233644008, -0.268184416567738, 0.24360224044987097, 0.3208131044822848]\n",
" B: [-2.6388927199644003, 0.8314814079287018, -0.21777668284358856, 2.2858186218857472]\n",
" B: [-3.473898607870094, 2.051862236379928, 2.4003392500206266, -1.046997796315806]\n",
" B: [-3.152819934613197, -1.9424358511984305, -2.028267056813039, -1.0263280422556738]\n",
" B: [-2.275152937944009, -1.7654922583464505, 0.7703768739716074, -0.6825521583027478]\n",
" B: [-1.8924280375266047, 1.0927688818039885, -1.1682746247854774, 0.14924627050619674]\n",
"\n",
" ⋮\n",
" Input for ABC Process: 'AB->ABBBBB':\n",
" 2 Incoming particles:\n",
" A: [6.22966038636724, 0.0, 0.0, 6.148875387375584]\n",
" B: [6.22966038636724, 0.0, 0.0, -6.148875387375584]\n",
" 6 Outgoing Particles:\n",
" A: [-1.4304429070664482, -0.33884344128192095, 0.8653360836289696, -0.42725343187224885]\n",
" B: [-1.9749814666096197, 1.3609392980219706, -0.9441991051819204, -0.39608593805462516]\n",
" B: [-2.2715747343865793, 1.2408591011012648, 1.6172984936557957, 0.06830847338590983]\n",
" B: [-1.661609068228756, -0.4012681871023404, -1.1964016761233542, 0.4105503221395213]\n",
" B: [-1.746963024762814, 1.345279186098992, -0.06451410595930414, 0.48779263162695097]\n",
" B: [-3.373749571680263, -3.2069659568379674, -0.2775196900201868, -0.1433120572255088]\n",
"\n",
" Input for ABC Process: 'AB->ABBBBB':\n",
" 2 Incoming particles:\n",
" A: [4.358722688789774, 0.0, 0.0, 4.242459602373458]\n",
" B: [4.358722688789774, 0.0, 0.0, -4.242459602373458]\n",
" 6 Outgoing Particles:\n",
" A: [-1.0452779390743625, -0.2727572224505045, -0.0754336299872278, 0.11188938726967125]\n",
" B: [-1.7048247824379945, 0.4983084694471347, 0.872827621048126, 0.9467249611304639]\n",
" B: [-1.2899467751023526, 0.29644307338358544, -0.46128198344041976, -0.602746313628815]\n",
" B: [-2.1244189851466975, -1.8139000349895653, -0.4266469607437963, -0.20222526648433034]\n",
" B: [-1.4709803178987078, 1.0687795622551313, -0.1466043527374882, 0.0007118353293400601]\n",
" B: [-1.0819965779194327, 0.22312615235421782, 0.23713930586080637, -0.25435460361632983]\n",
"\n",
" Input for ABC Process: 'AB->ABBBBB':\n",
" 2 Incoming particles:\n",
" A: [4.946953336826144, 0.0, 0.0, 4.844826861378569]\n",
" B: [4.946953336826144, 0.0, 0.0, -4.844826861378569]\n",
" 6 Outgoing Particles:\n",
" A: [-1.0798321354813016, -0.05701177676898147, 0.3748038410417432, -0.1493625751924078]\n",
" B: [-2.535607459805834, 0.2786802518140389, -2.1413493157456154, 0.8753659894167939]\n",
" B: [-1.1465622434125131, 0.048325266102822936, -0.30303094935893476, 0.46951239643469417]\n",
" B: [-1.0565850692648957, -0.15422821749644713, -0.2946016814579471, -0.0761282786060691]\n",
" B: [-1.3897397103611828, 0.8757386144485694, 0.40183039146109456, 0.054687093694094344]\n",
" B: [-2.6855800553265587, -0.9915041381000028, 1.96234771405966, -1.1740746257471053]\n",
"\n",
" Input for ABC Process: 'AB->ABBBBB':\n",
" 2 Incoming particles:\n",
" A: [5.263219273050624, 0.0, 0.0, 5.1673472029864165]\n",
" B: [5.263219273050624, 0.0, 0.0, -5.1673472029864165]\n",
" 6 Outgoing Particles:\n",
" A: [-2.399019535788919, -1.2110047848361276, -1.812263889139395, -0.06679625979229631]\n",
" B: [-2.017935306086244, -0.3374680394916718, 1.6282821358219384, 0.5539634536990483]\n",
" B: [-1.6695031594114513, 0.8270762338660977, -0.06260699981442713, 1.0484589005931164]\n",
" B: [-2.2597097606741916, 0.7611180237287621, 0.18055687193684328, -1.869327893238054]\n",
" B: [-1.073204850363539, -0.22248377596385552, 0.3188604064962904, -0.024447115284049005]\n",
" B: [-1.1070659337769053, 0.18276234269679548, -0.25282852530124955, 0.3581489140222342]\n",
"\n",
" Input for ABC Process: 'AB->ABBBBB':\n",
" 2 Incoming particles:\n",
" A: [4.459941032222146, 0.0, 0.0, 4.346386316343583]\n",
" B: [4.459941032222146, 0.0, 0.0, -4.346386316343583]\n",
" 6 Outgoing Particles:\n",
" A: [-1.9579957774892203, 0.01711251988645602, -0.9941971785148113, 1.3583175610150744]\n",
" B: [-2.2086526478827153, 0.26811947256465357, -0.29730202477347406, -1.9281778894844153]\n",
" B: [-1.1393295497986875, -0.09576318262839165, 0.3418914140864091, 0.4147426875441645]\n",
" B: [-1.5437833884502452, -0.2526758526831343, 1.1436052762387854, 0.10765238541055888]\n",
" B: [-1.029324601398587, -0.04086809209820055, -0.11666716588470447, -0.21030384327692128]\n",
" B: [-1.040796099424839, 0.10407513495861721, -0.07733032115220424, 0.25776909879153836]\n",
"\n",
" Input for ABC Process: 'AB->ABBBBB':\n",
" 2 Incoming particles:\n",
" A: [5.6127229037846575, 0.0, 0.0, 5.522921183094041]\n",
" B: [5.6127229037846575, 0.0, 0.0, -5.522921183094041]\n",
" 6 Outgoing Particles:\n",
" A: [-1.3401191006255044, 0.07455340773270878, 0.8329539127008466, 0.3107229836576332]\n",
" B: [-2.2407608326391446, 1.9616328357565815, 0.2748188274329855, 0.3122184153114968]\n",
" B: [-1.9353505325144305, 0.5041718248979296, 0.4986811623094062, -1.4975678792765024]\n",
" B: [-1.1665291383852119, -0.5919830552573446, -0.0003589073718047799, 0.10171609595055851]\n",
" B: [-1.3532183234755, -0.2764818233423043, 0.8493370095656062, 0.18271364627008788]\n",
" B: [-3.1894678799295257, -1.671893189787572, -2.45543200463704, 0.5901967380867258]\n",
"\n",
" Input for ABC Process: 'AB->ABBBBB':\n",
" 2 Incoming particles:\n",
" A: [4.8915558702989275, 0.0, 0.0, 4.788247991933574]\n",
" B: [4.8915558702989275, 0.0, 0.0, -4.788247991933574]\n",
" 6 Outgoing Particles:\n",
" A: [-1.7166600698631052, -0.6792891539923208, 0.6748994636717233, 1.0148885429772172]\n",
" B: [-2.5106233942424825, -0.7525848308448442, -1.9630692909736174, 0.9397897950798489]\n",
" B: [-1.0591214238384126, 0.22224342472975844, 0.26723772059994233, -0.030496742226701214]\n",
" B: [-2.107615205886531, 1.2019506202258687, 1.111787687227206, -0.8725163042331971]\n",
" B: [-1.1276654384352531, 0.3419112314983172, -0.15371273194576066, -0.3620751950278375]\n",
" B: [-1.2614262083320695, -0.33423129161677956, 0.06285715142050609, -0.689590096569332]\n",
"\n",
" Input for ABC Process: 'AB->ABBBBB':\n",
" 2 Incoming particles:\n",
" A: [7.730105975946025, 0.0, 0.0, 7.665150905191394]\n",
" B: [7.730105975946025, 0.0, 0.0, -7.665150905191394]\n",
" 6 Outgoing Particles:\n",
" A: [-1.5069861693238755, -0.14569717271308374, -1.0624243147247645, 0.3478997325070473]\n",
" B: [-1.3943234172777221, -0.04432112759455558, 0.08353004942916775, 0.9670554071303941]\n",
" B: [-2.959534510858716, -2.3414048211285614, 1.2349523309699664, 0.8669260203682391]\n",
" B: [-3.9504084752062516, -1.3395798731389539, -0.8585843373250325, -3.4747785282176675]\n",
" B: [-3.4956434330579116, 2.5236614743308494, -0.431975773525167, 2.1596418001942994]\n",
" B: [-2.153315946167574, 1.3473415202443053, 1.0345020451758309, -0.8667444319823133]\n",
"\n",
" Input for ABC Process: 'AB->ABBBBB':\n",
" 2 Incoming particles:\n",
" A: [5.140973354732315, 0.0, 0.0, 5.042777710158126]\n",
" B: [5.140973354732315, 0.0, 0.0, -5.042777710158126]\n",
" 6 Outgoing Particles:\n",
" A: [-2.1212395395513415, 0.5721186152245487, -1.464674439391297, 1.013442776314144]\n",
" B: [-1.4152359585953729, 0.6568206137784666, 0.5137348552056548, -0.5545773150462135]\n",
" B: [-1.6621060291271548, -0.07490000906447869, -1.013680695206552, 0.8540713605247167]\n",
" B: [-1.602034710373159, -1.201656230753467, -0.11487974312683813, 0.3306662379967043]\n",
" B: [-1.6826459861655199, -0.324056691191041, 0.7444127790391002, -1.082651555236741]\n",
" B: [-1.7986844856520843, 0.3716737020059716, 1.3350872434799315, -0.5609515045526104]\n"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"@time inputs = [gen_process_input(process) for _ in 1:1000]"
]
},
{
"cell_type": "code",
"execution_count": 17,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"BenchmarkTools.Trial: 231 samples with 1 evaluation.\n",
" Range \u001b[90m(\u001b[39m\u001b[36m\u001b[1mmin\u001b[22m\u001b[39m … \u001b[35mmax\u001b[39m\u001b[90m): \u001b[39m\u001b[36m\u001b[1m18.197 ms\u001b[22m\u001b[39m … \u001b[35m27.498 ms\u001b[39m \u001b[90m┊\u001b[39m GC \u001b[90m(\u001b[39mmin … max\u001b[90m): \u001b[39m0.00% … 8.36%\n",
" Time \u001b[90m(\u001b[39m\u001b[34m\u001b[1mmedian\u001b[22m\u001b[39m\u001b[90m): \u001b[39m\u001b[34m\u001b[1m21.868 ms \u001b[22m\u001b[39m\u001b[90m┊\u001b[39m GC \u001b[90m(\u001b[39mmedian\u001b[90m): \u001b[39m0.00%\n",
" Time \u001b[90m(\u001b[39m\u001b[32m\u001b[1mmean\u001b[22m\u001b[39m ± \u001b[32mσ\u001b[39m\u001b[90m): \u001b[39m\u001b[32m\u001b[1m21.644 ms\u001b[22m\u001b[39m ± \u001b[32m 1.609 ms\u001b[39m \u001b[90m┊\u001b[39m GC \u001b[90m(\u001b[39mmean ± σ\u001b[90m): \u001b[39m1.21% ± 2.71%\n",
"\n",
" \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[32m \u001b[39m\u001b[39m▃\u001b[34m█\u001b[39m\u001b[39m▁\u001b[39m \u001b[39m▅\u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \n",
" \u001b[39m▃\u001b[39m▃\u001b[39m▁\u001b[39m▅\u001b[39m▇\u001b[39m▃\u001b[39m▅\u001b[39m▅\u001b[39m▅\u001b[39m▃\u001b[39m▄\u001b[39m▃\u001b[39m▃\u001b[39m▅\u001b[39m▄\u001b[39m▅\u001b[39m▃\u001b[39m▅\u001b[39m▄\u001b[39m▃\u001b[39m▅\u001b[39m▄\u001b[39m▃\u001b[39m▅\u001b[39m▇\u001b[39m▅\u001b[39m▅\u001b[32m▆\u001b[39m\u001b[39m█\u001b[34m█\u001b[39m\u001b[39m█\u001b[39m█\u001b[39m█\u001b[39m▇\u001b[39m▆\u001b[39m▇\u001b[39m▄\u001b[39m▅\u001b[39m▄\u001b[39m▅\u001b[39m▅\u001b[39m▄\u001b[39m▃\u001b[39m▅\u001b[39m▃\u001b[39m▁\u001b[39m▁\u001b[39m▃\u001b[39m▄\u001b[39m▁\u001b[39m▄\u001b[39m▁\u001b[39m▃\u001b[39m▃\u001b[39m▁\u001b[39m▃\u001b[39m▁\u001b[39m▁\u001b[39m▃\u001b[39m \u001b[39m▃\n",
" 18.2 ms\u001b[90m Histogram: frequency by time\u001b[39m 25.6 ms \u001b[0m\u001b[1m<\u001b[22m\n",
"\n",
" Memory estimate\u001b[90m: \u001b[39m\u001b[33m6.78 MiB\u001b[39m, allocs estimate\u001b[90m: \u001b[39m\u001b[33m17003\u001b[39m."
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"using BenchmarkTools\n",
"#compute_bench = @benchmark compute_AB_AB5.(inputs)\n",
"compute_bench_reduced = @benchmark compute_AB_AB5_reduced.(inputs)"
]
},
{
"cell_type": "code",
"execution_count": 9,
"metadata": {},
"outputs": [],
"source": []
}
],
"metadata": {
"kernelspec": {
"display_name": "Julia 1.9.4",
"language": "julia",
"name": "julia-1.9"
},
"language_info": {
"file_extension": ".jl",
"mimetype": "application/julia",
"name": "julia",
"version": "1.9.4"
}
},
"nbformat": 4,
"nbformat_minor": 4
}

View File

@ -0,0 +1,407 @@
{
"cells": [
{
"cell_type": "code",
"execution_count": 2,
"id": "20768e45-df62-4638-ba33-b0ccf239f1aa",
"metadata": {},
"outputs": [],
"source": [
"using Revise\n",
"using MetagraphOptimization\n",
"using BenchmarkTools"
]
},
{
"cell_type": "code",
"execution_count": 3,
"id": "ff5f4a49",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Found 1 NUMA nodes\n",
"CUDA is non-functional\n"
]
},
{
"data": {
"text/plain": [
"Machine(MetagraphOptimization.AbstractDevice[MetagraphOptimization.NumaNode(0x0000, 0x0001, MetagraphOptimization.LocalVariables(), -1.0, UUID(\"a89974f6-6212-11ee-0866-0f591a3b69ea\"))], [-1.0;;])"
]
},
"execution_count": 3,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"# Get our machine's info\n",
"machine = get_machine_info()"
]
},
{
"cell_type": "code",
"execution_count": 4,
"id": "9df482a4-ca44-44c5-9ea7-7a2977d529be",
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"ABCModel()"
]
},
"execution_count": 4,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"# Create a model identifier\n",
"model = ABCModel()"
]
},
{
"cell_type": "code",
"execution_count": 5,
"id": "30b16872-07f7-4d47-8ff8-8c3a849c9d4e",
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"ABC Process: 'AB->ABBB'"
]
},
"execution_count": 5,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"# Create a process in our model\n",
"process_str = \"AB->ABBB\"\n",
"process = parse_process(process_str, model)"
]
},
{
"cell_type": "code",
"execution_count": 6,
"id": "043bd9e2-f89a-4362-885a-8c89d4cdd76f",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Total: 280, ComputeTaskABC_P"
]
},
{
"data": {
"text/plain": [
"Graph:\n",
" Nodes: \n",
" Edges: 385\n",
" Total Compute Effort: 1075.0\n",
" Total Data Transfer: 10944.0\n",
" Total Compute Intensity: 0.09822733918128655\n"
]
},
"execution_count": 6,
"metadata": {},
"output_type": "execute_result"
},
{
"name": "stdout",
"output_type": "stream",
"text": [
": 6, ComputeTaskABC_U: 6, \n",
" ComputeTaskABC_V: 64, ComputeTaskABC_Sum: 1, ComputeTaskABC_S2: 24, \n",
" ComputeTaskABC_S1: 36, DataTask: 143"
]
}
],
"source": [
"# Read the graph (of the same process) from a file\n",
"graph = parse_dag(\"../input/$process_str.txt\", model)"
]
},
{
"cell_type": "code",
"execution_count": 7,
"id": "02f01ad3-fd10-48d5-a0e0-c03dc83c80a4",
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"Input for ABC Process: 'AB->ABBB':\n",
" 2 Incoming particles:\n",
" A: [5.77986599979293, 0.0, 0.0, 5.692701553354288]\n",
" B: [5.77986599979293, 0.0, 0.0, -5.692701553354288]\n",
" 4 Outgoing Particles:\n",
" A: [-3.8835293143673746, -1.4292027910861678, 2.8576090179942106, 1.968057422378813]\n",
" B: [-1.1554024905063585, -0.1464656500147254, -0.2082400426692148, 0.5197487980391896]\n",
" B: [-2.849749730594798, -1.0177034035100576, -2.464951858896686, -0.09677625137882176]\n",
" B: [-3.6710504641173287, 2.5933718446109513, -0.1844171164283155, -2.391029969039186]\n"
]
},
"execution_count": 7,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"# Generate some random input data for our process\n",
"input_data = gen_process_input(process)"
]
},
{
"cell_type": "code",
"execution_count": 8,
"id": "083fb1be-ce2a-47f9-afb9-60a6fdfaed0b",
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"compute__af4450a2_6212_11ee_2601_cde7cf2aedc1 (generic function with 1 method)"
]
},
"execution_count": 8,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"# Get the function computing the result of the process from a ProcessInput\n",
"AB_AB3_compute = get_compute_function(graph, process, machine)"
]
},
{
"cell_type": "code",
"execution_count": 9,
"id": "a40c9500-8f79-4f04-b3c5-59b72a6b7ba9",
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"-1.8924431710735022e-13"
]
},
"execution_count": 9,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"# Actually compute a result using the generated function and the input data\n",
"result = AB_AB3_compute(input_data)"
]
},
{
"cell_type": "code",
"execution_count": 10,
"id": "80c70010",
"metadata": {},
"outputs": [],
"source": [
"# We can also mute the graph by applying some operations to it\n",
"optimize_to_fixpoint!(ReductionOptimizer(), graph)"
]
},
{
"cell_type": "code",
"execution_count": 11,
"id": "5b192b44",
"metadata": {},
"outputs": [],
"source": [
"# The result should be the same as before (we can use execute to save having to generate the function ourselves)\n",
"@assert result ≈ execute(graph, process, machine, input_data)"
]
},
{
"cell_type": "code",
"execution_count": 12,
"id": "9b2f4a3f",
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"1000-element Vector{Float64}:\n",
" -2.1491995259940396e-11\n",
" -1.04995646459455e-11\n",
" 5.821760691187782e-15\n",
" -6.556969485683705e-14\n",
" -1.3588086164373753e-14\n",
" -1.8789662441593694e-13\n",
" -2.131973301835892e-13\n",
" -5.3359759072004825e-12\n",
" -9.053914191490223e-13\n",
" -5.61107901706923e-13\n",
" -5.063492275603428e-11\n",
" 2.9168508985811397e-15\n",
" -1.6420151378194157e-13\n",
" ⋮\n",
" 1.0931677247833436e-13\n",
" -7.704755306462797e-16\n",
" -1.8385907037491397e-12\n",
" -6.036215596560059e-14\n",
" -9.98872401400362e-12\n",
" 3.4861755637292935e-13\n",
" -1.1051119822969222e-10\n",
" -2.496572513216201e-12\n",
" -3.8682427847201926e-11\n",
" 7.904149696653438e-15\n",
" -7.606811743178716e-11\n",
" -5.100594937480292e-13"
]
},
"execution_count": 12,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"# Now we can generate a function and use it on lots of inputs\n",
"inputs = [gen_process_input(process) for _ in 1:1000]\n",
"AB_AB3_reduced_compute = get_compute_function(graph, process, machine)\n",
"\n",
"results = AB_AB3_reduced_compute.(inputs)"
]
},
{
"cell_type": "code",
"execution_count": 13,
"id": "d43e4ff0",
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"BenchmarkTools.Trial: 879 samples with 1 evaluation.\n",
" Range \u001b[90m(\u001b[39m\u001b[36m\u001b[1mmin\u001b[22m\u001b[39m … \u001b[35mmax\u001b[39m\u001b[90m): \u001b[39m\u001b[36m\u001b[1m4.567 ms\u001b[22m\u001b[39m … \u001b[35m14.334 ms\u001b[39m \u001b[90m┊\u001b[39m GC \u001b[90m(\u001b[39mmin … max\u001b[90m): \u001b[39m0.00% … 54.51%\n",
" Time \u001b[90m(\u001b[39m\u001b[34m\u001b[1mmedian\u001b[22m\u001b[39m\u001b[90m): \u001b[39m\u001b[34m\u001b[1m4.998 ms \u001b[22m\u001b[39m\u001b[90m┊\u001b[39m GC \u001b[90m(\u001b[39mmedian\u001b[90m): \u001b[39m0.00%\n",
" Time \u001b[90m(\u001b[39m\u001b[32m\u001b[1mmean\u001b[22m\u001b[39m ± \u001b[32mσ\u001b[39m\u001b[90m): \u001b[39m\u001b[32m\u001b[1m5.686 ms\u001b[22m\u001b[39m ± \u001b[32m 1.414 ms\u001b[39m \u001b[90m┊\u001b[39m GC \u001b[90m(\u001b[39mmean ± σ\u001b[90m): \u001b[39m9.09% ± 14.49%\n",
"\n",
" \u001b[39m \u001b[39m \u001b[39m▃\u001b[39m▇\u001b[39m█\u001b[34m▅\u001b[39m\u001b[39m▄\u001b[39m▁\u001b[39m \u001b[39m▁\u001b[39m \u001b[39m \u001b[32m \u001b[39m\u001b[39m \u001b[39m▁\u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m▁\u001b[39m▁\u001b[39m \u001b[39m▁\u001b[39m▁\u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \n",
" \u001b[39m▆\u001b[39m█\u001b[39m█\u001b[39m█\u001b[39m█\u001b[34m█\u001b[39m\u001b[39m█\u001b[39m█\u001b[39m▇\u001b[39m█\u001b[39m▇\u001b[39m▇\u001b[32m█\u001b[39m\u001b[39m▆\u001b[39m█\u001b[39m█\u001b[39m▆\u001b[39m▆\u001b[39m▇\u001b[39m▅\u001b[39m▅\u001b[39m▄\u001b[39m▁\u001b[39m▄\u001b[39m▅\u001b[39m▅\u001b[39m▆\u001b[39m▅\u001b[39m▅\u001b[39m▄\u001b[39m▁\u001b[39m▄\u001b[39m▄\u001b[39m▁\u001b[39m▅\u001b[39m▄\u001b[39m▄\u001b[39m▆\u001b[39m▇\u001b[39m█\u001b[39m█\u001b[39m█\u001b[39m█\u001b[39m█\u001b[39m█\u001b[39m▄\u001b[39m▅\u001b[39m▆\u001b[39m▅\u001b[39m▅\u001b[39m▅\u001b[39m▁\u001b[39m▅\u001b[39m▄\u001b[39m▄\u001b[39m▅\u001b[39m▁\u001b[39m▄\u001b[39m \u001b[39m▇\n",
" 4.57 ms\u001b[90m \u001b[39m\u001b[90mHistogram: \u001b[39m\u001b[90m\u001b[1mlog(\u001b[22m\u001b[39m\u001b[90mfrequency\u001b[39m\u001b[90m\u001b[1m)\u001b[22m\u001b[39m\u001b[90m by time\u001b[39m 10 ms \u001b[0m\u001b[1m<\u001b[22m\n",
"\n",
" Memory estimate\u001b[90m: \u001b[39m\u001b[33m6.17 MiB\u001b[39m, allocs estimate\u001b[90m: \u001b[39m\u001b[33m143006\u001b[39m."
]
},
"execution_count": 13,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"@benchmark results = AB_AB3_compute.($inputs)"
]
},
{
"cell_type": "code",
"execution_count": 14,
"id": "e18d9546",
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"BenchmarkTools.Trial: 1089 samples with 1 evaluation.\n",
" Range \u001b[90m(\u001b[39m\u001b[36m\u001b[1mmin\u001b[22m\u001b[39m … \u001b[35mmax\u001b[39m\u001b[90m): \u001b[39m\u001b[36m\u001b[1m3.637 ms\u001b[22m\u001b[39m … \u001b[35m10.921 ms\u001b[39m \u001b[90m┊\u001b[39m GC \u001b[90m(\u001b[39mmin … max\u001b[90m): \u001b[39m 0.00% … 59.52%\n",
" Time \u001b[90m(\u001b[39m\u001b[34m\u001b[1mmedian\u001b[22m\u001b[39m\u001b[90m): \u001b[39m\u001b[34m\u001b[1m4.098 ms \u001b[22m\u001b[39m\u001b[90m┊\u001b[39m GC \u001b[90m(\u001b[39mmedian\u001b[90m): \u001b[39m 0.00%\n",
" Time \u001b[90m(\u001b[39m\u001b[32m\u001b[1mmean\u001b[22m\u001b[39m ± \u001b[32mσ\u001b[39m\u001b[90m): \u001b[39m\u001b[32m\u001b[1m4.587 ms\u001b[22m\u001b[39m ± \u001b[32m 1.334 ms\u001b[39m \u001b[90m┊\u001b[39m GC \u001b[90m(\u001b[39mmean ± σ\u001b[90m): \u001b[39m10.21% ± 15.77%\n",
"\n",
" \u001b[39m \u001b[39m▂\u001b[39m▆\u001b[39m▆\u001b[39m▇\u001b[34m█\u001b[39m\u001b[39m▆\u001b[39m▂\u001b[39m \u001b[39m \u001b[39m \u001b[32m \u001b[39m\u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m▁\u001b[39m▁\u001b[39m \u001b[39m▁\u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \n",
" \u001b[39m▆\u001b[39m█\u001b[39m█\u001b[39m█\u001b[39m█\u001b[34m█\u001b[39m\u001b[39m█\u001b[39m█\u001b[39m▇\u001b[39m█\u001b[39m▇\u001b[32m▆\u001b[39m\u001b[39m▅\u001b[39m▇\u001b[39m▅\u001b[39m▅\u001b[39m▅\u001b[39m▄\u001b[39m▆\u001b[39m▄\u001b[39m▅\u001b[39m▅\u001b[39m▅\u001b[39m▅\u001b[39m▆\u001b[39m▄\u001b[39m▁\u001b[39m▁\u001b[39m▁\u001b[39m▁\u001b[39m▁\u001b[39m▁\u001b[39m▁\u001b[39m▁\u001b[39m▁\u001b[39m▁\u001b[39m▁\u001b[39m▁\u001b[39m▁\u001b[39m▁\u001b[39m▄\u001b[39m▆\u001b[39m▆\u001b[39m▆\u001b[39m█\u001b[39m█\u001b[39m▇\u001b[39m█\u001b[39m█\u001b[39m▆\u001b[39m▆\u001b[39m▆\u001b[39m█\u001b[39m█\u001b[39m▇\u001b[39m▆\u001b[39m▄\u001b[39m▄\u001b[39m \u001b[39m█\n",
" 3.64 ms\u001b[90m \u001b[39m\u001b[90mHistogram: \u001b[39m\u001b[90m\u001b[1mlog(\u001b[22m\u001b[39m\u001b[90mfrequency\u001b[39m\u001b[90m\u001b[1m)\u001b[22m\u001b[39m\u001b[90m by time\u001b[39m 8.78 ms \u001b[0m\u001b[1m<\u001b[22m\n",
"\n",
" Memory estimate\u001b[90m: \u001b[39m\u001b[33m5.26 MiB\u001b[39m, allocs estimate\u001b[90m: \u001b[39m\u001b[33m123006\u001b[39m."
]
},
"execution_count": 14,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"@benchmark results = AB_AB3_reduced_compute.($inputs)"
]
},
{
"cell_type": "code",
"execution_count": 16,
"id": "13efed12-3547-400b-a7a2-5dfae9a973a2",
"metadata": {},
"outputs": [],
"source": [
"# Set a different caching strategy\n",
"MetagraphOptimization.set_cache_strategy(machine.devices[1], MetagraphOptimization.Dictionary())"
]
},
{
"cell_type": "code",
"execution_count": 18,
"id": "ef62716b-a219-4f6e-9150-f984d3734839",
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"BenchmarkTools.Trial: 331 samples with 1 evaluation.\n",
" Range \u001b[90m(\u001b[39m\u001b[36m\u001b[1mmin\u001b[22m\u001b[39m … \u001b[35mmax\u001b[39m\u001b[90m): \u001b[39m\u001b[36m\u001b[1m12.148 ms\u001b[22m\u001b[39m … \u001b[35m24.164 ms\u001b[39m \u001b[90m┊\u001b[39m GC \u001b[90m(\u001b[39mmin … max\u001b[90m): \u001b[39m 0.00% … 13.35%\n",
" Time \u001b[90m(\u001b[39m\u001b[34m\u001b[1mmedian\u001b[22m\u001b[39m\u001b[90m): \u001b[39m\u001b[34m\u001b[1m15.412 ms \u001b[22m\u001b[39m\u001b[90m┊\u001b[39m GC \u001b[90m(\u001b[39mmedian\u001b[90m): \u001b[39m17.47%\n",
" Time \u001b[90m(\u001b[39m\u001b[32m\u001b[1mmean\u001b[22m\u001b[39m ± \u001b[32mσ\u001b[39m\u001b[90m): \u001b[39m\u001b[32m\u001b[1m15.117 ms\u001b[22m\u001b[39m ± \u001b[32m 2.194 ms\u001b[39m \u001b[90m┊\u001b[39m GC \u001b[90m(\u001b[39mmean ± σ\u001b[90m): \u001b[39m12.31% ± 8.95%\n",
"\n",
" \u001b[39m \u001b[39m▄\u001b[39m█\u001b[39m▄\u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[32m▄\u001b[39m\u001b[39m▄\u001b[34m▂\u001b[39m\u001b[39m \u001b[39m▂\u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \n",
" \u001b[39m▅\u001b[39m█\u001b[39m█\u001b[39m█\u001b[39m▅\u001b[39m▃\u001b[39m▃\u001b[39m▂\u001b[39m▃\u001b[39m▂\u001b[39m▅\u001b[39m▂\u001b[39m▃\u001b[39m▁\u001b[39m▂\u001b[39m▂\u001b[39m▂\u001b[39m▃\u001b[39m▂\u001b[39m▃\u001b[32m█\u001b[39m\u001b[39m█\u001b[34m█\u001b[39m\u001b[39m▇\u001b[39m█\u001b[39m▄\u001b[39m▆\u001b[39m▄\u001b[39m▆\u001b[39m▄\u001b[39m▄\u001b[39m▆\u001b[39m▅\u001b[39m▄\u001b[39m▃\u001b[39m▄\u001b[39m▂\u001b[39m▂\u001b[39m▃\u001b[39m▃\u001b[39m▄\u001b[39m▃\u001b[39m▂\u001b[39m▂\u001b[39m▁\u001b[39m▂\u001b[39m▂\u001b[39m▃\u001b[39m▂\u001b[39m▂\u001b[39m▁\u001b[39m▂\u001b[39m▁\u001b[39m▃\u001b[39m▃\u001b[39m▂\u001b[39m▂\u001b[39m▁\u001b[39m▂\u001b[39m \u001b[39m▃\n",
" 12.1 ms\u001b[90m Histogram: frequency by time\u001b[39m 21 ms \u001b[0m\u001b[1m<\u001b[22m\n",
"\n",
" Memory estimate\u001b[90m: \u001b[39m\u001b[33m27.46 MiB\u001b[39m, allocs estimate\u001b[90m: \u001b[39m\u001b[33m118013\u001b[39m."
]
},
"execution_count": 18,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"# ... and bench again\n",
"AB_AB3_reduced_dict_compute = get_compute_function(graph, process, machine)\n",
"@benchmark results = AB_AB3_reduced_dict_compute.($inputs)"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "5461ffd4-6a0e-4f1f-b1f1-3a2854a8ae88",
"metadata": {},
"outputs": [],
"source": []
}
],
"metadata": {
"kernelspec": {
"display_name": "Julia 1.9.3",
"language": "julia",
"name": "julia-1.9"
},
"language_info": {
"file_extension": ".jl",
"mimetype": "application/julia",
"name": "julia",
"version": "1.9.3"
}
},
"nbformat": 4,
"nbformat_minor": 5
}

451
notebooks/diagram_gen.ipynb Normal file
View File

@ -0,0 +1,451 @@
{
"cells": [
{
"cell_type": "code",
"execution_count": 37,
"metadata": {},
"outputs": [],
"source": [
"using Revise; using QEDbase; using QEDprocesses; using MetagraphOptimization; using BenchmarkTools; using DataStructures\n",
"import MetagraphOptimization.gen_diagrams"
]
},
{
"cell_type": "code",
"execution_count": 38,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Diagram 1: Initial Particles: [k_i_1, e_i_1, k_o_1, e_o_1]\n",
" Virtuality Level 1 Vertices: [k_i_1 + e_i_1 -> e_i_2, k_o_1 + e_o_1 -> e_o_2]\n",
" Tie: e_i_2 -- e_o_2\n",
"\n",
"Diagram 2: Initial Particles: [k_i_1, e_i_1, k_o_1, e_o_1]\n",
" Virtuality Level 1 Vertices: [k_i_1 + e_o_1 -> e_o_2, e_i_1 + k_o_1 -> e_i_2]\n",
" Tie: e_o_2 -- e_i_2\n",
"\n"
]
}
],
"source": [
"# Compton Scattering\n",
"fd = FeynmanDiagram(parse_process(\"ke->ke\", QEDModel()))\n",
"\n",
"diagrams = gen_diagrams(fd)\n",
"\n",
"c = 1\n",
"for d in diagrams\n",
" println(\"Diagram $c: $d\")\n",
" c += 1\n",
"end"
]
},
{
"cell_type": "code",
"execution_count": 39,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"BenchmarkTools.Trial: 6044 samples with 1 evaluation.\n",
" Range \u001b[90m(\u001b[39m\u001b[36m\u001b[1mmin\u001b[22m\u001b[39m … \u001b[35mmax\u001b[39m\u001b[90m): \u001b[39m\u001b[36m\u001b[1m490.857 μs\u001b[22m\u001b[39m … \u001b[35m 3.657 ms\u001b[39m \u001b[90m┊\u001b[39m GC \u001b[90m(\u001b[39mmin … max\u001b[90m): \u001b[39m0.00% … 77.38%\n",
" Time \u001b[90m(\u001b[39m\u001b[34m\u001b[1mmedian\u001b[22m\u001b[39m\u001b[90m): \u001b[39m\u001b[34m\u001b[1m800.314 μs \u001b[22m\u001b[39m\u001b[90m┊\u001b[39m GC \u001b[90m(\u001b[39mmedian\u001b[90m): \u001b[39m0.00%\n",
" Time \u001b[90m(\u001b[39m\u001b[32m\u001b[1mmean\u001b[22m\u001b[39m ± \u001b[32mσ\u001b[39m\u001b[90m): \u001b[39m\u001b[32m\u001b[1m825.263 μs\u001b[22m\u001b[39m ± \u001b[32m208.306 μs\u001b[39m \u001b[90m┊\u001b[39m GC \u001b[90m(\u001b[39mmean ± σ\u001b[90m): \u001b[39m1.62% ± 5.53%\n",
"\n",
" \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m▃\u001b[39m█\u001b[39m▂\u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m▁\u001b[39m \u001b[39m▂\u001b[39m▃\u001b[39m▃\u001b[39m▂\u001b[39m▃\u001b[39m▃\u001b[39m▄\u001b[39m▅\u001b[34m▅\u001b[39m\u001b[39m▅\u001b[39m▃\u001b[32m▂\u001b[39m\u001b[39m▁\u001b[39m \u001b[39m▁\u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m▃\u001b[39m▆\u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \n",
" \u001b[39m▂\u001b[39m▂\u001b[39m▁\u001b[39m▂\u001b[39m▁\u001b[39m▁\u001b[39m▁\u001b[39m▁\u001b[39m▁\u001b[39m▁\u001b[39m▁\u001b[39m▁\u001b[39m▂\u001b[39m▂\u001b[39m▁\u001b[39m▁\u001b[39m▃\u001b[39m█\u001b[39m█\u001b[39m█\u001b[39m▇\u001b[39m█\u001b[39m█\u001b[39m█\u001b[39m█\u001b[39m█\u001b[39m█\u001b[39m█\u001b[39m█\u001b[39m█\u001b[39m█\u001b[39m█\u001b[39m█\u001b[39m█\u001b[34m█\u001b[39m\u001b[39m█\u001b[39m█\u001b[32m█\u001b[39m\u001b[39m█\u001b[39m█\u001b[39m█\u001b[39m█\u001b[39m█\u001b[39m█\u001b[39m█\u001b[39m▇\u001b[39m▆\u001b[39m▆\u001b[39m▅\u001b[39m▅\u001b[39m▄\u001b[39m▄\u001b[39m▄\u001b[39m▅\u001b[39m▇\u001b[39m█\u001b[39m█\u001b[39m█\u001b[39m▅\u001b[39m▄\u001b[39m▃\u001b[39m \u001b[39m▅\n",
" 491 μs\u001b[90m Histogram: frequency by time\u001b[39m 1.04 ms \u001b[0m\u001b[1m<\u001b[22m\n",
"\n",
" Memory estimate\u001b[90m: \u001b[39m\u001b[33m280.03 KiB\u001b[39m, allocs estimate\u001b[90m: \u001b[39m\u001b[33m2709\u001b[39m."
]
},
"metadata": {},
"output_type": "display_data"
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"Found 6 Diagrams for 2-Photon Compton\n",
"Diagram 1: Initial Particles: [k_i_1, k_i_2, e_i_1, k_o_1, e_o_1]\n",
" Virtuality Level 1 Vertices: [k_i_1 + e_i_1 -> e_i_2, k_i_2 + e_o_1 -> e_o_2]\n",
" Virtuality Level 2 Vertices: [k_o_1 + e_i_2 -> e_i_3]\n",
" Tie: e_o_2 -- e_i_3\n",
"\n"
]
}
],
"source": [
"# 2-Photon Compton Scattering\n",
"two_k_compton = FeynmanDiagram(parse_process(\"kke->ke\", QEDModel()))\n",
"\n",
"display(@benchmark gen_diagrams(two_k_compton))\n",
"diagrams = gen_diagrams(two_k_compton)\n",
"\n",
"println(\"Found $(length(diagrams)) Diagrams for 2-Photon Compton\")\n",
"println(\"Diagram 1: $(first(diagrams))\")"
]
},
{
"cell_type": "code",
"execution_count": 40,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"BenchmarkTools.Trial: 1167 samples with 1 evaluation.\n",
" Range \u001b[90m(\u001b[39m\u001b[36m\u001b[1mmin\u001b[22m\u001b[39m … \u001b[35mmax\u001b[39m\u001b[90m): \u001b[39m\u001b[36m\u001b[1m2.581 ms\u001b[22m\u001b[39m … \u001b[35m 7.394 ms\u001b[39m \u001b[90m┊\u001b[39m GC \u001b[90m(\u001b[39mmin … max\u001b[90m): \u001b[39m0.00% … 38.39%\n",
" Time \u001b[90m(\u001b[39m\u001b[34m\u001b[1mmedian\u001b[22m\u001b[39m\u001b[90m): \u001b[39m\u001b[34m\u001b[1m4.278 ms \u001b[22m\u001b[39m\u001b[90m┊\u001b[39m GC \u001b[90m(\u001b[39mmedian\u001b[90m): \u001b[39m0.00%\n",
" Time \u001b[90m(\u001b[39m\u001b[32m\u001b[1mmean\u001b[22m\u001b[39m ± \u001b[32mσ\u001b[39m\u001b[90m): \u001b[39m\u001b[32m\u001b[1m4.284 ms\u001b[22m\u001b[39m ± \u001b[32m550.104 μs\u001b[39m \u001b[90m┊\u001b[39m GC \u001b[90m(\u001b[39mmean ± σ\u001b[90m): \u001b[39m1.84% ± 6.28%\n",
"\n",
" \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m▃\u001b[39m▃\u001b[39m▅\u001b[39m▅\u001b[34m▃\u001b[39m\u001b[39m▃\u001b[39m▇\u001b[39m█\u001b[39m▄\u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \n",
" \u001b[39m▂\u001b[39m▁\u001b[39m▁\u001b[39m▁\u001b[39m▁\u001b[39m▂\u001b[39m▂\u001b[39m▁\u001b[39m▂\u001b[39m▂\u001b[39m▂\u001b[39m▄\u001b[39m█\u001b[39m▄\u001b[39m▄\u001b[39m▄\u001b[39m▃\u001b[39m▃\u001b[39m▄\u001b[39m▆\u001b[39m▇\u001b[39m█\u001b[39m█\u001b[39m█\u001b[39m█\u001b[39m█\u001b[34m█\u001b[39m\u001b[39m█\u001b[39m█\u001b[39m█\u001b[39m█\u001b[39m▆\u001b[39m▄\u001b[39m▃\u001b[39m▃\u001b[39m▂\u001b[39m▂\u001b[39m▂\u001b[39m▂\u001b[39m▂\u001b[39m▂\u001b[39m▁\u001b[39m▁\u001b[39m▁\u001b[39m▂\u001b[39m▁\u001b[39m▁\u001b[39m▁\u001b[39m▁\u001b[39m▁\u001b[39m▂\u001b[39m▃\u001b[39m▂\u001b[39m▂\u001b[39m▂\u001b[39m▂\u001b[39m▂\u001b[39m▂\u001b[39m▂\u001b[39m \u001b[39m▃\n",
" 2.58 ms\u001b[90m Histogram: frequency by time\u001b[39m 6.46 ms \u001b[0m\u001b[1m<\u001b[22m\n",
"\n",
" Memory estimate\u001b[90m: \u001b[39m\u001b[33m1.71 MiB\u001b[39m, allocs estimate\u001b[90m: \u001b[39m\u001b[33m15410\u001b[39m."
]
},
"metadata": {},
"output_type": "display_data"
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"Found 24 Diagrams for 3-Photon Compton\n",
"Diagram 1: Initial Particles: [k_i_1, k_i_2, k_i_3, e_i_1, k_o_1, e_o_1]\n",
" Virtuality Level 1 Vertices: [k_i_2 + e_o_1 -> e_o_2, k_i_3 + e_i_1 -> e_i_2]\n",
" Virtuality Level 2 Vertices: [k_i_1 + e_o_2 -> e_o_3, k_o_1 + e_i_2 -> e_i_3]\n",
" Tie: e_o_3 -- e_i_3\n",
"\n"
]
}
],
"source": [
"# 3-Photon Compton Scattering\n",
"three_k_compton = FeynmanDiagram(parse_process(\"kkke->ke\", QEDModel()))\n",
"\n",
"display(@benchmark gen_diagrams(three_k_compton))\n",
"diagrams = gen_diagrams(three_k_compton)\n",
"\n",
"println(\"Found $(length(diagrams)) Diagrams for 3-Photon Compton\")\n",
"println(\"Diagram 1: $(first(diagrams))\")"
]
},
{
"cell_type": "code",
"execution_count": 41,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"BenchmarkTools.Trial: 141 samples with 1 evaluation.\n",
" Range \u001b[90m(\u001b[39m\u001b[36m\u001b[1mmin\u001b[22m\u001b[39m … \u001b[35mmax\u001b[39m\u001b[90m): \u001b[39m\u001b[36m\u001b[1m31.255 ms\u001b[22m\u001b[39m … \u001b[35m42.658 ms\u001b[39m \u001b[90m┊\u001b[39m GC \u001b[90m(\u001b[39mmin … max\u001b[90m): \u001b[39m0.00% … 4.92%\n",
" Time \u001b[90m(\u001b[39m\u001b[34m\u001b[1mmedian\u001b[22m\u001b[39m\u001b[90m): \u001b[39m\u001b[34m\u001b[1m35.749 ms \u001b[22m\u001b[39m\u001b[90m┊\u001b[39m GC \u001b[90m(\u001b[39mmedian\u001b[90m): \u001b[39m4.34%\n",
" Time \u001b[90m(\u001b[39m\u001b[32m\u001b[1mmean\u001b[22m\u001b[39m ± \u001b[32mσ\u001b[39m\u001b[90m): \u001b[39m\u001b[32m\u001b[1m35.690 ms\u001b[22m\u001b[39m ± \u001b[32m 2.009 ms\u001b[39m \u001b[90m┊\u001b[39m GC \u001b[90m(\u001b[39mmean ± σ\u001b[90m): \u001b[39m3.04% ± 2.83%\n",
"\n",
" \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m▆\u001b[39m▁\u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m▃\u001b[39m▁\u001b[39m▁\u001b[39m \u001b[39m \u001b[39m▁\u001b[39m \u001b[39m▃\u001b[39m▁\u001b[39m▃\u001b[39m▁\u001b[39m \u001b[39m█\u001b[34m▆\u001b[39m\u001b[39m▁\u001b[39m▁\u001b[39m▆\u001b[39m▁\u001b[39m▁\u001b[39m▃\u001b[39m \u001b[39m▁\u001b[39m \u001b[39m▃\u001b[39m▆\u001b[39m▁\u001b[39m▆\u001b[39m█\u001b[39m \u001b[39m \u001b[39m \u001b[39m▁\u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m▁\u001b[39m \u001b[39m \u001b[39m \u001b[39m \n",
" \u001b[39m▇\u001b[39m▄\u001b[39m▄\u001b[39m▁\u001b[39m▁\u001b[39m▁\u001b[39m▄\u001b[39m▇\u001b[39m▇\u001b[39m▄\u001b[39m▄\u001b[39m▄\u001b[39m▇\u001b[39m▄\u001b[39m█\u001b[39m█\u001b[39m▇\u001b[39m▄\u001b[39m▇\u001b[39m▇\u001b[39m█\u001b[39m█\u001b[39m█\u001b[39m▇\u001b[39m▁\u001b[39m█\u001b[39m▄\u001b[39m█\u001b[39m█\u001b[39m█\u001b[39m█\u001b[39m▇\u001b[39m█\u001b[34m█\u001b[39m\u001b[39m█\u001b[39m█\u001b[39m█\u001b[39m█\u001b[39m█\u001b[39m█\u001b[39m▄\u001b[39m█\u001b[39m▇\u001b[39m█\u001b[39m█\u001b[39m█\u001b[39m█\u001b[39m█\u001b[39m▇\u001b[39m▇\u001b[39m▁\u001b[39m█\u001b[39m▄\u001b[39m▁\u001b[39m▄\u001b[39m▇\u001b[39m█\u001b[39m▇\u001b[39m▄\u001b[39m \u001b[39m▄\n",
" 31.3 ms\u001b[90m Histogram: frequency by time\u001b[39m 39.2 ms \u001b[0m\u001b[1m<\u001b[22m\n",
"\n",
" Memory estimate\u001b[90m: \u001b[39m\u001b[33m23.29 MiB\u001b[39m, allocs estimate\u001b[90m: \u001b[39m\u001b[33m171048\u001b[39m."
]
},
"metadata": {},
"output_type": "display_data"
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"Found 120 Diagrams for 4-Photon Compton\n",
"Diagram 1: Initial Particles: [k_i_1, k_i_2, k_i_3, k_i_4, e_i_1, k_o_1, e_o_1]\n",
" Virtuality Level 1 Vertices: [k_i_1 + e_o_1 -> e_o_2, e_i_1 + k_o_1 -> e_i_2]\n",
" Virtuality Level 2 Vertices: [k_i_3 + e_o_2 -> e_o_3, k_i_2 + e_i_2 -> e_i_3]\n",
" Virtuality Level 3 Vertices: [k_i_4 + e_o_3 -> e_o_4]\n",
" Tie: e_i_3 -- e_o_4\n",
"\n"
]
}
],
"source": [
"# 4-Photon Compton Scattering\n",
"four_k_compton = FeynmanDiagram(parse_process(\"kkkke->ke\", QEDModel()))\n",
"\n",
"display(@benchmark gen_diagrams(four_k_compton))\n",
"diagrams = gen_diagrams(four_k_compton)\n",
"\n",
"println(\"Found $(length(diagrams)) Diagrams for 4-Photon Compton\")\n",
"println(\"Diagram 1: $(first(diagrams))\")"
]
},
{
"cell_type": "code",
"execution_count": 42,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"BenchmarkTools.Trial: 10 samples with 1 evaluation.\n",
" Range \u001b[90m(\u001b[39m\u001b[36m\u001b[1mmin\u001b[22m\u001b[39m … \u001b[35mmax\u001b[39m\u001b[90m): \u001b[39m\u001b[36m\u001b[1m471.789 ms\u001b[22m\u001b[39m … \u001b[35m527.196 ms\u001b[39m \u001b[90m┊\u001b[39m GC \u001b[90m(\u001b[39mmin … max\u001b[90m): \u001b[39m6.00% … 7.35%\n",
" Time \u001b[90m(\u001b[39m\u001b[34m\u001b[1mmedian\u001b[22m\u001b[39m\u001b[90m): \u001b[39m\u001b[34m\u001b[1m499.068 ms \u001b[22m\u001b[39m\u001b[90m┊\u001b[39m GC \u001b[90m(\u001b[39mmedian\u001b[90m): \u001b[39m6.98%\n",
" Time \u001b[90m(\u001b[39m\u001b[32m\u001b[1mmean\u001b[22m\u001b[39m ± \u001b[32mσ\u001b[39m\u001b[90m): \u001b[39m\u001b[32m\u001b[1m502.132 ms\u001b[22m\u001b[39m ± \u001b[32m 17.383 ms\u001b[39m \u001b[90m┊\u001b[39m GC \u001b[90m(\u001b[39mmean ± σ\u001b[90m): \u001b[39m6.79% ± 0.77%\n",
"\n",
" \u001b[39m▁\u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m█\u001b[39m▁\u001b[39m \u001b[34m▁\u001b[39m\u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[32m \u001b[39m\u001b[39m \u001b[39m▁\u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m▁\u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m▁\u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m▁\u001b[39m▁\u001b[39m \u001b[39m \n",
" \u001b[39m█\u001b[39m▁\u001b[39m▁\u001b[39m▁\u001b[39m▁\u001b[39m▁\u001b[39m▁\u001b[39m▁\u001b[39m▁\u001b[39m▁\u001b[39m▁\u001b[39m▁\u001b[39m▁\u001b[39m▁\u001b[39m▁\u001b[39m▁\u001b[39m▁\u001b[39m▁\u001b[39m▁\u001b[39m▁\u001b[39m▁\u001b[39m█\u001b[39m█\u001b[39m▁\u001b[34m█\u001b[39m\u001b[39m▁\u001b[39m▁\u001b[39m▁\u001b[39m▁\u001b[39m▁\u001b[39m▁\u001b[39m▁\u001b[39m▁\u001b[32m▁\u001b[39m\u001b[39m▁\u001b[39m█\u001b[39m▁\u001b[39m▁\u001b[39m▁\u001b[39m▁\u001b[39m█\u001b[39m▁\u001b[39m▁\u001b[39m▁\u001b[39m▁\u001b[39m▁\u001b[39m▁\u001b[39m█\u001b[39m▁\u001b[39m▁\u001b[39m▁\u001b[39m▁\u001b[39m▁\u001b[39m▁\u001b[39m▁\u001b[39m▁\u001b[39m▁\u001b[39m▁\u001b[39m▁\u001b[39m█\u001b[39m█\u001b[39m \u001b[39m▁\n",
" 472 ms\u001b[90m Histogram: frequency by time\u001b[39m 527 ms \u001b[0m\u001b[1m<\u001b[22m\n",
"\n",
" Memory estimate\u001b[90m: \u001b[39m\u001b[33m627.12 MiB\u001b[39m, allocs estimate\u001b[90m: \u001b[39m\u001b[33m3747679\u001b[39m."
]
},
"metadata": {},
"output_type": "display_data"
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"Found 720 Diagrams for 5-Photon Compton\n",
"Diagram 1: Initial Particles: [k_i_1, k_i_2, k_i_3, k_i_4, k_i_5, e_i_1, k_o_1, e_o_1]\n",
" Virtuality Level 1 Vertices: [k_i_1 + e_i_1 -> e_i_2, k_i_4 + e_o_1 -> e_o_2]\n",
" Virtuality Level 2 Vertices: [k_i_3 + e_i_2 -> e_i_3, k_i_5 + e_o_2 -> e_o_3]\n",
" Virtuality Level 3 Vertices: [k_i_2 + e_i_3 -> e_i_4, k_o_1 + e_o_3 -> e_o_4]\n",
" Tie: e_i_4 -- e_o_4\n",
"\n"
]
}
],
"source": [
"# 5-Photon Compton Scattering\n",
"five_k_compton = FeynmanDiagram(parse_process(\"kkkkke->ke\", QEDModel()))\n",
"\n",
"display(@benchmark gen_diagrams(five_k_compton))\n",
"diagrams = gen_diagrams(five_k_compton)\n",
"\n",
"println(\"Found $(length(diagrams)) Diagrams for 5-Photon Compton\")\n",
"println(\"Diagram 1: $(first(diagrams))\")"
]
},
{
"cell_type": "code",
"execution_count": 43,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Diagram 1: Initial Particles: [p_i_1, e_i_1, e_o_1, p_o_1]\n",
" Virtuality Level 1 Vertices: [p_i_1 + e_i_1 -> k_o_2, e_o_1 + p_o_1 -> k_o_1]\n",
" Tie: k_o_2 -- k_o_1\n",
"\n",
"Diagram 2: Initial Particles: [p_i_1, e_i_1, e_o_1, p_o_1]\n",
" Virtuality Level 1 Vertices: [p_i_1 + p_o_1 -> k_o_1, e_i_1 + e_o_1 -> k_o_2]\n",
" Tie: k_o_1 -- k_o_2\n",
"\n"
]
}
],
"source": [
"# Bhabha Scattering\n",
"fd = FeynmanDiagram(parse_process(\"ep->ep\", QEDModel()))\n",
"\n",
"diagrams = gen_diagrams(fd)\n",
"\n",
"c = 1\n",
"for d in diagrams\n",
" println(\"Diagram $c: $d\")\n",
" c += 1\n",
"end"
]
},
{
"cell_type": "code",
"execution_count": 44,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Diagram 1: Initial Particles: [e_i_1, e_i_2, e_o_1, e_o_2]\n",
" Virtuality Level 1 Vertices: [e_i_2 + e_o_2 -> k_o_2, e_i_1 + e_o_1 -> k_o_1]\n",
" Tie: k_o_2 -- k_o_1\n",
"\n",
"Diagram 2: Initial Particles: [e_i_1, e_i_2, e_o_1, e_o_2]\n",
" Virtuality Level 1 Vertices: [e_i_1 + e_o_2 -> k_o_1, e_i_2 + e_o_1 -> k_o_2]\n",
" Tie: k_o_1 -- k_o_2\n",
"\n"
]
}
],
"source": [
"# Moller Scattering\n",
"fd = FeynmanDiagram(parse_process(\"ee->ee\", QEDModel()))\n",
"\n",
"diagrams = gen_diagrams(fd)\n",
"\n",
"c = 1\n",
"for d in diagrams\n",
" println(\"Diagram $c: $d\")\n",
" c += 1\n",
"end"
]
},
{
"cell_type": "code",
"execution_count": 45,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Diagram 1: Initial Particles: [p_i_1, e_i_1, k_o_1, k_o_2]\n",
" Virtuality Level 1 Vertices: [e_i_1 + k_o_2 -> e_i_2, p_i_1 + k_o_1 -> e_o_1]\n",
" Tie: e_i_2 -- e_o_1\n",
"\n",
"Diagram 2: Initial Particles: [p_i_1, e_i_1, k_o_1, k_o_2]\n",
" Virtuality Level 1 Vertices: [e_i_1 + k_o_1 -> e_i_2, p_i_1 + k_o_2 -> e_o_1]\n",
" Tie: e_i_2 -- e_o_1\n",
"\n"
]
}
],
"source": [
"# Pair annihilation\n",
"fd = FeynmanDiagram(parse_process(\"ep->kk\", QEDModel()))\n",
"\n",
"diagrams = gen_diagrams(fd)\n",
"\n",
"c = 1\n",
"for d in diagrams\n",
" println(\"Diagram $c: $d\")\n",
" c += 1\n",
"end"
]
},
{
"cell_type": "code",
"execution_count": 46,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Diagram 1: Initial Particles: [k_i_1, k_i_2, e_o_1, p_o_1]\n",
" Virtuality Level 1 Vertices: [k_i_1 + p_o_1 -> e_i_1, k_i_2 + e_o_1 -> e_o_2]\n",
" Tie: e_i_1 -- e_o_2\n",
"\n",
"Diagram 2: Initial Particles: [k_i_1, k_i_2, e_o_1, p_o_1]\n",
" Virtuality Level 1 Vertices: [k_i_1 + e_o_1 -> e_o_2, k_i_2 + p_o_1 -> e_i_1]\n",
" Tie: e_o_2 -- e_i_1\n",
"\n"
]
}
],
"source": [
"# Pair production\n",
"fd = FeynmanDiagram(parse_process(\"kk->pe\", QEDModel()))\n",
"\n",
"diagrams = gen_diagrams(fd)\n",
"\n",
"c = 1\n",
"for d in diagrams\n",
" println(\"Diagram $c: $d\")\n",
" c += 1\n",
"end"
]
},
{
"cell_type": "code",
"execution_count": 47,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Found 8 diagrams:\n",
"Diagram 1: Initial Particles: [k_i_1, e_i_1, e_o_1, e_o_2, p_o_1]\n",
" Virtuality Level 1 Vertices: [k_i_1 + e_o_1 -> e_o_3, e_i_1 + e_o_2 -> k_o_1]\n",
" Virtuality Level 2 Vertices: [p_o_1 + k_o_1 -> e_i_2]\n",
" Tie: e_o_3 -- e_i_2\n",
"\n",
"Diagram 2: Initial Particles: [k_i_1, e_i_1, e_o_1, e_o_2, p_o_1]\n",
" Virtuality Level 1 Vertices: [k_i_1 + p_o_1 -> e_i_2, e_i_1 + e_o_2 -> k_o_1]\n",
" Virtuality Level 2 Vertices: [e_o_1 + e_i_2 -> k_o_2]\n",
" Tie: k_o_1 -- k_o_2\n",
"\n",
"Diagram 3: Initial Particles: [k_i_1, e_i_1, e_o_1, e_o_2, p_o_1]\n",
" Virtuality Level 1 Vertices: [k_i_1 + e_o_2 -> e_o_3, e_i_1 + e_o_1 -> k_o_1]\n",
" Virtuality Level 2 Vertices: [p_o_1 + e_o_3 -> k_o_2]\n",
" Tie: k_o_1 -- k_o_2\n",
"\n",
"Diagram 4: Initial Particles: [k_i_1, e_i_1, e_o_1, e_o_2, p_o_1]\n",
" Virtuality Level 1 Vertices: [k_i_1 + e_i_1 -> e_i_2, e_o_2 + p_o_1 -> k_o_1]\n",
" Virtuality Level 2 Vertices: [e_o_1 + e_i_2 -> k_o_2]\n",
" Tie: k_o_1 -- k_o_2\n",
"\n",
"Diagram 5: Initial Particles: [k_i_1, e_i_1, e_o_1, e_o_2, p_o_1]\n",
" Virtuality Level 1 Vertices: [k_i_1 + e_o_1 -> e_o_3, e_o_2 + p_o_1 -> k_o_1]\n",
" Virtuality Level 2 Vertices: [e_i_1 + k_o_1 -> e_i_2]\n",
" Tie: e_o_3 -- e_i_2\n",
"\n",
"Diagram 6: Initial Particles: [k_i_1, e_i_1, e_o_1, e_o_2, p_o_1]\n",
" Virtuality Level 1 Vertices: [k_i_1 + e_o_2 -> e_o_3, e_o_1 + p_o_1 -> k_o_1]\n",
" Virtuality Level 2 Vertices: [e_i_1 + e_o_3 -> k_o_2]\n",
" Tie: k_o_1 -- k_o_2\n",
"\n",
"Diagram 7: Initial Particles: [k_i_1, e_i_1, e_o_1, e_o_2, p_o_1]\n",
" Virtuality Level 1 Vertices: [k_i_1 + p_o_1 -> e_i_2, e_i_1 + e_o_1 -> k_o_1]\n",
" Virtuality Level 2 Vertices: [e_o_2 + k_o_1 -> e_o_3]\n",
" Tie: e_i_2 -- e_o_3\n",
"\n",
"Diagram 8: Initial Particles: [k_i_1, e_i_1, e_o_1, e_o_2, p_o_1]\n",
" Virtuality Level 1 Vertices: [k_i_1 + e_i_1 -> e_i_2, e_o_1 + p_o_1 -> k_o_1]\n",
" Virtuality Level 2 Vertices: [e_o_2 + k_o_1 -> e_o_3]\n",
" Tie: e_i_2 -- e_o_3\n",
"\n"
]
}
],
"source": [
"# Trident\n",
"fd = FeynmanDiagram(parse_process(\"ke->epe\", QEDModel()))\n",
"\n",
"diagrams = gen_diagrams(fd)\n",
"\n",
"println(\"Found $(length(diagrams)) diagrams:\")\n",
"c = 1\n",
"for d in diagrams\n",
" println(\"Diagram $c: $d\")\n",
" c += 1\n",
"end"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Julia 1.9.4",
"language": "julia",
"name": "julia-1.9"
},
"language_info": {
"file_extension": ".jl",
"mimetype": "application/julia",
"name": "julia",
"version": "1.9.4"
}
},
"nbformat": 4,
"nbformat_minor": 2
}

View File

@ -0,0 +1,111 @@
{
"cells": [
{
"cell_type": "code",
"execution_count": 1,
"id": "595a07c5-0ecc-4f3e-8cbe-63fc64b456da",
"metadata": {},
"outputs": [
{
"name": "stderr",
"output_type": "stream",
"text": [
"\u001b[36m\u001b[1m[ \u001b[22m\u001b[39m\u001b[36m\u001b[1mInfo: \u001b[22m\u001b[39mPrecompiling MetagraphOptimization [3e869610-d48d-4942-ba70-c1b702a33ca4]\n"
]
},
{
"data": {
"text/plain": [
"1"
]
},
"execution_count": 1,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"using BenchmarkTools; using Profile; using PProf; using Revise; using MetagraphOptimization;\n",
"Threads.nthreads()"
]
},
{
"cell_type": "code",
"execution_count": 2,
"id": "163f84be-1e2e-480e-9944-1fa4e0eedf3b",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Found 1 NUMA nodes\n",
"CUDA is non-functional\n"
]
},
{
"data": {
"text/plain": [
"QED Process: 'ke->kkkkke'"
]
},
"execution_count": 2,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"machine = get_machine_info()\n",
"model = QEDModel()\n",
"process = parse_process(\"ke->kkkkke\", model)"
]
},
{
"cell_type": "code",
"execution_count": 6,
"id": "6c2eef40-5df0-4396-8e62-5204c4de61f3",
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"\"profile.pb.gz\""
]
},
"execution_count": 6,
"metadata": {},
"output_type": "execute_result"
},
{
"name": "stderr",
"output_type": "stream",
"text": [
"Main binary filename not available.\n",
"Serving web UI on http://localhost:57599\n"
]
}
],
"source": [
"gen_graph(parse_process(\"ke->kke\", model))\n",
"Profile.clear()\n",
"@profile gen_graph(process)\n",
"pprof()"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Julia 1.9.4",
"language": "julia",
"name": "julia-1.9"
},
"language_info": {
"file_extension": ".jl",
"mimetype": "application/julia",
"name": "julia",
"version": "1.9.4"
}
},
"nbformat": 4,
"nbformat_minor": 5
}

View File

@ -0,0 +1,129 @@
{
"cells": [
{
"cell_type": "code",
"execution_count": 5,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"12"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"using MetagraphOptimization\n",
"using BenchmarkTools\n",
"\n",
"Threads.nthreads()"
]
},
{
"cell_type": "code",
"execution_count": 6,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"Graph:\n",
" Nodes: Total: 131069, DataTask: 65539, ComputeTaskQED_Sum: 1, \n",
" ComputeTaskQED_V: 35280, ComputeTaskQED_S2: 5040, ComputeTaskQED_U: 9, \n",
" ComputeTaskQED_S1: 25200\n",
" Edges: 176419\n",
" Total Compute Effort: 549370.0\n",
" Total Data Transfer: 1.0645344e7\n",
" Total Compute Intensity: 0.05160659909158408\n"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"machine = get_machine_info()\n",
"model = QEDModel()\n",
"process = parse_process(\"ke->kkkkkke\", model)\n",
"\n",
"inputs = [gen_process_input(process) for _ in 1:1e3];\n",
"graph = gen_graph(process)"
]
},
{
"cell_type": "code",
"execution_count": 7,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"Graph:\n",
" Nodes: Total: 14783, DataTask: 7396, ComputeTaskQED_Sum: 1, \n",
" ComputeTaskQED_V: 1819, ComputeTaskQED_S2: 5040, ComputeTaskQED_U: 9, \n",
" ComputeTaskQED_S1: 518\n",
" Edges: 26672\n",
" Total Compute Effort: 77102.0\n",
" Total Data Transfer: 5.063616e6\n",
" Total Compute Intensity: 0.015226668056977465\n"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"optimizer = ReductionOptimizer()\n",
"\n",
"optimize_to_fixpoint!(optimizer, graph)\n",
"graph"
]
},
{
"cell_type": "code",
"execution_count": 8,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Calculated 15537.0 results/s, 1295.0 results/s per thread for QED Process: 'ke->kkkkkke' (12 threads)\n"
]
}
],
"source": [
"compute_compton_reduced = get_compute_function(graph, process, machine)\n",
"outputs = [zero(ComplexF64) for _ in 1:1e6]\n",
"\n",
"bench_result = @benchmark begin\n",
" Threads.@threads :static for i in eachindex(inputs)\n",
" outputs[i] = compute_compton_reduced(inputs[i])\n",
" end\n",
"end\n",
"\n",
"rate = length(inputs) / (mean(bench_result.times) / 1.0e9)\n",
"rate_per_thread = rate / Threads.nthreads()\n",
"println(\"Calculated $(round(rate)) results/s, $(round(rate_per_thread)) results/s per thread for $(process) ($(Threads.nthreads()) threads)\")"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Julia 1.9.4",
"language": "julia",
"name": "julia-1.9"
},
"language_info": {
"file_extension": ".jl",
"mimetype": "application/julia",
"name": "julia",
"version": "1.9.4"
}
},
"nbformat": 4,
"nbformat_minor": 4
}

69
notebooks/profiling.ipynb Normal file
View File

@ -0,0 +1,69 @@
{
"cells": [
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"using Revise; using MetagraphOptimization; using BenchmarkTools; using ProfileView\n",
"using Base.Threads\n",
"nthreads()"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"model = ABCModel()\n",
"process_str = \"AB->ABBBBB\"\n",
"process = parse_process(process_str, model)\n",
"graph = parse_dag(\"../input/$process_str.txt\", model)\n",
"print(graph)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"@ProfileView.profview optimize_to_fixpoint!(ReductionOptimizer(), graph)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"@ProfileView.profview comp_func = get_compute_function(graph, process, get_machine_info())"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": []
}
],
"metadata": {
"kernelspec": {
"display_name": "Julia 1.9.4",
"language": "julia",
"name": "julia-1.9"
},
"language_info": {
"file_extension": ".jl",
"mimetype": "application/julia",
"name": "julia",
"version": "1.9.4"
},
"orig_nbformat": 4
},
"nbformat": 4,
"nbformat_minor": 2
}

164
results/FWKHIP8999 Normal file
View File

@ -0,0 +1,164 @@
Commit Hash: a7fb15c95b63eee40eb7b9324d83b748053c5e13
Run with 32 Threads
AB->AB:
Graph:
Nodes: Total: 34, ComputeTaskABC_S2: 2, ComputeTaskABC_U: 4,
ComputeTaskABC_Sum: 1, ComputeTaskABC_V: 4, ComputeTaskABC_P: 4,
DataTask: 19
Edges: 37
Total Compute Effort: 185
Total Data Transfer: 104
Total Compute Intensity: 1.7788461538461537
28.171 μs (515 allocations: 52.06 KiB)
Get Operations:
Sorting...
0.218136 seconds (155.59 k allocations: 10.433 MiB, 3.34% gc time, 3175.93% compilation time)
Node Reductions...
0.299127 seconds (257.04 k allocations: 16.853 MiB, 2827.94% compilation time)
Node Fusions...
0.046983 seconds (16.70 k allocations: 1.120 MiB, 3048.15% compilation time)
Node Splits...
0.033681 seconds (14.09 k allocations: 958.144 KiB, 3166.45% compilation time)
Waiting...
0.000001 seconds
1.096006 seconds (581.46 k allocations: 38.180 MiB, 0.66% gc time, 1677.26% compilation time)
AB->ABBB:
Graph:
Nodes: Total: 280, ComputeTaskABC_S2: 24, ComputeTaskABC_U: 6,
ComputeTaskABC_V: 64, ComputeTaskABC_Sum: 1, ComputeTaskABC_P: 6,
ComputeTaskABC_S1: 36, DataTask: 143
Edges: 385
Total Compute Effort: 2007
Total Data Transfer: 1176
Total Compute Intensity: 1.7066326530612246
207.236 μs (4324 allocations: 296.87 KiB)
Get Operations:
Sorting...
0.000120 seconds (167 allocations: 16.750 KiB)
Node Reductions...
0.000550 seconds (1.98 k allocations: 351.234 KiB)
Node Fusions...
0.000168 seconds (417 allocations: 83.797 KiB)
Node Splits...
0.000150 seconds (478 allocations: 36.406 KiB)
Waiting...
0.000000 seconds
0.039897 seconds (16.19 k allocations: 1.440 MiB, 95.31% compilation time)
AB->ABBBBB:
Graph:
Nodes: Total: 7854, ComputeTaskABC_S2: 720, ComputeTaskABC_U: 8,
ComputeTaskABC_V: 1956, ComputeTaskABC_Sum: 1, ComputeTaskABC_P: 8,
ComputeTaskABC_S1: 1230, DataTask: 3931
Edges: 11241
Total Compute Effort: 58789
Total Data Transfer: 34826
Total Compute Intensity: 1.6880778728536152
5.787 ms (121839 allocations: 7.72 MiB)
Get Operations:
Sorting...
0.000499 seconds (175 allocations: 17.000 KiB)
Node Reductions...
0.002126 seconds (45.76 k allocations: 4.477 MiB)
Node Fusions...
0.000949 seconds (7.09 k allocations: 1.730 MiB)
Node Splits...
0.000423 seconds (8.06 k allocations: 544.031 KiB)
Waiting...
0.000000 seconds
0.015005 seconds (100.12 k allocations: 13.161 MiB)
AB->ABBBBBBB:
Graph:
Nodes: Total: 438436, ComputeTaskABC_S2: 40320, ComputeTaskABC_U: 10,
ComputeTaskABC_V: 109600, ComputeTaskABC_Sum: 1, ComputeTaskABC_P: 10,
ComputeTaskABC_S1: 69272, DataTask: 219223
Edges: 628665
Total Compute Effort: 3288131
Total Data Transfer: 1949004
Total Compute Intensity: 1.687082735592128
1.309 s (6826397 allocations: 430.63 MiB)
Get Operations:
Sorting...
0.011898 seconds (197 allocations: 17.688 KiB)
Node Reductions...
0.110569 seconds (2.78 M allocations: 225.675 MiB)
Node Fusions...
0.022475 seconds (380.91 k allocations: 108.982 MiB)
Node Splits...
0.011369 seconds (438.80 k allocations: 28.743 MiB)
Waiting...
0.000001 seconds
2.503065 seconds (5.77 M allocations: 683.968 MiB, 48.27% gc time)
AB->ABBBBBBBBB:
Graph:
Nodes: Total: 39456442, ComputeTaskABC_S2: 3628800, ComputeTaskABC_U: 12,
ComputeTaskABC_V: 9864100, ComputeTaskABC_Sum: 1, ComputeTaskABC_P: 12,
ComputeTaskABC_S1: 6235290, DataTask: 19728227
Edges: 56578129
Total Compute Effort: 295923153
Total Data Transfer: 175407750
Total Compute Intensity: 1.6870585991782006
389.495 s (626095682 allocations: 37.80 GiB)
Get Operations:
Sorting...
1.181713 seconds (197 allocations: 17.688 KiB)
Node Reductions...
10.057358 seconds (251.09 M allocations: 19.927 GiB)
Node Fusions...
1.288635 seconds (34.24 M allocations: 6.095 GiB)
Node Splits...
0.719345 seconds (39.46 M allocations: 2.522 GiB)
Waiting...
0.000001 seconds
904.138951 seconds (519.47 M allocations: 54.494 GiB, 25.03% gc time)
ABAB->ABAB:
Graph:
Nodes: Total: 3218, ComputeTaskABC_S2: 288, ComputeTaskABC_U: 8,
ComputeTaskABC_V: 796, ComputeTaskABC_Sum: 1, ComputeTaskABC_P: 8,
ComputeTaskABC_S1: 504, DataTask: 1613
Edges: 4581
Total Compute Effort: 24009
Total Data Transfer: 14144
Total Compute Intensity: 1.697468891402715
2.691 ms (49557 allocations: 3.17 MiB)
Get Operations:
Sorting...
0.000246 seconds (171 allocations: 16.875 KiB)
Node Reductions...
0.001037 seconds (19.42 k allocations: 1.751 MiB)
Node Fusions...
0.001512 seconds (3.04 k allocations: 1.027 MiB)
Node Splits...
0.000197 seconds (3.41 k allocations: 231.078 KiB)
Waiting...
0.000000 seconds
0.007492 seconds (42.20 k allocations: 5.399 MiB)
ABAB->ABC:
Graph:
Nodes: Total: 817, ComputeTaskABC_S2: 72, ComputeTaskABC_U: 7,
ComputeTaskABC_V: 198, ComputeTaskABC_Sum: 1, ComputeTaskABC_P: 7,
ComputeTaskABC_S1: 120, DataTask: 412
Edges: 1151
Total Compute Effort: 6028
Total Data Transfer: 3538
Total Compute Intensity: 1.7037874505370265
602.767 μs (12544 allocations: 843.16 KiB)
Get Operations:
Sorting...
0.000127 seconds (171 allocations: 16.875 KiB)
Node Reductions...
0.000440 seconds (5.33 k allocations: 494.047 KiB)
Node Fusions...
0.001761 seconds (939 allocations: 280.797 KiB)
Node Splits...
0.000123 seconds (1.00 k allocations: 72.109 KiB)
Waiting...
0.000000 seconds
0.003831 seconds (11.74 k allocations: 1.451 MiB)

30
results/temp.md Normal file
View File

@ -0,0 +1,30 @@
(AB->ABBBBBBB, 1) 1.620 s (5909018 allocations: 656.78 MiB)
(AB->ABBBBBBB, 2) 758.299 ms (5909088 allocations: 765.78 MiB)
(AB->ABBBBBBB, 3) 595.788 ms (5909161 allocations: 748.89 MiB)
(AB->ABBBBBBB, 4) 849.007 ms (5880250 allocations: 762.00 MiB)
(AB->ABBBBBBB, 5) 563.021 ms (5880332 allocations: 781.17 MiB)
(AB->ABBBBBBB, 6) 526.095 ms (5880419 allocations: 818.32 MiB)
(AB->ABBBBBBB, 7) 586.057 ms (5880482 allocations: 826.36 MiB)
(AB->ABBBBBBB, 8) 504.515 ms (5880542 allocations: 796.58 MiB)
(AB->ABBBBBBB, 1) 1.537 s (5596315 allocations: 616.81 MiB)
(AB->ABBBBBBB, 2) 826.918 ms (5596385 allocations: 725.81 MiB)
(AB->ABBBBBBB, 3) 538.787 ms (5596457 allocations: 708.92 MiB)
(AB->ABBBBBBB, 4) 918.853 ms (5596528 allocations: 725.08 MiB)
(AB->ABBBBBBB, 5) 511.959 ms (5596606 allocations: 744.25 MiB)
(AB->ABBBBBBB, 6) 887.160 ms (5596691 allocations: 763.42 MiB)
(AB->ABBBBBBB, 7) 898.757 ms (5596762 allocations: 789.91 MiB)
(AB->ABBBBBBB, 8) 497.545 ms (5596820 allocations: 759.66 MiB)
Initial:
$ julia --project=examples/ -e 'using BenchmarkTools; using MetagraphOptimization; parse_abc("input/AB->AB.txt"); @time g = parse_abc("input/AB->ABBBBBBBBB.txt")'
65.370947 seconds (626.10 M allocations: 37.381 GiB, 53.59% gc time, 0.01% compilation time)
Removing make_edge from calls in parse:
50.053920 seconds (593.41 M allocations: 32.921 GiB, 49.70% gc time, 0.09% compilation time)
Nodes operation storage rework (and O3):
31.997128 seconds (450.66 M allocations: 25.294 GiB, 31.56% gc time, 0.14% compilation time)

25
scripts/bench_threads.fish Executable file
View File

@ -0,0 +1,25 @@
#!/bin/fish
set minthreads 1
set maxthreads 8
julia --project=./examples -t 4 -e 'import Pkg; Pkg.instantiate()'
#for i in $(seq $minthreads $maxthreads)
# printf "(AB->AB, $i) "
# julia --project=./examples -t $i -O3 -e 'using MetagraphOptimization; using BenchmarkTools; @btime get_operations(graph) setup=(graph = parse_dag("input/AB->AB.txt"), ABCModel())'
#end
#for i in $(seq $minthreads $maxthreads)
# printf "(AB->ABBB, $i) "
# julia --project=./examples -t $i -O3 -e 'using MetagraphOptimization; using BenchmarkTools; @btime get_operations(graph) setup=(graph = parse_dag("input/AB->ABBB.txt"), ABCModel())'
#end
#for i in $(seq $minthreads $maxthreads)
# printf "(AB->ABBBBB, $i) "
# julia --project=./examples -t $i -O3 -e 'using MetagraphOptimization; using BenchmarkTools; @btime get_operations(graph) setup=(graph = parse_dag("input/AB->ABBBBB.txt"), ABCModel())'
#end
for i in $(seq $minthreads $maxthreads)
printf "(AB->ABBBBBBB, $i) "
julia --project=./examples -t $i -O3 -e 'using MetagraphOptimization; using BenchmarkTools; @btime get_operations(graph) setup=(graph = parse_dag("input/AB->ABBBBBBB.txt"), ABCModel())'
end

View File

@ -1,36 +1,205 @@
"""
MetagraphOptimization
A module containing tools to work on DAGs.
"""
module MetagraphOptimization
export Node, Edge, ComputeTaskNode, DataTaskNode, DAG
export AbstractTask, AbstractComputeTask, AbstractDataTask, DataTask, FusedComputeTask
export make_node, make_edge, insert_node, insert_edge, is_entry_node, is_exit_node, parents, children, compute, graph_properties, get_exit_node, is_valid
export NodeFusion, NodeReduction, NodeSplit, push_operation!, pop_operation!, can_pop, reset_graph!, get_operations
export parse_abc, ComputeTaskP, ComputeTaskS1, ComputeTaskS2, ComputeTaskV, ComputeTaskU, ComputeTaskSum
using QEDbase
# graph types
export DAG
export Node
export Edge
export ComputeTaskNode
export DataTaskNode
export AbstractTask
export AbstractComputeTask
export AbstractDataTask
export DataTask
export FusedComputeTask
export PossibleOperations
export GraphProperties
# graph functions
export make_node
export make_edge
export insert_node
export insert_edge
export is_entry_node
export is_exit_node
export parents
export children
export compute
export data
export compute_effort
export task
export get_properties
export get_exit_node
export operation_stack_length
export is_valid, is_scheduled
# graph operation related
export Operation
export AppliedOperation
export NodeFusion
export NodeReduction
export NodeSplit
export push_operation!
export pop_operation!
export can_pop
export reset_graph!
export get_operations
# ABC model
export ParticleValue
export ParticleA, ParticleB, ParticleC
export ABCParticle, ABCProcessDescription, ABCProcessInput, ABCModel
export ComputeTaskABC_P
export ComputeTaskABC_S1
export ComputeTaskABC_S2
export ComputeTaskABC_V
export ComputeTaskABC_U
export ComputeTaskABC_Sum
# QED model
export FeynmanDiagram, FeynmanVertex, FeynmanTie, FeynmanParticle
export PhotonStateful, FermionStateful, AntiFermionStateful
export QEDParticle, QEDProcessDescription, QEDProcessInput, QEDModel
export ComputeTaskQED_P
export ComputeTaskQED_S1
export ComputeTaskQED_S2
export ComputeTaskQED_V
export ComputeTaskQED_U
export ComputeTaskQED_Sum
export gen_graph
# code generation related
export execute
export parse_dag, parse_process
export gen_process_input
export get_compute_function
# estimator
export cost_type, graph_cost, operation_effect
export GlobalMetricEstimator, CDCost
# optimization
export AbstractOptimizer, GreedyOptimizer, ReductionOptimizer, RandomWalkOptimizer
export optimize_step!, optimize!
export fixpoint_reached, optimize_to_fixpoint!
# machine info
export Machine
export get_machine_info
export ==, in, show, isempty, delete!, length
export bytes_to_human_readable
# TODO: this is probably not good
import QEDprocesses.compute
import Base.length
import Base.show
import Base.==
import Base.+
import Base.-
import Base.in
import Base.copy
import Base.isempty
import Base.delete!
import Base.insert!
import Base.collect
include("tasks.jl")
include("nodes.jl")
include("graph.jl")
include("devices/interface.jl")
include("task/type.jl")
include("node/type.jl")
include("diff/type.jl")
include("properties/type.jl")
include("operation/type.jl")
include("graph/type.jl")
include("task_functions.jl")
include("node_functions.jl")
include("graph_functions.jl")
include("graph_operations.jl")
include("trie.jl")
include("utility.jl")
include("abc_model/tasks.jl")
include("abc_model/task_functions.jl")
include("abc_model/parse.jl")
include("diff/print.jl")
include("diff/properties.jl")
include("graph/compare.jl")
include("graph/interface.jl")
include("graph/mute.jl")
include("graph/print.jl")
include("graph/properties.jl")
include("graph/validate.jl")
include("node/compare.jl")
include("node/create.jl")
include("node/print.jl")
include("node/properties.jl")
include("node/validate.jl")
include("operation/utility.jl")
include("operation/iterate.jl")
include("operation/apply.jl")
include("operation/clean.jl")
include("operation/find.jl")
include("operation/get.jl")
include("operation/print.jl")
include("operation/validate.jl")
include("properties/create.jl")
include("properties/utility.jl")
include("task/create.jl")
include("task/compare.jl")
include("task/compute.jl")
include("task/print.jl")
include("task/properties.jl")
include("estimator/interface.jl")
include("estimator/global_metric.jl")
include("optimization/interface.jl")
include("optimization/greedy.jl")
include("optimization/random_walk.jl")
include("optimization/reduce.jl")
include("models/interface.jl")
include("models/print.jl")
include("models/abc/types.jl")
include("models/abc/particle.jl")
include("models/abc/compute.jl")
include("models/abc/create.jl")
include("models/abc/properties.jl")
include("models/abc/parse.jl")
include("models/abc/print.jl")
include("models/qed/types.jl")
include("models/qed/particle.jl")
include("models/qed/diagrams.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("devices/measure.jl")
include("devices/detect.jl")
include("devices/impl.jl")
include("devices/numa/impl.jl")
include("devices/cuda/impl.jl")
# can currently not use AMDGPU because of incompatability with the newest rocm drivers
# include("devices/rocm/impl.jl")
# oneapi seems also broken for now
# include("devices/oneapi/impl.jl")
include("scheduler/interface.jl")
include("scheduler/greedy.jl")
include("code_gen/main.jl")
end # module MetagraphOptimization

View File

@ -1,149 +0,0 @@
using Printf
# functions for importing DAGs from a file
regex_a = r"^[A-C]\d+$" # Regex for the initial particles
regex_c = r"^[A-C]\(([^']*),([^']*)\)$" # Regex for the combinations of 2 particles
regex_m = r"^M\(([^']*),([^']*),([^']*)\)$" # Regex for the combinations of 3 particles
regex_plus = r"^\+$" # Regex for the sum
function parse_nodes(input::AbstractString)
regex = r"'([^']*)'"
matches = eachmatch(regex, input)
output = [match.captures[1] for match in matches]
return output
end
function parse_edges(input::AbstractString)
regex = r"\('([^']*)', '([^']*)'\)"
matches = eachmatch(regex, input)
output = [(match.captures[1], match.captures[2]) for match in matches]
return output
end
# reads an abc-model process from the given file
function parse_abc(filename::String, verbose::Bool = false)
file = open(filename, "r")
if (verbose) println("Opened file") end
nodes_string = readline(file)
nodes = parse_nodes(nodes_string)
close(file)
if (verbose) println("Read file") end
graph = DAG()
# estimate total number of nodes
# try to slightly overestimate so no resizing is necessary
# data nodes are not included in length(nodes) and there are a few more than compute nodes
estimate_no_nodes = round(Int, length(nodes) * 4)
if (verbose) println("Estimating ", estimate_no_nodes, " Nodes") end
sizehint!(graph.nodes, estimate_no_nodes)
sum_node = insert_node!(graph, make_node(ComputeTaskSum()), false)
global_data_out = insert_node!(graph, make_node(DataTask(10)), false)
insert_edge!(graph, make_edge(sum_node, global_data_out), false)
# remember the data out nodes for connection
dataOutNodes = Dict()
if (verbose) println("Building graph") end
noNodes = 0
nodesToRead = length(nodes)
while !isempty(nodes)
node = popfirst!(nodes)
noNodes += 1
if (noNodes % 100 == 0)
if (verbose) @printf "\rReading Nodes... %.2f%%" (100. * noNodes / nodesToRead) end
end
if occursin(regex_a, node)
# add nodes and edges for the state reading to u(P(Particle))
data_in = insert_node!(graph, make_node(DataTask(4)), false) # read particle data node
compute_P = insert_node!(graph, make_node(ComputeTaskP()), false) # compute P node
data_Pu = insert_node!(graph, make_node(DataTask(6)), false) # transfer data from P to u
compute_u = insert_node!(graph, make_node(ComputeTaskU()), false) # compute U node
data_out = insert_node!(graph, make_node(DataTask(3)), false) # transfer data out from u
insert_edge!(graph, make_edge(data_in, compute_P), false)
insert_edge!(graph, make_edge(compute_P, data_Pu), false)
insert_edge!(graph, make_edge(data_Pu, compute_u), false)
insert_edge!(graph, make_edge(compute_u, data_out), false)
# remember the data_out node for future edges
dataOutNodes[node] = data_out
elseif occursin(regex_c, node)
capt = match(regex_c, node)
in1 = capt.captures[1]
in2 = capt.captures[2]
compute_v = insert_node!(graph, make_node(ComputeTaskV()), false)
data_out = insert_node!(graph, make_node(DataTask(5)), false)
if (occursin(regex_c, capt.captures[1]))
# put an S node after this input
compute_S = insert_node!(graph, make_node(ComputeTaskS1()), false)
data_S_v = insert_node!(graph, make_node(DataTask(5)), false)
insert_edge!(graph, make_edge(dataOutNodes[capt.captures[1]], compute_S), false)
insert_edge!(graph, make_edge(compute_S, data_S_v), false)
insert_edge!(graph, make_edge(data_S_v, compute_v), false)
else
insert_edge!(graph, make_edge(dataOutNodes[capt.captures[1]], compute_v), false)
end
if (occursin(regex_c, capt.captures[2]))
# i think the current generator only puts the combined particles in the first space, so this case might never be entered
# put an S node after this input
compute_S = insert_node!(graph, make_node(ComputeTaskS1()), false)
data_S_v = insert_node!(graph, make_node(DataTask(5)), false)
insert_edge!(graph, make_edge(dataOutNodes[capt.captures[2]], compute_S), false)
insert_edge!(graph, make_edge(compute_S, data_S_v), false)
insert_edge!(graph, make_edge(data_S_v, compute_v), false)
else
insert_edge!(graph, make_edge(dataOutNodes[capt.captures[2]], compute_v), false)
end
insert_edge!(graph, make_edge(compute_v, data_out), false)
dataOutNodes[node] = data_out
elseif occursin(regex_m, node)
# assume for now that only the first particle of the three is combined and the other two are "original" ones
capt = match(regex_m, node)
in1 = capt.captures[1]
in2 = capt.captures[2]
in3 = capt.captures[3]
# in2 + in3 with a v
compute_v = insert_node!(graph, make_node(ComputeTaskV()), false)
data_v = insert_node!(graph, make_node(DataTask(5)), false)
insert_edge!(graph, make_edge(dataOutNodes[in2], compute_v), false)
insert_edge!(graph, make_edge(dataOutNodes[in3], compute_v), false)
insert_edge!(graph, make_edge(compute_v, data_v), false)
# combine with the v of the combined other input
compute_S2 = insert_node!(graph, make_node(ComputeTaskS2()), false)
data_out = insert_node!(graph, make_node(DataTask(10)), false)
insert_edge!(graph, make_edge(data_v, compute_S2), false)
insert_edge!(graph, make_edge(dataOutNodes[in1], compute_S2), false)
insert_edge!(graph, make_edge(compute_S2, data_out), false)
insert_edge!(graph, make_edge(data_out, sum_node), false)
elseif occursin(regex_plus, node)
if (verbose)
println("\rReading Nodes Complete ")
println("Added ", length(graph.nodes), " nodes")
end
else
error("Unknown node '", node, "' while reading from file ", filename)
end
end
# don't actually need to read the edges
return graph
end

View File

@ -1,21 +0,0 @@
# define compute_efforts tasks computation
# put some "random" numbers here for now
compute_effort(t::ComputeTaskS1) = 10
compute_effort(t::ComputeTaskS2) = 10
compute_effort(t::ComputeTaskU) = 6
compute_effort(t::ComputeTaskV) = 20
compute_effort(t::ComputeTaskP) = 15
compute_effort(t::ComputeTaskSum) = 1
function show(io::IO, t::DataTask)
print(io, "Data", t.data)
end
show(io::IO, t::ComputeTaskS1) = print("ComputeS1")
show(io::IO, t::ComputeTaskS2) = print("ComputeS2")
show(io::IO, t::ComputeTaskP) = print("ComputeP")
show(io::IO, t::ComputeTaskU) = print("ComputeU")
show(io::IO, t::ComputeTaskV) = print("ComputeV")
show(io::IO, t::ComputeTaskSum) = print("ComputeSum")
copy(t::DataTask) = DataTask(t.data)

View File

@ -1,27 +0,0 @@
struct DataTask <: AbstractDataTask
data::UInt64
end
# S task with 1 child
struct ComputeTaskS1 <: AbstractComputeTask
end
# S task with 2 children
struct ComputeTaskS2 <: AbstractComputeTask
end
# P task with 0 children
struct ComputeTaskP <: AbstractComputeTask
end
# v task with 2 children
struct ComputeTaskV <: AbstractComputeTask
end
# u task with 1 child
struct ComputeTaskU <: AbstractComputeTask
end
# task that sums all its inputs, n children
struct ComputeTaskSum <: AbstractComputeTask
end

155
src/code_gen/main.jl Normal file
View File

@ -0,0 +1,155 @@
"""
gen_code(graph::DAG)
Generate the code for a given graph. The return value is a named tuple of:
- `code::Expr`: The julia expression containing the code for the whole graph.
- `inputSymbols::Dict{String, Vector{Symbol}}`: A dictionary of symbols mapping the names of the input nodes of the graph to the symbols their inputs should be provided on.
- `outputSymbol::Symbol`: The symbol of the final calculated value
See also: [`execute`](@ref)
"""
function gen_code(graph::DAG, machine::Machine)
sched = schedule_dag(GreedyScheduler(), graph, machine)
codeAcc = Vector{Expr}()
sizehint!(codeAcc, length(graph.nodes))
for node in sched
# TODO: this is kind of ugly, should init nodes be scheduled differently from the rest?
if (node isa DataTaskNode && length(node.children) == 0)
push!(codeAcc, get_init_expression(node, entry_device(machine)))
continue
end
push!(codeAcc, get_expression(node))
end
# get inSymbols
inputSyms = Dict{String, Vector{Symbol}}()
for node in get_entry_nodes(graph)
if !haskey(inputSyms, node.name)
inputSyms[node.name] = Vector{Symbol}()
end
push!(inputSyms[node.name], Symbol("$(to_var_name(node.id))_in"))
end
# get outSymbol
outSym = Symbol(to_var_name(get_exit_node(graph).id))
return (code = Expr(:block, codeAcc...), inputSymbols = inputSyms, outputSymbol = outSym)
end
function gen_cache_init_code(machine::Machine)
initializeCaches = Vector{Expr}()
for device in machine.devices
push!(initializeCaches, gen_cache_init_code(device))
end
return Expr(:block, initializeCaches...)
end
function gen_input_assignment_code(
inputSymbols::Dict{String, Vector{Symbol}},
processDescription::AbstractProcessDescription,
machine::Machine,
processInputSymbol::Symbol = :input,
)
@assert length(inputSymbols) >=
sum(values(in_particles(processDescription))) + sum(values(out_particles(processDescription))) "Number of input Symbols is smaller than the number of particles in the process description"
assignInputs = Vector{Expr}()
for (name, symbols) in inputSymbols
(type, index) = type_index_from_name(model(processDescription), name)
p = nothing
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)]"
else
p = "filter(x -> typeof(x) <: $type, in_particles($(processInputSymbol)))[$(index)]"
end
for symbol in symbols
device = entry_device(machine)
evalExpr = eval(gen_access_expr(device, symbol))
push!(assignInputs, Meta.parse("$(evalExpr)::ParticleValue{$type} = ParticleValue($p, one(ComplexF64))"))
end
end
return Expr(:block, assignInputs...)
end
"""
get_compute_function(graph::DAG, process::AbstractProcessDescription, machine::Machine)
Return a function of signature `compute_<id>(input::AbstractProcessInput)`, which will return the result of the DAG computation on the given input.
"""
function get_compute_function(graph::DAG, process::AbstractProcessDescription, machine::Machine)
(code, inputSymbols, outputSymbol) = gen_code(graph, machine)
initCaches = gen_cache_init_code(machine)
assignInputs = gen_input_assignment_code(inputSymbols, process, machine, :input)
functionId = to_var_name(UUIDs.uuid1(rng[1]))
resSym = eval(gen_access_expr(entry_device(machine), outputSymbol))
expr = Meta.parse(
"function compute_$(functionId)(input::AbstractProcessInput) $initCaches; $assignInputs; $code; return $resSym; end",
)
func = eval(expr)
return func
end
"""
execute(graph::DAG, process::AbstractProcessDescription, machine::Machine, input::AbstractProcessInput)
Execute the code of the given `graph` on the given input particles.
This is essentially shorthand for
```julia
compute_graph = get_compute_function(graph, process)
result = compute_graph(particles)
```
See also: [`parse_dag`](@ref), [`parse_process`](@ref), [`gen_process_input`](@ref)
"""
function execute(graph::DAG, process::AbstractProcessDescription, machine::Machine, input::AbstractProcessInput)
(code, inputSymbols, outputSymbol) = gen_code(graph, machine)
initCaches = gen_cache_init_code(machine)
assignInputs = gen_input_assignment_code(inputSymbols, process, machine, :input)
functionId = to_var_name(UUIDs.uuid1(rng[1]))
resSym = eval(gen_access_expr(entry_device(machine), outputSymbol))
expr = Meta.parse(
"function compute_$(functionId)(input::AbstractProcessInput) $initCaches; $assignInputs; $code; return $resSym; end",
)
func = eval(expr)
result = 0
try
result = @eval $func($input)
catch e
println("Error while evaluating: $e")
# if we find a uuid in the exception we can color it in so it's easier to spot
uuidRegex = r"[0-9a-f]{8}_[0-9a-f]{4}_[0-9a-f]{4}_[0-9a-f]{4}_[0-9a-f]{12}"
m = match(uuidRegex, string(e))
functionStr = string(expr)
if (isa(m, RegexMatch))
functionStr = replace(functionStr, m.match => "\033[31m$(m.match)\033[0m")
end
println("Function:\n$functionStr")
@assert false
end
return result
end

53
src/devices/cuda/impl.jl Normal file
View File

@ -0,0 +1,53 @@
using CUDA
"""
CUDAGPU <: AbstractGPU
Representation of a specific CUDA GPU that code can run on. Implements the [`AbstractDevice`](@ref) interface.
"""
mutable struct CUDAGPU <: AbstractGPU
device::Any # TODO: what's the cuda device type?
cacheStrategy::CacheStrategy
FLOPS::Float64
end
push!(DEVICE_TYPES, CUDAGPU)
CACHE_STRATEGIES[CUDAGPU] = [LocalVariables()]
default_strategy(::Type{T}) where {T <: CUDAGPU} = LocalVariables()
function measure_device!(device::CUDAGPU; verbose::Bool)
if verbose
println("Measuring CUDA GPU $(device.device)")
end
# TODO implement
return nothing
end
"""
get_devices(deviceType::Type{T}; verbose::Bool) where {T <: CUDAGPU}
Return a Vector of [`CUDAGPU`](@ref)s available on the current machine. If `verbose` is true, print some additional information.
"""
function get_devices(deviceType::Type{T}; verbose::Bool = false) where {T <: CUDAGPU}
devices = Vector{AbstractDevice}()
if !CUDA.functional()
if verbose
println("CUDA is non-functional")
end
return devices
end
CUDADevices = CUDA.devices()
if verbose
println("Found $(length(CUDADevices)) CUDA devices")
end
for device in CUDADevices
push!(devices, CUDAGPU(device, default_strategy(CUDAGPU), -1))
end
return devices
end

23
src/devices/detect.jl Normal file
View File

@ -0,0 +1,23 @@
"""
get_machine_info(verbose::Bool)
Return the [`Machine`](@ref) currently running on. The parameter `verbose` defaults to true when interactive.
"""
function get_machine_info(; verbose::Bool = Base.is_interactive)
devices = Vector{AbstractDevice}()
for device in device_types()
devs = get_devices(device, verbose = verbose)
for dev in devs
push!(devices, dev)
end
end
noDevices = length(devices)
@assert noDevices > 0 "No devices were found, but at least one NUMA node should always be available!"
transferRates = Matrix{Float64}(undef, noDevices, noDevices)
fill!(transferRates, -1)
return Machine(devices, transferRates)
end

52
src/devices/impl.jl Normal file
View File

@ -0,0 +1,52 @@
"""
device_types()
Return a vector of available and implemented device types.
See also: [`DEVICE_TYPES`](@ref)
"""
function device_types()
return DEVICE_TYPES
end
"""
entry_device(machine::Machine)
Return the "entry" device, i.e., the device that starts CPU threads and GPU kernels, and takes input values and returns the output value.
"""
function entry_device(machine::Machine)
return machine.devices[1]
end
"""
strategies(t::Type{T}) where {T <: AbstractDevice}
Return a vector of available [`CacheStrategy`](@ref)s for the given [`AbstractDevice`](@ref).
The caching strategies are used in code generation.
"""
function strategies(t::Type{T}) where {T <: AbstractDevice}
if !haskey(CACHE_STRATEGIES, t)
error("Trying to get strategies for $T, but it has no strategies defined!")
end
return CACHE_STRATEGIES[t]
end
"""
cache_strategy(device::AbstractDevice)
Returns the cache strategy set for this device.
"""
function cache_strategy(device::AbstractDevice)
return device.cacheStrategy
end
"""
set_cache_strategy(device::AbstractDevice, cacheStrategy::CacheStrategy)
Sets the device's cache strategy. After this call, [`cache_strategy`](@ref) should return `cacheStrategy` on the given device.
"""
function set_cache_strategy(device::AbstractDevice, cacheStrategy::CacheStrategy)
device.cacheStrategy = cacheStrategy
return nothing
end

108
src/devices/interface.jl Normal file
View File

@ -0,0 +1,108 @@
"""
AbstractDevice
Abstract base type for every device, like GPUs, CPUs or any other compute devices.
Every implementation needs to implement various functions and needs a member `cacheStrategy`.
"""
abstract type AbstractDevice end
abstract type AbstractCPU <: AbstractDevice end
abstract type AbstractGPU <: AbstractDevice end
"""
Machine
A representation of a machine to execute on. Contains information about its architecture (CPUs, GPUs, maybe more). This representation can be used to make a more accurate cost prediction of a [`DAG`](@ref) state.
See also: [`Scheduler`](@ref)
"""
struct Machine
devices::Vector{AbstractDevice}
transferRates::Matrix{Float64}
end
"""
CacheStrategy
Abstract base type for caching strategies.
See also: [`strategies`](@ref)
"""
abstract type CacheStrategy end
"""
LocalVariables <: CacheStrategy
A caching strategy relying solely on local variables for every input and output.
Implements the [`CacheStrategy`](@ref) interface.
"""
struct LocalVariables <: CacheStrategy end
"""
Dictionary <: CacheStrategy
A caching strategy relying on a dictionary of Symbols to store every input and output.
Implements the [`CacheStrategy`](@ref) interface.
"""
struct Dictionary <: CacheStrategy end
"""
DEVICE_TYPES::Vector{Type}
Global vector of available and implemented device types. Each implementation of a [`AbstractDevice`](@ref) should add its concrete type to this vector.
See also: [`device_types`](@ref), [`get_devices`](@ref)
"""
DEVICE_TYPES = Vector{Type}()
"""
CACHE_STRATEGIES::Dict{Type{AbstractDevice}, Symbol}
Global dictionary of available caching strategies per device. Each implementation of [`AbstractDevice`](@ref) should add its available strategies to the dictionary.
See also: [`strategies`](@ref)
"""
CACHE_STRATEGIES = Dict{Type, Vector{CacheStrategy}}()
"""
default_strategy(deviceType::Type{T}) where {T <: AbstractDevice}
Interface function that must be implemented for every subtype of [`AbstractDevice`](@ref). Returns the default [`CacheStrategy`](@ref) to use on the given device type.
See also: [`cache_strategy`](@ref), [`set_cache_strategy`](@ref)
"""
function default_strategy end
"""
get_devices(t::Type{T}; verbose::Bool) where {T <: AbstractDevice}
Interface function that must be implemented for every subtype of [`AbstractDevice`](@ref). Returns a `Vector{Type}` of the devices for the given [`AbstractDevice`](@ref) Type available on the current machine.
"""
function get_devices end
"""
measure_device!(device::AbstractDevice; verbose::Bool)
Interface function that must be implemented for every subtype of [`AbstractDevice`](@ref). Measures the compute speed of the given device and writes into it.
"""
function measure_device! end
"""
gen_cache_init_code(device::AbstractDevice)
Interface function that must be implemented for every subtype of [`AbstractDevice`](@ref) and at least one [`CacheStrategy`](@ref). Returns an `Expr` initializing this device's variable cache.
The strategy is a symbol
"""
function gen_cache_init_code end
"""
gen_access_expr(device::AbstractDevice, symbol::Symbol)
Interface function that must be implemented for every subtype of [`AbstractDevice`](@ref) and at least one [`CacheStrategy`](@ref).
Return an `Expr` or `QuoteNode` accessing the variable identified by [`symbol`].
"""
function gen_access_expr end

22
src/devices/measure.jl Normal file
View File

@ -0,0 +1,22 @@
"""
measure_devices(machine::Machine; verbose::Bool)
Measure FLOPS, RAM, cache sizes and what other properties can be extracted for the devices in the given machine.
"""
function measure_devices!(machine::Machine; verbose::Bool = Base.is_interactive())
for device in machine.devices
measure_device!(device; verbose = verbose)
end
return nothing
end
"""
measure_transfer_rates(machine::Machine; verbose::Bool)
Measure the transfer rates between devices in the machine.
"""
function measure_transfer_rates!(machine::Machine; verbose::Bool = Base.is_interactive())
# TODO implement
return nothing
end

96
src/devices/numa/impl.jl Normal file
View File

@ -0,0 +1,96 @@
using NumaAllocators
"""
NumaNode <: AbstractCPU
Representation of a specific CPU that code can run on. Implements the [`AbstractDevice`](@ref) interface.
"""
mutable struct NumaNode <: AbstractCPU
numaId::UInt16
threads::UInt16
cacheStrategy::CacheStrategy
FLOPS::Float64
id::UUID
end
push!(DEVICE_TYPES, NumaNode)
CACHE_STRATEGIES[NumaNode] = [LocalVariables()]
default_strategy(::Type{T}) where {T <: NumaNode} = LocalVariables()
function measure_device!(device::NumaNode; verbose::Bool)
if verbose
println("Measuring Numa Node $(device.numaId)")
end
# TODO implement
return nothing
end
"""
get_devices(deviceType::Type{T}; verbose::Bool) where {T <: NumaNode}
Return a Vector of [`NumaNode`](@ref)s available on the current machine. If `verbose` is true, print some additional information.
"""
function get_devices(deviceType::Type{T}; verbose::Bool = false) where {T <: NumaNode}
devices = Vector{AbstractDevice}()
noNumaNodes = highest_numa_node()
if (verbose)
println("Found $(noNumaNodes + 1) NUMA nodes")
end
for i in 0:noNumaNodes
push!(devices, NumaNode(i, 1, default_strategy(NumaNode), -1, UUIDs.uuid1(rng[1])))
end
return devices
end
"""
gen_cache_init_code(device::NumaNode)
Generate code for initializing the [`LocalVariables`](@ref) strategy on a [`NumaNode`](@ref).
"""
function gen_cache_init_code(device::NumaNode)
if typeof(device.cacheStrategy) <: LocalVariables
# don't need to initialize anything
return Expr(:block)
elseif typeof(device.cacheStrategy) <: Dictionary
return Meta.parse("cache_$(to_var_name(device.id)) = Dict{Symbol, Any}()")
# TODO: sizehint?
end
return error("Unimplemented cache strategy \"$(device.cacheStrategy)\" for device \"$(device)\"")
end
"""
gen_access_expr(device::NumaNode, symbol::Symbol)
Generate code to access the variable designated by `symbol` on a [`NumaNode`](@ref), using the [`CacheStrategy`](@ref) set in the device.
"""
function gen_access_expr(device::NumaNode, symbol::Symbol)
return _gen_access_expr(device, device.cacheStrategy, symbol)
end
"""
_gen_access_expr(device::NumaNode, ::LocalVariables, symbol::Symbol)
Internal function for dispatch, used in [`gen_access_expr`](@ref).
"""
function _gen_access_expr(device::NumaNode, ::LocalVariables, symbol::Symbol)
s = Symbol("data_$symbol")
quoteNode = Meta.parse(":($s)")
return quoteNode
end
"""
_gen_access_expr(device::NumaNode, ::Dictionary, symbol::Symbol)
Internal function for dispatch, used in [`gen_access_expr`](@ref).
"""
function _gen_access_expr(device::NumaNode, ::Dictionary, symbol::Symbol)
accessStr = ":(cache_$(to_var_name(device.id))[:$symbol])"
quoteNode = Meta.parse(accessStr)
return quoteNode
end

View File

@ -0,0 +1,53 @@
using oneAPI
"""
oneAPIGPU <: AbstractGPU
Representation of a specific Intel GPU that code can run on. Implements the [`AbstractDevice`](@ref) interface.
"""
mutable struct oneAPIGPU <: AbstractGPU
device::Any
cacheStrategy::CacheStrategy
FLOPS::Float64
end
push!(DEVICE_TYPES, oneAPIGPU)
CACHE_STRATEGIES[oneAPIGPU] = [LocalVariables()]
default_strategy(::Type{T}) where {T <: oneAPIGPU} = LocalVariables()
function measure_device!(device::oneAPIGPU; verbose::Bool)
if verbose
println("Measuring oneAPI GPU $(device.device)")
end
# TODO implement
return nothing
end
"""
get_devices(deviceType::Type{T}; verbose::Bool = false) where {T <: oneAPIGPU}
Return a Vector of [`oneAPIGPU`](@ref)s available on the current machine. If `verbose` is true, print some additional information.
"""
function get_devices(deviceType::Type{T}; verbose::Bool = false) where {T <: oneAPIGPU}
devices = Vector{AbstractDevice}()
if !oneAPI.functional()
if verbose
println("oneAPI is non-functional")
end
return devices
end
oneAPIDevices = oneAPI.devices()
if verbose
println("Found $(length(oneAPIDevices)) oneAPI devices")
end
for device in oneAPIDevices
push!(devices, oneAPIGPU(device, default_strategy(oneAPIGPU), -1))
end
return devices
end

53
src/devices/rocm/impl.jl Normal file
View File

@ -0,0 +1,53 @@
using AMDGPU
"""
ROCmGPU <: AbstractGPU
Representation of a specific AMD GPU that code can run on. Implements the [`AbstractDevice`](@ref) interface.
"""
mutable struct ROCmGPU <: AbstractGPU
device::Any
cacheStrategy::CacheStrategy
FLOPS::Float64
end
push!(DEVICE_TYPES, ROCmGPU)
CACHE_STRATEGIES[ROCmGPU] = [LocalVariables()]
default_strategy(::Type{T}) where {T <: ROCmGPU} = LocalVariables()
function measure_device!(device::ROCmGPU; verbose::Bool)
if verbose
println("Measuring ROCm GPU $(device.device)")
end
# TODO implement
return nothing
end
"""
get_devices(deviceType::Type{T}; verbose::Bool = false) where {T <: ROCmGPU}
Return a Vector of [`ROCmGPU`](@ref)s available on the current machine. If `verbose` is true, print some additional information.
"""
function get_devices(deviceType::Type{T}; verbose::Bool = false) where {T <: ROCmGPU}
devices = Vector{AbstractDevice}()
if !AMDGPU.functional()
if verbose
println("AMDGPU is non-functional")
end
return devices
end
AMDDevices = AMDGPU.devices()
if verbose
println("Found $(length(AMDDevices)) AMD devices")
end
for device in AMDDevices
push!(devices, ROCmGPU(device, default_strategy(ROCmGPU), -1))
end
return devices
end

11
src/diff/print.jl Normal file
View File

@ -0,0 +1,11 @@
"""
show(io::IO, diff::Diff)
Pretty-print a [`Diff`](@ref). Called via print, println and co.
"""
function show(io::IO, diff::Diff)
print(io, "Nodes: ")
print(io, length(diff.addedNodes) + length(diff.removedNodes))
print(io, ", Edges: ")
return print(io, length(diff.addedEdges) + length(diff.removedEdges))
end

14
src/diff/properties.jl Normal file
View File

@ -0,0 +1,14 @@
"""
length(diff::Diff)
Return a named tuple of the lengths of the added/removed nodes/edges.
The fields are `.addedNodes`, `.addedEdges`, `.removedNodes` and `.removedEdges`.
"""
function length(diff::Diff)
return (
addedNodes = length(diff.addedNodes),
removedNodes = length(diff.removedNodes),
addedEdges = length(diff.addedEdges),
removedEdges = length(diff.removedEdges),
)
end

21
src/diff/type.jl Normal file
View File

@ -0,0 +1,21 @@
"""
Diff
A named tuple representing a difference of added and removed nodes and edges on a [`DAG`](@ref).
"""
const Diff = NamedTuple{
(:addedNodes, :removedNodes, :addedEdges, :removedEdges, :updatedChildren),
Tuple{Vector{Node}, Vector{Node}, Vector{Edge}, Vector{Edge}, Vector{Tuple{Node, AbstractTask}}},
}
function Diff()
return (
addedNodes = Vector{Node}(),
removedNodes = Vector{Node}(),
addedEdges = Vector{Edge}(),
removedEdges = Vector{Edge}(),
# children were updated in the task, updatedChildren[x][2] is the task before the update
updatedChildren = Vector{Tuple{Node, AbstractTask}}(),
)::Diff
end

View File

@ -0,0 +1,77 @@
"""
CDCost
Representation of a [`DAG`](@ref)'s cost as estimated by the [`GlobalMetricEstimator`](@ref).
# Fields:
`.data`: The total data transfer.\\
`.computeEffort`: The total compute effort.\\
`.computeIntensity`: The compute intensity, will always equal `.computeEffort / .data`.
!!! note
Note that the `computeIntensity` doesn't necessarily make sense in the context of only operation costs.
For example, for node fusions this will always be 0, since the computeEffort is zero.
It will still work as intended when adding/subtracting to/from a `graph_cost` estimate.
"""
const CDCost = NamedTuple{(:data, :computeEffort, :computeIntensity), Tuple{Float64, Float64, Float64}}
function +(cost1::CDCost, cost2::CDCost)::CDCost
d = cost1.data + cost2.data
ce = computeEffort = cost1.computeEffort + cost2.computeEffort
return (data = d, computeEffort = ce, computeIntensity = ce / d)::CDCost
end
function -(cost1::CDCost, cost2::CDCost)::CDCost
d = cost1.data - cost2.data
ce = computeEffort = cost1.computeEffort - cost2.computeEffort
return (data = d, computeEffort = ce, computeIntensity = ce / d)::CDCost
end
function isless(cost1::CDCost, cost2::CDCost)::Bool
return cost1.data + cost1.computeEffort < cost2.data + cost2.computeEffort
end
function zero(type::Type{CDCost})
return (data = 0.0, computeEffort = 00.0, computeIntensity = 0.0)::CDCost
end
function typemax(type::Type{CDCost})
return (data = Inf, computeEffort = Inf, computeIntensity = 0.0)::CDCost
end
struct GlobalMetricEstimator <: AbstractEstimator end
function cost_type(estimator::GlobalMetricEstimator)::Type{CDCost}
return CDCost
end
function graph_cost(estimator::GlobalMetricEstimator, graph::DAG)
properties = get_properties(graph)
return (
data = properties.data,
computeEffort = properties.computeEffort,
computeIntensity = properties.computeIntensity,
)::CDCost
end
function operation_effect(estimator::GlobalMetricEstimator, graph::DAG, operation::NodeFusion)
return (data = -data(operation.input[2].task), computeEffort = 0.0, computeIntensity = 0.0)::CDCost
end
function operation_effect(estimator::GlobalMetricEstimator, graph::DAG, operation::NodeReduction)
s = length(operation.input) - 1
return (
data = s * -data(task(operation.input[1])),
computeEffort = s * -compute_effort(task(operation.input[1])),
computeIntensity = typeof(operation.input) <: DataTaskNode ? 0.0 : Inf,
)::CDCost
end
function operation_effect(estimator::GlobalMetricEstimator, graph::DAG, operation::NodeSplit)
s::Float64 = length(parents(operation.input)) - 1
d::Float64 = s * data(task(operation.input))
ce::Float64 = s * compute_effort(task(operation.input))
return (data = d, computeEffort = ce, computeIntensity = ce / d)::CDCost
end

View File

@ -0,0 +1,44 @@
"""
AbstractEstimator
Abstract base type for an estimator. An estimator estimates the cost of a graph or the difference an operation applied to a graph will make to its cost.
Interface functions are
- [`graph_cost`](@ref)
- [`operation_effect`](@ref)
"""
abstract type AbstractEstimator end
"""
cost_type(estimator::AbstractEstimator)
Interface function returning a specific estimator's cost type, i.e., the type returned by its implementation of [`graph_cost`](@ref) and [`operation_effect`](@ref).
"""
function cost_type end
"""
graph_cost(estimator::AbstractEstimator, graph::DAG)
Get the total estimated cost of the graph. The cost's data type can be chosen by the implementation, but must have a usable lessthan comparison operator (<), basic math operators (+, -) and an implementation of `zero()` and `typemax()`.
"""
function graph_cost end
"""
operation_effect(estimator::AbstractEstimator, graph::DAG, operation::Operation)
Get the estimated effect on the cost of the graph, such that `graph_cost(estimator, graph) + operation_effect(estimator, graph, operation) ~= graph_cost(estimator, graph_with_operation_applied)`. There is no hard requirement for this, but the better the estimate, the better an optimization algorithm will be.
!!! note
There is a default implementation of this function, applying the operation, calling [`graph_cost`](@ref), then popping the operation again.
It can be much faster to overload this function for a specific estimator and directly compute the effects from the operation if possible.
"""
function operation_effect(estimator::AbstractEstimator, graph::DAG, operation::Operation)
# This is currently not stably working, see issue #16
cost = graph_cost(estimator, graph)
push_operation!(graph, operation)
cost_after = graph_cost(estimator, graph)
pop_operation!(graph)
return cost_after - cost
end

View File

@ -1,92 +0,0 @@
using DataStructures
const Diff = NamedTuple{
(:addedNodes, :removedNodes, :addedEdges, :removedEdges),
Tuple{Vector{Node}, Vector{Node}, Vector{Edge}, Vector{Edge}}
}
function Diff()
return (
addedNodes = Vector{Node}(),
removedNodes = Vector{Node}(),
addedEdges = Vector{Edge}(),
removedEdges = Vector{Edge}()
)::Diff
end
# An abstract base class for operations
# an operation can be applied to a DAG
abstract type Operation end
# An abstract base class for already applied operations
# an applied operation can be reversed iff it is the last applied operation on the DAG
abstract type AppliedOperation end
struct NodeFusion <: Operation
input::Tuple{ComputeTaskNode, DataTaskNode, ComputeTaskNode}
end
struct AppliedNodeFusion <: AppliedOperation
operation::NodeFusion
diff::Diff
end
struct NodeReduction <: Operation
input::Vector{Node}
end
struct AppliedNodeReduction <: AppliedOperation
operation::NodeReduction
diff::Diff
end
struct NodeSplit <: Operation
input::Node
end
struct AppliedNodeSplit <: AppliedOperation
operation::NodeSplit
diff::Diff
end
mutable struct PossibleOperations
nodeFusions::Set{NodeFusion}
nodeReductions::Set{NodeReduction}
nodeSplits::Set{NodeSplit}
end
function PossibleOperations()
return PossibleOperations(
Set{NodeFusion}(),
Set{NodeReduction}(),
Set{NodeSplit}()
)
end
# The actual state of the DAG is the initial state given by the set of nodes
# but with all the operations in appliedChain applied in order
mutable struct DAG
nodes::Set{Node}
# The operations currently applied to the set of nodes
appliedOperations::Stack{AppliedOperation}
# The operations not currently applied but part of the current state of the DAG
operationsToApply::Deque{Operation}
# The possible operations at the current state of the DAG
possibleOperations::PossibleOperations
# The set of nodes whose possible operations need to be reevaluated
dirtyNodes::Set{Node}
# "snapshot" system: keep track of added/removed nodes/edges since last snapshot
# these are muted in insert_node! etc.
diff::Diff
end
function DAG()
return DAG(Set{Node}(), Stack{AppliedOperation}(), Deque{Operation}(), PossibleOperations(), Set{Node}(), Diff())
end

21
src/graph/compare.jl Normal file
View File

@ -0,0 +1,21 @@
"""
in(node::Node, graph::DAG)
Check whether the node is part of the graph.
"""
in(node::Node, graph::DAG) = node in graph.nodes
"""
in(edge::Edge, graph::DAG)
Check whether the edge is part of the graph.
"""
function in(edge::Edge, graph::DAG)
n1 = edge.edge[1]
n2 = edge.edge[2]
if !(n1 in graph) || !(n2 in graph)
return false
end
return n1 in children(n2)
end

54
src/graph/interface.jl Normal file
View File

@ -0,0 +1,54 @@
"""
push_operation!(graph::DAG, operation::Operation)
Apply a new operation to the graph.
See also: [`DAG`](@ref), [`pop_operation!`](@ref)
"""
function push_operation!(graph::DAG, operation::Operation)
# 1.: Add the operation to the DAG
push!(graph.operationsToApply, operation)
return nothing
end
"""
pop_operation!(graph::DAG)
Revert the latest applied operation on the graph.
See also: [`DAG`](@ref), [`push_operation!`](@ref)
"""
function pop_operation!(graph::DAG)
# 1.: Remove the operation from the appliedChain of the DAG
if !isempty(graph.operationsToApply)
pop!(graph.operationsToApply)
elseif !isempty(graph.appliedOperations)
appliedOp = pop!(graph.appliedOperations)
revert_operation!(graph, appliedOp)
else
error("No more operations to pop!")
end
return nothing
end
"""
can_pop(graph::DAG)
Return `true` if [`pop_operation!`](@ref) is possible, `false` otherwise.
"""
can_pop(graph::DAG) = !isempty(graph.operationsToApply) || !isempty(graph.appliedOperations)
"""
reset_graph!(graph::DAG)
Reset the graph to its initial state with no operations applied.
"""
function reset_graph!(graph::DAG)
while (can_pop(graph))
pop_operation!(graph)
end
return nothing
end

336
src/graph/mute.jl Normal file
View File

@ -0,0 +1,336 @@
# for graph mutating functions we need to do a few things
# 1: mute the graph (duh)
# 2: keep track of what was changed for the diff (if track == true)
# 3: invalidate operation caches
"""
insert_node!(graph::DAG, node::Node; track = true, invalidate_cache = true)
Insert the node into the graph.
## Keyword Arguments
`track::Bool`: Whether to add the changes to the [`DAG`](@ref)'s [`Diff`](@ref). Should be set `false` in parsing or graph creation functions for performance.
`invalidate_cache::Bool`: Whether to invalidate caches associated with the changes. Should also be turned off for graph creation or parsing.
See also: [`remove_node!`](@ref), [`insert_edge!`](@ref), [`remove_edge!`](@ref)
"""
function insert_node!(graph::DAG, node::Node; track = true, invalidate_cache = true)
# 1: mute
push!(graph.nodes, node)
# 2: keep track
if (track)
push!(graph.diff.addedNodes, node)
end
# 3: invalidate caches
if (!invalidate_cache)
return node
end
push!(graph.dirtyNodes, node)
return node
end
"""
insert_edge!(graph::DAG, node1::Node, node2::Node; track = true, invalidate_cache = true)
Insert the edge between node1 (child) and node2 (parent) into the graph.
## Keyword Arguments
`track::Bool`: Whether to add the changes to the [`DAG`](@ref)'s [`Diff`](@ref). Should be set `false` in parsing or graph creation functions for performance.
`invalidate_cache::Bool`: Whether to invalidate caches associated with the changes. Should also be turned off for graph creation or parsing.
See also: [`insert_node!`](@ref), [`remove_node!`](@ref), [`remove_edge!`](@ref)
"""
function insert_edge!(graph::DAG, node1::Node, node2::Node; track = true, invalidate_cache = true)
#@assert (node2 ∉ parents(node1)) && (node1 ∉ children(node2)) "Edge to insert already exists"
# 1: mute
# edge points from child to parent
push!(node1.parents, node2)
push!(node2.children, node1)
# 2: keep track
if (track)
push!(graph.diff.addedEdges, make_edge(node1, node2))
end
# 3: invalidate caches
if (!invalidate_cache)
return nothing
end
invalidate_operation_caches!(graph, node1)
invalidate_operation_caches!(graph, node2)
push!(graph.dirtyNodes, node1)
push!(graph.dirtyNodes, node2)
return nothing
end
"""
remove_node!(graph::DAG, node::Node; track = true, invalidate_cache = true)
Remove the node from the graph.
## Keyword Arguments
`track::Bool`: Whether to add the changes to the [`DAG`](@ref)'s [`Diff`](@ref). Should be set `false` in parsing or graph creation functions for performance.
`invalidate_cache::Bool`: Whether to invalidate caches associated with the changes. Should also be turned off for graph creation or parsing.
See also: [`insert_node!`](@ref), [`insert_edge!`](@ref), [`remove_edge!`](@ref)
"""
function remove_node!(graph::DAG, node::Node; track = true, invalidate_cache = true)
#@assert node in graph.nodes "Trying to remove a node that's not in the graph"
# 1: mute
delete!(graph.nodes, node)
# 2: keep track
if (track)
push!(graph.diff.removedNodes, node)
end
# 3: invalidate caches
if (!invalidate_cache)
return nothing
end
invalidate_operation_caches!(graph, node)
delete!(graph.dirtyNodes, node)
return nothing
end
"""
remove_edge!(graph::DAG, node1::Node, node2::Node; track = true, invalidate_cache = true)
Remove the edge between node1 (child) and node2 (parent) into the graph.
## Keyword Arguments
`track::Bool`: Whether to add the changes to the [`DAG`](@ref)'s [`Diff`](@ref). Should be set `false` in parsing or graph creation functions for performance.
`invalidate_cache::Bool`: Whether to invalidate caches associated with the changes. Should also be turned off for graph creation or parsing.
See also: [`insert_node!`](@ref), [`remove_node!`](@ref), [`insert_edge!`](@ref)
"""
function remove_edge!(graph::DAG, node1::Node, node2::Node; track = true, invalidate_cache = true)
# 1: mute
pre_length1 = length(node1.parents)
pre_length2 = length(node2.children)
for i in eachindex(node1.parents)
if (node1.parents[i] == node2)
splice!(node1.parents, i)
break
end
end
for i in eachindex(node2.children)
if (node2.children[i] == node1)
splice!(node2.children, i)
break
end
end
#=@assert begin
removed = pre_length1 - length(node1.parents)
removed <= 1
end "removed more than one node from node1's parents"=#
#=@assert begin
removed = pre_length2 - length(children(node2))
removed <= 1
end "removed more than one node from node2's children"=#
# 2: keep track
if (track)
push!(graph.diff.removedEdges, make_edge(node1, node2))
end
# 3: invalidate caches
if (!invalidate_cache)
return nothing
end
invalidate_operation_caches!(graph, node1)
invalidate_operation_caches!(graph, node2)
if (node1 in graph)
push!(graph.dirtyNodes, node1)
end
if (node2 in graph)
push!(graph.dirtyNodes, node2)
end
return nothing
end
function replace_children!(task::FusedComputeTask, before, after)
replacedIn1 = length(findall(x -> x == before, task.t1_inputs))
replacedIn2 = length(findall(x -> x == before, task.t2_inputs))
#@assert replacedIn1 >= 1 || replacedIn2 >= 1 "Nothing to replace while replacing $before with $after in $(task.t1_inputs...) and $(task.t2_inputs...)"
replace!(task.t1_inputs, before => after)
replace!(task.t2_inputs, before => after)
# recursively descend down the tree, but only in the tasks where we're replacing things
if replacedIn1 > 0
replace_children!(task.first_task, before, after)
end
if replacedIn2 > 0
replace_children!(task.second_task, before, after)
end
return nothing
end
function replace_children!(task::AbstractTask, before, after)
return nothing
end
function update_child!(graph::DAG, n::Node, child_before::Symbol, child_after::Symbol; track = true)
# only need to update fused compute tasks
if !(typeof(task(n)) <: FusedComputeTask)
return nothing
end
taskBefore = copy(task(n))
#=if !((child_before in task(n).t1_inputs) || (child_before in task(n).t2_inputs))
println("------------------ Nothing to replace!! ------------------")
child_ids = Vector{String}()
for child in children(n)
push!(child_ids, "$(child.id)")
end
println("From $(child_before) to $(child_after) in $n with children $(child_ids)")
@assert false
end=#
replace_children!(task(n), child_before, child_after)
#=if !((child_after in task(n).t1_inputs) || (child_after in task(n).t2_inputs))
println("------------------ Did not replace anything!! ------------------")
child_ids = Vector{String}()
for child in children(n)
push!(child_ids, "$(child.id)")
end
println("From $(child_before) to $(child_after) in $n with children $(child_ids)")
@assert false
end=#
# keep track
if (track)
push!(graph.diff.updatedChildren, (n, taskBefore))
end
end
"""
get_snapshot_diff(graph::DAG)
Return the graph's [`Diff`](@ref) since last time this function was called.
See also: [`revert_diff!`](@ref), [`AppliedOperation`](@ref) and [`revert_operation!`](@ref)
"""
function get_snapshot_diff(graph::DAG)
return swapfield!(graph, :diff, Diff())
end
"""
invalidate_caches!(graph::DAG, operation::NodeFusion)
Invalidate the operation caches for a given [`NodeFusion`](@ref).
This deletes the operation from the graph's possible operations and from the involved nodes' own operation caches.
"""
function invalidate_caches!(graph::DAG, operation::NodeFusion)
delete!(graph.possibleOperations, operation)
# delete the operation from all caches of nodes involved in the operation
for n in [1, 3]
for i in eachindex(operation.input[n].nodeFusions)
if operation == operation.input[n].nodeFusions[i]
splice!(operation.input[n].nodeFusions, i)
break
end
end
end
operation.input[2].nodeFusion = missing
return nothing
end
"""
invalidate_caches!(graph::DAG, operation::NodeReduction)
Invalidate the operation caches for a given [`NodeReduction`](@ref).
This deletes the operation from the graph's possible operations and from the involved nodes' own operation caches.
"""
function invalidate_caches!(graph::DAG, operation::NodeReduction)
delete!(graph.possibleOperations, operation)
for node in operation.input
node.nodeReduction = missing
end
return nothing
end
"""
invalidate_caches!(graph::DAG, operation::NodeSplit)
Invalidate the operation caches for a given [`NodeSplit`](@ref).
This deletes the operation from the graph's possible operations and from the involved nodes' own operation caches.
"""
function invalidate_caches!(graph::DAG, operation::NodeSplit)
delete!(graph.possibleOperations, operation)
# delete the operation from all caches of nodes involved in the operation
# for node split there is only one node
operation.input.nodeSplit = missing
return nothing
end
"""
invalidate_operation_caches!(graph::DAG, node::ComputeTaskNode)
Invalidate the operation caches of the given node through calls to the respective [`invalidate_caches!`](@ref) functions.
"""
function invalidate_operation_caches!(graph::DAG, node::ComputeTaskNode)
if !ismissing(node.nodeReduction)
invalidate_caches!(graph, node.nodeReduction)
end
if !ismissing(node.nodeSplit)
invalidate_caches!(graph, node.nodeSplit)
end
while !isempty(node.nodeFusions)
invalidate_caches!(graph, pop!(node.nodeFusions))
end
return nothing
end
"""
invalidate_operation_caches!(graph::DAG, node::DataTaskNode)
Invalidate the operation caches of the given node through calls to the respective [`invalidate_caches!`](@ref) functions.
"""
function invalidate_operation_caches!(graph::DAG, node::DataTaskNode)
if !ismissing(node.nodeReduction)
invalidate_caches!(graph, node.nodeReduction)
end
if !ismissing(node.nodeSplit)
invalidate_caches!(graph, node.nodeSplit)
end
if !ismissing(node.nodeFusion)
invalidate_caches!(graph, node.nodeFusion)
end
return nothing
end

66
src/graph/print.jl Normal file
View File

@ -0,0 +1,66 @@
"""
show_nodes(io::IO, graph::DAG)
Print a graph's nodes. Should only be used for small graphs as it prints every node in a list.
"""
function show_nodes(io::IO, graph::DAG)
print(io, "[")
first = true
for n in graph.nodes
if first
first = false
else
print(io, ", ")
end
print(io, n)
end
return print(io, "]")
end
"""
show(io::IO, graph::DAG)
Print the given graph to io. If there are too many nodes it will print only a summary of them.
"""
function show(io::IO, graph::DAG)
apply_all!(graph)
println(io, "Graph:")
print(io, " Nodes: ")
nodeDict = Dict{Type, Int64}()
noEdges = 0
for node in graph.nodes
if haskey(nodeDict, typeof(task(node)))
nodeDict[typeof(task(node))] = nodeDict[typeof(task(node))] + 1
else
nodeDict[typeof(task(node))] = 1
end
noEdges += length(parents(node))
end
if length(graph.nodes) <= 20
show_nodes(io, graph)
else
print(io, "Total: ", length(graph.nodes), ", ")
first = true
i = 0
for (type, number) in zip(keys(nodeDict), values(nodeDict))
i += 1
if first
first = false
else
print(io, ", ")
end
if (i % 3 == 0)
print(io, "\n ")
end
print(io, type, ": ", number)
end
end
println(io)
println(io, " Edges: ", noEdges)
properties = get_properties(graph)
println(io, " Total Compute Effort: ", properties.computeEffort)
println(io, " Total Data Transfer: ", properties.data)
return println(io, " Total Compute Intensity: ", properties.computeIntensity)
end

54
src/graph/properties.jl Normal file
View File

@ -0,0 +1,54 @@
"""
get_properties(graph::DAG)
Return the graph's [`GraphProperties`](@ref).
"""
function get_properties(graph::DAG)
# make sure the graph is fully generated
apply_all!(graph)
if (graph.properties.computeEffort == 0.0)
graph.properties = GraphProperties(graph)
end
return graph.properties
end
"""
get_exit_node(graph::DAG)
Return the graph's exit node. This assumes the graph only has a single exit node. If the graph has multiple exit nodes, the one encountered first will be returned.
"""
function get_exit_node(graph::DAG)
for node in graph.nodes
if (is_exit_node(node))
return node
end
end
@assert false "The given graph has no exit node! It is either empty or not acyclic!"
end
"""
get_entry_nodes(graph::DAG)
Return a vector of the graph's entry nodes.
"""
function get_entry_nodes(graph::DAG)
apply_all!(graph)
result = Vector{Node}()
for node in graph.nodes
if (is_entry_node(node))
push!(result, node)
end
end
return result
end
"""
operation_stack_length(graph::DAG)
Return the number of operations applied to the graph.
"""
function operation_stack_length(graph::DAG)
return length(graph.appliedOperations) + length(graph.operationsToApply)
end

73
src/graph/type.jl Normal file
View File

@ -0,0 +1,73 @@
using DataStructures
"""
PossibleOperations
A struct storing all possible operations on a [`DAG`](@ref).
To get the [`PossibleOperations`](@ref) on a [`DAG`](@ref), use [`get_operations`](@ref).
"""
mutable struct PossibleOperations
nodeFusions::Set{NodeFusion}
nodeReductions::Set{NodeReduction}
nodeSplits::Set{NodeSplit}
end
"""
DAG
The representation of the graph as a set of [`Node`](@ref)s.
A DAG can be loaded using the appropriate parse_dag function, e.g. [`parse_dag`](@ref).
[`Operation`](@ref)s can be applied on it using [`push_operation!`](@ref) and reverted using [`pop_operation!`](@ref) like a stack.
To get the set of possible operations, use [`get_operations`](@ref).
The members of the object should not be manually accessed, instead always use the provided interface functions.
"""
mutable struct DAG
nodes::Set{Union{DataTaskNode, ComputeTaskNode}}
# The operations currently applied to the set of nodes
appliedOperations::Stack{AppliedOperation}
# The operations not currently applied but part of the current state of the DAG
operationsToApply::Deque{Operation}
# The possible operations at the current state of the DAG
possibleOperations::PossibleOperations
# The set of nodes whose possible operations need to be reevaluated
dirtyNodes::Set{Union{DataTaskNode, ComputeTaskNode}}
# "snapshot" system: keep track of added/removed nodes/edges since last snapshot
# these are muted in insert_node! etc.
diff::Diff
# the cached properties of the DAG
properties::GraphProperties
end
"""
PossibleOperations()
Construct and return an empty [`PossibleOperations`](@ref) object.
"""
function PossibleOperations()
return PossibleOperations(Set{NodeFusion}(), Set{NodeReduction}(), Set{NodeSplit}())
end
"""
DAG()
Construct and return an empty [`DAG`](@ref).
"""
function DAG()
return DAG(
Set{Node}(),
Stack{AppliedOperation}(),
Deque{Operation}(),
PossibleOperations(),
Set{Node}(),
Diff(),
GraphProperties(),
)
end

77
src/graph/validate.jl Normal file
View File

@ -0,0 +1,77 @@
"""
is_connected(graph::DAG)
Return whether the given graph is connected.
"""
function is_connected(graph::DAG)
nodeQueue = Deque{Node}()
push!(nodeQueue, get_exit_node(graph))
seenNodes = Set{Node}()
while !isempty(nodeQueue)
current = pop!(nodeQueue)
push!(seenNodes, current)
for child in current.children
push!(nodeQueue, child)
end
end
return length(seenNodes) == length(graph.nodes)
end
"""
is_valid(graph::DAG)
Validate the entire graph using asserts. Intended for testing with `@assert is_valid(graph)`.
"""
function is_valid(graph::DAG)
for node in graph.nodes
@assert is_valid(graph, node)
end
for op in graph.operationsToApply
@assert is_valid(graph, op)
end
for nr in graph.possibleOperations.nodeReductions
@assert is_valid(graph, nr)
end
for ns in graph.possibleOperations.nodeSplits
@assert is_valid(graph, ns)
end
for nf in graph.possibleOperations.nodeFusions
@assert is_valid(graph, nf)
end
for node in graph.dirtyNodes
@assert node in graph "Dirty Node is not part of the graph!"
@assert ismissing(node.nodeReduction) "Dirty Node has a NodeReduction!"
@assert ismissing(node.nodeSplit) "Dirty Node has a NodeSplit!"
if (typeof(node) <: DataTaskNode)
@assert ismissing(node.nodeFusion) "Dirty DataTaskNode has a Node Fusion!"
elseif (typeof(node) <: ComputeTaskNode)
@assert isempty(node.nodeFusions) "Dirty ComputeTaskNode has Node Fusions!"
end
end
@assert is_connected(graph) "Graph is not connected!"
return true
end
"""
is_scheduled(graph::DAG)
Validate that the entire graph has been scheduled, i.e., every [`ComputeTaskNode`](@ref) has its `.device` set.
"""
function is_scheduled(graph::DAG)
for node in graph.nodes
if (node isa DataTaskNode)
continue
end
@assert !ismissing(node.device)
end
return true
end

View File

@ -1,374 +0,0 @@
using DataStructures
in(node::Node, graph::DAG) = node in graph.nodes
in(edge::Edge, graph::DAG) = edge in graph.edges
function isempty(operations::PossibleOperations)
return isempty(operations.nodeFusions) &&
isempty(operations.nodeReductions) &&
isempty(operations.nodeSplits)
end
function length(operations::PossibleOperations)
return (nodeFusions = length(operations.nodeFusions),
nodeReductions = length(operations.nodeReductions),
nodeSplits = length(operations.nodeSplits))
end
function delete!(operations::PossibleOperations, op::NodeFusion)
delete!(operations.nodeFusions, op)
return operations
end
function delete!(operations::PossibleOperations, op::NodeReduction)
delete!(operations.nodeReductions, op)
return operations
end
function delete!(operations::PossibleOperations, op::NodeSplit)
delete!(operations.nodeSplits, op)
return operations
end
function is_parent(potential_parent, node)
return potential_parent in node.parents
end
function is_child(potential_child, node)
return potential_child in node.children
end
function ==(n1::Node, n2::Node, g::DAG)
if typeof(n1) != typeof(n2)
return false
end
if !(n1 in g) || !(n2 in g)
return false
end
return n1.task == n2.task && children(n1) == children(n2)
end
# children = prerequisite nodes, nodes that need to execute before the task, edges point into this task
function children(node::Node)
return copy(node.children)
end
# parents = subsequent nodes, nodes that need this node to execute, edges point from this task
function parents(node::Node)
return copy(node.parents)
end
# siblings = all children of any parents, no duplicates, does not include the node itself
function siblings(node::Node)
result = Set{Node}()
for parent in node.parents
for sibling in parent.children
if (sibling != node)
push!(result, sibling)
end
end
end
return result
end
# partners = all parents of any children, no duplicates, does not include the node itself
function partners(node::Node)
result = Set{Node}()
for child in node.children
for partner in child.parents
if (partner != node)
push!(result, partner)
end
end
end
return result
end
is_entry_node(node::Node) = length(node.children) == 0
is_exit_node(node::Node) = length(node.parents) == 0
# function to invalidate the operation caches for a given operation
function invalidate_caches!(graph::DAG, operation::Operation)
delete!(graph.possibleOperations, operation)
# delete the operation from all caches of nodes involved in the operation
# (we can iterate over tuples and vectors just fine)
for node in operation.input
filter!(!=(operation), node.operations)
end
return nothing
end
# function to invalidate the operation caches for a given Node Split specifically
function invalidate_caches!(graph::DAG, operation::NodeSplit)
delete!(graph.possibleOperations, operation)
# delete the operation from all caches of nodes involved in the operation
# for node split there is only one node
filter!(x -> x != operation, operation.input.operations)
return nothing
end
# for graph mutating functions we need to do a few things
# 1: mute the graph (duh)
# 2: keep track of what was changed for the diff (if track == true)
# 3: invalidate operation caches
function insert_node!(graph::DAG, node::Node, track=true)
# 1: mute
push!(graph.nodes, node)
# 2: keep track
if (track) push!(graph.diff.addedNodes, node) end
# 3: invalidate caches
push!(graph.dirtyNodes, node)
return node
end
function insert_edge!(graph::DAG, edge::Edge, track=true)
node1 = edge.edge[1]
node2 = edge.edge[2]
# 1: mute
#=if (node2 in node1.parents) || (node1 in node2.children)
if !(node2 in node1.parents && node1 in node2.children)
error("One-sided edge")
end
error("Edge to insert already exists")
end=#
# edge points from child to parent
push!(node1.parents, node2)
push!(node2.children, node1)
# 2: keep track
if (track) push!(graph.diff.addedEdges, edge) end
# 3: invalidate caches
while !isempty(node1.operations)
invalidate_caches!(graph, first(node1.operations))
end
while !isempty(node2.operations)
invalidate_caches!(graph, first(node2.operations))
end
push!(graph.dirtyNodes, node1)
push!(graph.dirtyNodes, node2)
return edge
end
function remove_node!(graph::DAG, node::Node, track=true)
# 1: mute
#=if !(node in graph.nodes)
error("Trying to remove a node that's not in the graph")
end=#
delete!(graph.nodes, node)
# 2: keep track
if (track) push!(graph.diff.removedNodes, node) end
# 3: invalidate caches
while !isempty(node.operations)
invalidate_caches!(graph, first(node.operations))
end
delete!(graph.dirtyNodes, node)
return nothing
end
function remove_edge!(graph::DAG, edge::Edge, track=true)
node1 = edge.edge[1]
node2 = edge.edge[2]
# 1: mute
pre_length1 = length(node1.parents)
pre_length2 = length(node2.children)
filter!(x -> x != node2, node1.parents)
filter!(x -> x != node1, node2.children)
#=removed = pre_length1 - length(node1.parents)
if (removed > 1)
error("removed $removed from node1's parents")
end
removed = pre_length2 - length(node2.children)
if (removed > 1)
error("removed $removed from node2's children")
end=#
# 2: keep track
if (track) push!(graph.diff.removedEdges, edge) end
# 3: invalidate caches
while !isempty(node1.operations)
invalidate_caches!(graph, first(node1.operations))
end
while !isempty(node2.operations)
invalidate_caches!(graph, first(node2.operations))
end
if (node1 in graph)
push!(graph.dirtyNodes, node1)
end
if (node2 in graph)
push!(graph.dirtyNodes, node2)
end
return nothing
end
# return the graph "difference" since last time this function was called
function get_snapshot_diff(graph::DAG)
return swapfield!(graph, :diff, Diff())
end
function graph_properties(graph::DAG)
# make sure the graph is fully generated
apply_all!(graph)
d = 0
ce = 0
ed = 0
for node in graph.nodes
d += data(node.task) * length(node.parents)
ce += compute_effort(node.task)
ed += length(node.parents)
end
ci = ce / d
result = (data = d,
compute_effort = ce,
compute_intensity = ci,
nodes = length(graph.nodes),
edges = ed)
return result
end
function get_exit_node(graph::DAG)
for node in graph.nodes
if (is_exit_node(node))
return node
end
end
error("The given graph has no exit node! It is either empty or not acyclic!")
end
function can_fuse(n1::ComputeTaskNode, n2::DataTaskNode, n3::ComputeTaskNode)
if !is_child(n1, n2) || !is_child(n2, n3)
# the checks are redundant but maybe a good sanity check
return false
end
if length(n2.parents) != 1 || length(n2.children) != 1 || length(n1.parents) != 1
return false
end
return true
end
function can_reduce(n1::Node, n2::Node)
if (n1.task != n2.task)
return false
end
return Set(n1.children) == Set(n2.children)
end
function can_split(n::Node)
return length(parents(n)) > 1
end
# check whether the given graph is connected
function is_valid(graph::DAG)
nodeQueue = Deque{Node}()
push!(nodeQueue, get_exit_node(graph))
seenNodes = Set{Node}()
while !isempty(nodeQueue)
current = pop!(nodeQueue)
push!(seenNodes, current)
for child in current.chlidren
push!(nodeQueue, child)
end
end
return length(seenNodes) == length(graph.nodes)
end
function show_nodes(io, graph::DAG)
print(io, "[")
first = true
for n in graph.nodes
if first
first = false
else
print(io, ", ")
end
print(io, n)
end
print(io, "]")
end
function show(io::IO, graph::DAG)
println(io, "Graph:")
print(io, " Nodes: ")
nodeDict = Dict{Type, Int64}()
noEdges = 0
for node in graph.nodes
if haskey(nodeDict, typeof(node.task))
nodeDict[typeof(node.task)] = nodeDict[typeof(node.task)] + 1
else
nodeDict[typeof(node.task)] = 1
end
noEdges += length(parents(node))
end
if length(graph.nodes) <= 20
show_nodes(io, graph)
else
print("Total: ", length(graph.nodes), ", ")
first = true
i = 0
for (type, number) in zip(keys(nodeDict), values(nodeDict))
i += 1
if first
first = false
else
print(", ")
end
if (i % 3 == 0)
print("\n ")
end
print(type, ": ", number)
end
end
println(io)
println(io, " Edges: ", noEdges)
properties = graph_properties(graph)
println(io, " Total Compute Effort: ", properties.compute_effort)
println(io, " Total Data Transfer: ", properties.data)
println(io, " Total Compute Intensity: ", properties.compute_intensity)
end
function show(io::IO, diff::Diff)
print(io, "Nodes: ")
print(io, length(diff.addedNodes) + length(diff.removedNodes))
print(io, " Edges: ")
print(io, length(diff.addedEdges) + length(diff.removedEdges))
end
# return a namedtuple of the lengths of the added/removed nodes/edges
function length(diff::Diff)
return (
addedNodes = length(diff.addedNodes),
removedNodes = length(diff.removedNodes),
addedEdges = length(diff.addedEdges),
removedEdges = length(diff.removedEdges)
)
end

View File

@ -1,485 +0,0 @@
# outside interface
# applies a new operation to the end of the graph
function push_operation!(graph::DAG, operation::Operation)
# 1.: Add the operation to the DAG
push!(graph.operationsToApply, operation)
return nothing
end
# reverts the latest applied operation, essentially like a ctrl+z for
function pop_operation!(graph::DAG)
# 1.: Remove the operation from the appliedChain of the DAG
if !isempty(graph.operationsToApply)
pop!(graph.operationsToApply)
elseif !isempty(graph.appliedOperations)
appliedOp = pop!(graph.appliedOperations)
revert_operation!(graph, appliedOp)
else
error("No more operations to pop!")
end
return nothing
end
can_pop(graph::DAG) = !isempty(graph.operationsToApply) || !isempty(graph.appliedOperations)
# reset the graph to its initial state with no operations applied
function reset_graph!(graph::DAG)
while (can_pop(graph))
pop_operation!(graph)
end
return nothing
end
# implementation detail functions, don't export
# applies all unapplied operations in the DAG
function apply_all!(graph::DAG)
while !isempty(graph.operationsToApply)
# get next operation to apply from front of the deque
op = popfirst!(graph.operationsToApply)
# apply it
appliedOp = apply_operation!(graph, op)
# push to the end of the appliedOperations deque
push!(graph.appliedOperations, appliedOp)
end
return nothing
end
function apply_operation!(graph::DAG, operation::Operation)
error("Unknown operation type!")
end
function apply_operation!(graph::DAG, operation::NodeFusion)
diff = node_fusion!(graph, operation.input[1], operation.input[2], operation.input[3])
return AppliedNodeFusion(operation, diff)
end
function apply_operation!(graph::DAG, operation::NodeReduction)
diff = node_reduction!(graph, operation.input[1], operation.input[2])
return AppliedNodeReduction(operation, diff)
end
function apply_operation!(graph::DAG, operation::NodeSplit)
diff = node_split!(graph, operation.input)
return AppliedNodeSplit(operation, diff)
end
function revert_operation!(graph::DAG, operation::AppliedOperation)
error("Unknown operation type!")
end
function revert_operation!(graph::DAG, operation::AppliedNodeFusion)
revert_diff!(graph, operation.diff)
return operation.operation
end
function revert_operation!(graph::DAG, operation::AppliedNodeReduction)
revert_diff!(graph, operation.diff)
return operation.operation
end
function revert_operation!(graph::DAG, operation::AppliedNodeSplit)
revert_diff!(graph, operation.diff)
return operation.operation
end
function revert_diff!(graph::DAG, diff)
# add removed nodes, remove added nodes, same for edges
# note the order
for edge in diff.addedEdges
remove_edge!(graph, edge, false)
end
for node in diff.addedNodes
remove_node!(graph, node, false)
end
for node in diff.removedNodes
insert_node!(graph, node, false)
end
for edge in diff.removedEdges
insert_edge!(graph, edge, false)
end
end
# Fuse nodes n1 -> n2 -> n3 together into one node, return the applied difference to the graph
function node_fusion!(graph::DAG, n1::ComputeTaskNode, n2::DataTaskNode, n3::ComputeTaskNode)
# clear snapshot
get_snapshot_diff(graph)
if !(n1 in graph) || !(n2 in graph) || !(n3 in graph)
error("[Node Fusion] The given nodes are not part of the given graph")
end
if !is_child(n1, n2) || !is_child(n2, n3) || !is_parent(n3, n2) || !is_parent(n2, n1)
# the checks are redundant but maybe a good sanity check
error("[Node Fusion] The given nodes are not connected by edges which is required for node fusion")
end
# save children and parents
n1_children = children(n1)
n3_parents = parents(n3)
n3_children = children(n3)
if length(n2.parents) > 1
error("[Node Fusion] The given data node has more than one parent")
end
if length(n2.children) > 1
error("[Node Fusion] The given data node has more than one child")
end
if length(n1.parents) > 1
error("[Node Fusion] The given n1 has more than one parent")
end
required_edge1 = make_edge(n1, n2)
required_edge2 = make_edge(n2, n3)
# remove the edges and nodes that will be replaced by the fused node
remove_edge!(graph, required_edge1)
remove_edge!(graph, required_edge2)
remove_node!(graph, n1)
remove_node!(graph, n2)
# get n3's children now so it automatically excludes n2
n3_children = children(n3)
remove_node!(graph, n3)
# create new node with the fused compute task
new_node = ComputeTaskNode(FusedComputeTask{typeof(n1.task), typeof(n3.task)}())
insert_node!(graph, new_node)
# use a set for combined children of n1 and n3 to not get duplicates
n1and3_children = Set{Node}()
# remove edges from n1 children to n1
for child in n1_children
remove_edge!(graph, make_edge(child, n1))
push!(n1and3_children, child)
end
# remove edges from n3 children to n3
for child in n3_children
remove_edge!(graph, make_edge(child, n3))
push!(n1and3_children, child)
end
for child in n1and3_children
insert_edge!(graph, make_edge(child, new_node))
end
# "repoint" parents of n3 from new node
for parent in n3_parents
remove_edge!(graph, make_edge(n3, parent))
insert_edge!(graph, make_edge(new_node, parent))
end
return get_snapshot_diff(graph)
end
function node_reduction!(graph::DAG, n1::Node, n2::Node)
# clear snapshot
get_snapshot_diff(graph)
#=if !(n1 in graph) || !(n2 in graph)
error("[Node Reduction] The given nodes are not part of the given graph")
end=#
#=if typeof(n1) != typeof(n2)
error("[Node Reduction] The given nodes are not of the same type")
end=#
# save n2 parents and children
n2_children = children(n2)
n2_parents = Set(n2.parents)
#=if Set(n2_children) != Set(n1.children)
error("[Node Reduction] The given nodes do not have equal prerequisite nodes which is required for node reduction")
end=#
# remove n2 and all its parents and children
for child in n2_children
remove_edge!(graph, make_edge(child, n2))
end
for parent in n2_parents
remove_edge!(graph, make_edge(n2, parent))
end
for parent in n1.parents
# delete parents in n1 that already exist in n2
delete!(n2_parents, parent)
end
for parent in n2_parents
# now add parents of n2 to n1 without duplicates
insert_edge!(graph, make_edge(n1, parent))
end
remove_node!(graph, n2)
return get_snapshot_diff(graph)
end
function node_split!(graph::DAG, n1::Node)
# clear snapshot
get_snapshot_diff(graph)
#=if !(n1 in graph)
error("[Node Split] The given node is not part of the given graph")
end=#
n1_parents = parents(n1)
n1_children = children(n1)
#=if length(n1_parents) <= 1
error("[Node Split] The given node does not have multiple parents which is required for node split")
end=#
for parent in n1_parents
remove_edge!(graph, make_edge(n1, parent))
end
for child in n1_children
remove_edge!(graph, make_edge(child, n1))
end
remove_node!(graph, n1)
for parent in n1_parents
n_copy = copy(n1)
insert_node!(graph, n_copy)
insert_edge!(graph, make_edge(n_copy, parent))
for child in n1_children
insert_edge!(graph, make_edge(child, n_copy))
end
end
return get_snapshot_diff(graph)
end
# function to find node fusions involving the given node if it's a data node
# pushes the found fusion everywhere it needs to be and returns nothing
function find_fusions!(graph::DAG, node::DataTaskNode)
if length(node.parents) != 1 || length(node.children) != 1
return nothing
end
child_node = first(node.children)
parent_node = first(node.parents)
#=if !(child_node in graph) || !(parent_node in graph)
error("Parents/Children that are not in the graph!!!")
end=#
if length(child_node.parents) != 1
return nothing
end
nf = NodeFusion((child_node, node, parent_node))
push!(graph.possibleOperations.nodeFusions, nf)
push!(child_node.operations, nf)
push!(node.operations, nf)
push!(parent_node.operations, nf)
return nothing
end
# function to find node fusions involving the given node if it's a compute node
# pushes the found fusion(s) everywhere it needs to be and returns nothing
function find_fusions!(graph::DAG, node::ComputeTaskNode)
# for loop that always runs once for a scoped block we can break out of
for _ in 1:1
# assume this node as child of the chain
if length(node.parents) != 1
break
end
node2 = first(node.parents)
if length(node2.parents) != 1 || length(node2.children) != 1
break
end
node3 = first(node2.parents)
#=if !(node2 in graph) || !(node3 in graph)
error("Parents/Children that are not in the graph!!!")
end=#
nf = NodeFusion((node, node2, node3))
push!(graph.possibleOperations.nodeFusions, nf)
push!(node.operations, nf)
push!(node2.operations, nf)
push!(node3.operations, nf)
end
for _ in 1:1
# assume this node as parent of the chain
if length(node.children) < 1
break
end
node2 = first(node.children)
if length(node2.parents) != 1 || length(node2.children) != 1
break
end
node1 = first(node2.children)
if (length(node1.parents) > 1)
break
end
#=if !(node2 in graph) || !(node1 in graph)
error("Parents/Children that are not in the graph!!!")
end=#
nf = NodeFusion((node1, node2, node))
push!(graph.possibleOperations.nodeFusions, nf)
push!(node1.operations, nf)
push!(node2.operations, nf)
push!(node.operations, nf)
end
return nothing
end
function find_reductions!(graph::DAG, node::Node)
reductionVector = nothing
# possible reductions are with nodes that are partners, i.e. parents of children
for partner in partners(node)
if can_reduce(node, partner)
if reductionVector === nothing
# only when there's at least one reduction partner, insert the vector
reductionVector = Vector{Node}()
push!(reductionVector, node)
end
push!(reductionVector, partner)
end
end
if reductionVector !== nothing
nr = NodeReduction(reductionVector)
push!(graph.possibleOperations.nodeReductions, nr)
for node in reductionVector
push!(node.operations, nr)
end
end
return nothing
end
function find_splits!(graph::DAG, node::Node)
if (can_split(node))
ns = NodeSplit(node)
push!(graph.possibleOperations.nodeSplits, ns)
push!(node.operations, ns)
end
return nothing
end
# "clean" the operations on a dirty node
function clean_node!(graph::DAG, node::Node)
find_fusions!(graph, node)
find_reductions!(graph, node)
find_splits!(graph, node)
delete!(graph.dirtyNodes, node)
end
# function to generate all possible optmizations on the graph
function generate_options(graph::DAG)
options = PossibleOperations()
# make sure the graph is fully generated through
apply_all!(graph)
# find possible node fusions
for node in graph.nodes
if (typeof(node) <: DataTaskNode)
if length(node.parents) != 1
# data node can only have a single parent
continue
end
parent_node = first(node.parents)
if length(node.children) != 1
# this node is an entry node or has multiple children which should not be possible
continue
end
child_node = first(node.children)
if (length(child_node.parents) != 1)
continue
end
nf = NodeFusion((child_node, node, parent_node))
push!(options.nodeFusions, nf)
push!(child_node.operations, nf)
push!(node.operations, nf)
push!(parent_node.operations, nf)
end
end
# find possible node reductions
visitedNodes = Set{Node}()
for node in graph.nodes
if (node in visitedNodes)
continue
end
push!(visitedNodes, node)
reductionVector = nothing
# possible reductions are with nodes that are partners, i.e. parents of children
for partner in partners(node)
if can_reduce(node, partner)
if reductionVector === nothing
# only when there's at least one reduction partner, insert the vector
reductionVector = Vector{Node}()
push!(reductionVector, node)
end
push!(reductionVector, partner)
push!(visitedNodes, partner)
end
end
if reductionVector !== nothing
nr = NodeReduction(reductionVector)
push!(options.nodeReductions, nr)
for node in reductionVector
push!(node.operations, nr)
end
end
end
# find possible node splits
for node in graph.nodes
if (can_split(node))
ns = NodeSplit(node)
push!(options.nodeSplits, ns)
push!(node.operations, ns)
end
end
graph.possibleOperations = options
empty!(graph.dirtyNodes)
end
function get_operations(graph::DAG)
apply_all!(graph)
if isempty(graph.possibleOperations)
generate_options(graph)
end
while !isempty(graph.dirtyNodes)
clean_node!(graph, first(graph.dirtyNodes))
end
return graph.possibleOperations
end

163
src/models/abc/compute.jl Normal file
View File

@ -0,0 +1,163 @@
using AccurateArithmetic
"""
compute(::ComputeTaskABC_P, data::ABCParticleValue)
Return the particle and value as is.
0 FLOP.
"""
function compute(::ComputeTaskABC_P, data::ABCParticleValue{P})::ABCParticleValue{P} where {P <: ABCParticle}
return data
end
"""
compute(::ComputeTaskABC_U, data::ABCParticleValue)
Compute an outer edge. Return the particle value with the same particle and the value multiplied by an ABC_outer_edge factor.
1 FLOP.
"""
function compute(::ComputeTaskABC_U, data::ABCParticleValue{P})::ABCParticleValue{P} where {P <: ABCParticle}
return ABCParticleValue{P}(data.p, data.v * ABC_outer_edge(data.p))
end
"""
compute(::ComputeTaskABC_V, data1::ABCParticleValue, data2::ABCParticleValue)
Compute a vertex. Preserve momentum and particle types (AB->C etc.) to create resulting particle, multiply values together and times a vertex factor.
6 FLOP.
"""
function compute(
::ComputeTaskABC_V,
data1::ABCParticleValue{P1},
data2::ABCParticleValue{P2},
)::ABCParticleValue where {P1 <: ABCParticle, P2 <: ABCParticle}
p3 = ABC_conserve_momentum(data1.p, data2.p)
dataOut = ABCParticleValue{typeof(p3)}(p3, data1.v * ABC_vertex() * data2.v)
return dataOut
end
"""
compute(::ComputeTaskABC_S2, data1::ABCParticleValue, data2::ABCParticleValue)
Compute a final inner edge (2 input particles, no output particle).
For valid inputs, both input particles should have the same momenta at this point.
12 FLOP.
"""
function compute(
::ComputeTaskABC_S2,
data1::ParticleValue{P},
data2::ParticleValue{P},
)::Float64 where {P <: ABCParticle}
#=
@assert isapprox(abs(data1.p.momentum.E), abs(data2.p.momentum.E), rtol = 0.001, atol = sqrt(eps())) "E: $(data1.p.momentum.E) vs. $(data2.p.momentum.E)"
@assert isapprox(data1.p.momentum.px, -data2.p.momentum.px, rtol = 0.001, atol = sqrt(eps())) "px: $(data1.p.momentum.px) vs. $(data2.p.momentum.px)"
@assert isapprox(data1.p.momentum.py, -data2.p.momentum.py, rtol = 0.001, atol = sqrt(eps())) "py: $(data1.p.momentum.py) vs. $(data2.p.momentum.py)"
@assert isapprox(data1.p.momentum.pz, -data2.p.momentum.pz, rtol = 0.001, atol = sqrt(eps())) "pz: $(data1.p.momentum.pz) vs. $(data2.p.momentum.pz)"
=#
inner = ABC_inner_edge(data1.p)
return data1.v * inner * data2.v
end
"""
compute(::ComputeTaskABC_S1, data::ABCParticleValue)
Compute inner edge (1 input particle, 1 output particle).
11 FLOP.
"""
function compute(::ComputeTaskABC_S1, data::ABCParticleValue{P})::ABCParticleValue{P} where {P <: ABCParticle}
return ABCParticleValue{P}(data.p, data.v * ABC_inner_edge(data.p))
end
"""
compute(::ComputeTaskABC_Sum, data::Vector{Float64})
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(::ComputeTaskABC_Sum, data::Vector{Float64})::Float64
return sum_kbn(data)
end
"""
get_expression(::ComputeTaskABC_P, device::AbstractDevice, inExprs::Vector{Expr}, outExpr::Expr)
Generate and return code evaluating [`ComputeTaskABC_P`](@ref) on `inSyms`, providing the output on `outSym`.
"""
function get_expression(::ComputeTaskABC_P, device::AbstractDevice, inExprs::Vector, outExpr)
in = [eval(inExprs[1])]
out = eval(outExpr)
return Meta.parse("$out = compute(ComputeTaskABC_P(), $(in[1]))")
end
"""
get_expression(::ComputeTaskABC_U, device::AbstractDevice, inExprs::Vector{Expr}, outExpr::Expr)
Generate code evaluating [`ComputeTaskABC_U`](@ref) on `inSyms`, providing the output on `outSym`.
`inSyms` should be of type [`ABCParticleValue`](@ref), `outSym` will be of type [`ABCParticleValue`](@ref).
"""
function get_expression(::ComputeTaskABC_U, device::AbstractDevice, inExprs::Vector, outExpr)
in = [eval(inExprs[1])]
out = eval(outExpr)
return Meta.parse("$out = compute(ComputeTaskABC_U(), $(in[1]))")
end
"""
get_expression(::ComputeTaskABC_V, device::AbstractDevice, inExprs::Vector{Expr}, outExpr::Expr)
Generate code evaluating [`ComputeTaskABC_V`](@ref) on `inSyms`, providing the output on `outSym`.
`inSym[1]` and `inSym[2]` should be of type [`ABCParticleValue`](@ref), `outSym` will be of type [`ABCParticleValue`](@ref).
"""
function get_expression(::ComputeTaskABC_V, device::AbstractDevice, inExprs::Vector, outExpr)
in = [eval(inExprs[1]), eval(inExprs[2])]
out = eval(outExpr)
return Meta.parse("$out = compute(ComputeTaskABC_V(), $(in[1]), $(in[2]))")
end
"""
get_expression(::ComputeTaskABC_S2, device::AbstractDevice, inExprs::Vector{Expr}, outExpr::Expr)
Generate code evaluating [`ComputeTaskABC_S2`](@ref) on `inSyms`, providing the output on `outSym`.
`inSyms[1]` and `inSyms[2]` should be of type [`ABCParticleValue`](@ref), `outSym` will be of type `Float64`.
"""
function get_expression(::ComputeTaskABC_S2, device::AbstractDevice, inExprs::Vector, outExpr)
in = [eval(inExprs[1]), eval(inExprs[2])]
out = eval(outExpr)
return Meta.parse("$out = compute(ComputeTaskABC_S2(), $(in[1]), $(in[2]))")
end
"""
get_expression(::ComputeTaskABC_S1, device::AbstractDevice, inExprs::Vector{Expr}, outExpr::Expr)
Generate code evaluating [`ComputeTaskABC_S1`](@ref) on `inSyms`, providing the output on `outSym`.
`inSyms` should be of type [`ABCParticleValue`](@ref), `outSym` will be of type [`ABCParticleValue`](@ref).
"""
function get_expression(::ComputeTaskABC_S1, device::AbstractDevice, inExprs::Vector, outExpr)
in = [eval(inExprs[1])]
out = eval(outExpr)
return Meta.parse("$out = compute(ComputeTaskABC_S1(), $(in[1]))")
end
"""
get_expression(::ComputeTaskABC_Sum, device::AbstractDevice, inExprs::Vector{Expr}, outExpr::Expr)
Generate code evaluating [`ComputeTaskABC_Sum`](@ref) on `inSyms`, providing the output on `outSym`.
`inSyms` should be of type [`Float64`], `outSym` will be of type [`Float64`].
"""
function get_expression(::ComputeTaskABC_Sum, device::AbstractDevice, inExprs::Vector, outExpr)
in = eval.(inExprs)
out = eval(outExpr)
return Meta.parse("$out = compute(ComputeTaskABC_Sum(), [$(unroll_symbol_vector(in))])")
end

64
src/models/abc/create.jl Normal file
View File

@ -0,0 +1,64 @@
using QEDbase
using Random
using Roots
using ForwardDiff
ComputeTaskABC_Sum() = ComputeTaskABC_Sum(0)
"""
gen_process_input(processDescription::ABCProcessDescription)
Return a ProcessInput of randomly generated [`ABCParticle`](@ref)s from a [`ABCProcessDescription`](@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::ABCProcessDescription)
inParticleTypes = keys(processDescription.inParticles)
outParticleTypes = keys(processDescription.outParticles)
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{ABCParticle}()
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{ABCParticle}()
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 = ABCProcessInput(processDescription, inputParticles, outputParticles)
return return processInput
end

248
src/models/abc/parse.jl Normal file
View File

@ -0,0 +1,248 @@
# functions for importing DAGs from a file
regex_a = r"^[A-C]\d+$" # Regex for the initial particles
regex_c = r"^[A-C]\(([^']*),([^']*)\)$" # Regex for the combinations of 2 particles
regex_m = r"^M\(([^']*),([^']*),([^']*)\)$" # Regex for the combinations of 3 particles
regex_plus = r"^\+$" # Regex for the sum
const PARTICLE_VALUE_SIZE::Int = 48
const FLOAT_SIZE::Int = 8
"""
parse_nodes(input::AbstractString)
Parse the given string into a vector of strings containing each node.
"""
function parse_nodes(input::AbstractString)
regex = r"'([^']*)'"
matches = eachmatch(regex, input)
output = [match.captures[1] for match in matches]
return output
end
"""
parse_edges(input::AbstractString)
Parse the given string into a vector of strings containing each edge. Currently unused since the entire graph can be read from just the node names.
"""
function parse_edges(input::AbstractString)
regex = r"\('([^']*)', '([^']*)'\)"
matches = eachmatch(regex, input)
output = [(match.captures[1], match.captures[2]) for match in matches]
return output
end
"""
parse_dag(filename::String, model::ABCModel; verbose::Bool = false)
Read an abc-model process from the given file. If `verbose` is set to true, print some progress information to stdout.
Returns a valid [`DAG`](@ref).
"""
function parse_dag(filename::AbstractString, model::ABCModel, verbose::Bool = false)
file = open(filename, "r")
if (verbose)
println("Opened file")
end
nodes_string = readline(file)
nodes = parse_nodes(nodes_string)
close(file)
if (verbose)
println("Read file")
end
graph = DAG()
# estimate total number of nodes
# try to slightly overestimate so no resizing is necessary
# data nodes are not included in length(nodes) and there are a few more than compute nodes
estimate_no_nodes = round(Int, length(nodes) * 4)
if (verbose)
println("Estimating ", estimate_no_nodes, " Nodes")
end
sizehint!(graph.nodes, estimate_no_nodes)
sum_node = insert_node!(graph, make_node(ComputeTaskABC_Sum(0)), track = false, invalidate_cache = false)
global_data_out = insert_node!(graph, make_node(DataTask(FLOAT_SIZE)), track = false, invalidate_cache = false)
insert_edge!(graph, sum_node, global_data_out, track = false, invalidate_cache = false)
# remember the data out nodes for connection
dataOutNodes = Dict()
if (verbose)
println("Building graph")
end
noNodes = 0
nodesToRead = length(nodes)
while !isempty(nodes)
node = popfirst!(nodes)
noNodes += 1
if (noNodes % 100 == 0)
if (verbose)
percent = string(round(100.0 * noNodes / nodesToRead, digits = 2), "%")
print("\rReading Nodes... $percent")
end
end
if occursin(regex_a, node)
# add nodes and edges for the state reading to u(P(Particle))
data_in = insert_node!(
graph,
make_node(DataTask(PARTICLE_VALUE_SIZE), string(node)),
track = false,
invalidate_cache = false,
) # read particle data node
compute_P = insert_node!(graph, make_node(ComputeTaskABC_P()), track = false, invalidate_cache = false) # compute P node
data_Pu =
insert_node!(graph, make_node(DataTask(PARTICLE_VALUE_SIZE)), track = false, invalidate_cache = false) # transfer data from P to u (one ABCParticleValue object)
compute_u = insert_node!(graph, make_node(ComputeTaskABC_U()), track = false, invalidate_cache = false) # compute U node
data_out =
insert_node!(graph, make_node(DataTask(PARTICLE_VALUE_SIZE)), track = false, invalidate_cache = false) # transfer data out from u (one ABCParticleValue object)
insert_edge!(graph, data_in, compute_P, track = false, invalidate_cache = false)
insert_edge!(graph, compute_P, data_Pu, track = false, invalidate_cache = false)
insert_edge!(graph, data_Pu, compute_u, track = false, invalidate_cache = false)
insert_edge!(graph, compute_u, data_out, track = false, invalidate_cache = false)
# remember the data_out node for future edges
dataOutNodes[node] = data_out
elseif occursin(regex_c, node)
capt = match(regex_c, node)
in1 = capt.captures[1]
in2 = capt.captures[2]
compute_v = insert_node!(graph, make_node(ComputeTaskABC_V()), track = false, invalidate_cache = false)
data_out =
insert_node!(graph, make_node(DataTask(PARTICLE_VALUE_SIZE)), track = false, invalidate_cache = false)
if (occursin(regex_c, in1))
# put an S node after this input
compute_S = insert_node!(graph, make_node(ComputeTaskABC_S1()), track = false, invalidate_cache = false)
data_S_v = insert_node!(
graph,
make_node(DataTask(PARTICLE_VALUE_SIZE)),
track = false,
invalidate_cache = false,
)
insert_edge!(graph, dataOutNodes[in1], compute_S, track = false, invalidate_cache = false)
insert_edge!(graph, compute_S, data_S_v, track = false, invalidate_cache = false)
insert_edge!(graph, data_S_v, compute_v, track = false, invalidate_cache = false)
else
insert_edge!(graph, dataOutNodes[in1], compute_v, track = false, invalidate_cache = false)
end
if (occursin(regex_c, in2))
# i think the current generator only puts the combined particles in the first space, so this case might never be entered
# put an S node after this input
compute_S = insert_node!(graph, make_node(ComputeTaskABC_S1()), track = false, invalidate_cache = false)
data_S_v = insert_node!(
graph,
make_node(DataTask(PARTICLE_VALUE_SIZE)),
track = false,
invalidate_cache = false,
)
insert_edge!(graph, dataOutNodes[in2], compute_S, track = false, invalidate_cache = false)
insert_edge!(graph, compute_S, data_S_v, track = false, invalidate_cache = false)
insert_edge!(graph, data_S_v, compute_v, track = false, invalidate_cache = false)
else
insert_edge!(graph, dataOutNodes[in2], compute_v, track = false, invalidate_cache = false)
end
insert_edge!(graph, compute_v, data_out, track = false, invalidate_cache = false)
dataOutNodes[node] = data_out
elseif occursin(regex_m, node)
# assume for now that only the first particle of the three is combined and the other two are "original" ones
capt = match(regex_m, node)
in1 = capt.captures[1]
in2 = capt.captures[2]
in3 = capt.captures[3]
# in2 + in3 with a v
compute_v = insert_node!(graph, make_node(ComputeTaskABC_V()), track = false, invalidate_cache = false)
data_v =
insert_node!(graph, make_node(DataTask(PARTICLE_VALUE_SIZE)), track = false, invalidate_cache = false)
insert_edge!(graph, dataOutNodes[in2], compute_v, track = false, invalidate_cache = false)
insert_edge!(graph, dataOutNodes[in3], compute_v, track = false, invalidate_cache = false)
insert_edge!(graph, compute_v, data_v, track = false, invalidate_cache = false)
# combine with the v of the combined other input
compute_S2 = insert_node!(graph, make_node(ComputeTaskABC_S2()), track = false, invalidate_cache = false)
data_out = insert_node!(graph, make_node(DataTask(FLOAT_SIZE)), track = false, invalidate_cache = false) # output of a S2 task is only a float
insert_edge!(graph, data_v, compute_S2, track = false, invalidate_cache = false)
insert_edge!(graph, dataOutNodes[in1], compute_S2, track = false, invalidate_cache = false)
insert_edge!(graph, compute_S2, data_out, track = false, invalidate_cache = false)
insert_edge!(graph, data_out, sum_node, track = false, invalidate_cache = false)
add_child!(task(sum_node))
elseif occursin(regex_plus, node)
if (verbose)
println("\rReading Nodes Complete ")
println("Added ", length(graph.nodes), " nodes")
end
else
@assert false ("Unknown node '$node' while reading from file $filename")
end
end
#put all nodes into dirty nodes set
graph.dirtyNodes = copy(graph.nodes)
if (verbose)
println("Generating the graph's properties")
end
graph.properties = GraphProperties(graph)
if (verbose)
println("Done")
end
# don't actually need to read the edges
return graph
end
"""
parse_process(string::AbstractString, model::ABCModel)
Parse a string representation of a process, such as "AB->ABBB" into the corresponding [`ABCProcessDescription`](@ref).
"""
function parse_process(str::AbstractString, model::ABCModel)
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)
inCount = count(x -> x == String(t)[1], inStr)
outCount = count(x -> x == String(t)[1], outStr)
if inCount != 0
inParticles[t] = inCount
end
if outCount != 0
outParticles[t] = outCount
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 ABCProcessDescription(inParticles, outParticles)
end

208
src/models/abc/particle.jl Normal file
View File

@ -0,0 +1,208 @@
import QEDbase.mass
"""
ABCModel <: AbstractPhysicsModel
Singleton definition for identification of the ABC-Model.
"""
struct ABCModel <: AbstractPhysicsModel end
"""
ABCParticle
Base type for all particles in the [`ABCModel`](@ref).
"""
abstract type ABCParticle <: AbstractParticle end
"""
ParticleA <: ABCParticle
An 'A' particle in the ABC Model.
"""
struct ParticleA <: ABCParticle
momentum::SFourMomentum
end
"""
ParticleB <: ABCParticle
A 'B' particle in the ABC Model.
"""
struct ParticleB <: ABCParticle
momentum::SFourMomentum
end
"""
ParticleC <: ABCParticle
A 'C' particle in the ABC Model.
"""
struct ParticleC <: ABCParticle
momentum::SFourMomentum
end
"""
ABCProcessDescription <: AbstractProcessDescription
A description of a process in the ABC-Model. Contains the input and output particles.
See also: [`in_particles`](@ref), [`out_particles`](@ref), [`parse_process`](@ref)
"""
struct ABCProcessDescription <: AbstractProcessDescription
inParticles::Dict{Type, Int}
outParticles::Dict{Type, Int}
end
"""
ABCProcessInput <: AbstractProcessInput
Input for a ABC Process. Contains the [`ABCProcessDescription`](@ref) of the process it is an input for, and the values of the in and out particles.
See also: [`gen_process_input`](@ref)
"""
struct ABCProcessInput <: AbstractProcessInput
process::ABCProcessDescription
inParticles::Vector{ABCParticle}
outParticles::Vector{ABCParticle}
end
ABCParticleValue{ParticleType <: ABCParticle} = ParticleValue{ParticleType, ComplexF64}
"""
PARTICLE_MASSES
A constant dictionary containing the masses of the different [`ABCParticle`](@ref)s.
"""
const PARTICLE_MASSES = Dict{Type, Float64}(ParticleA => 1.0, ParticleB => 1.0, ParticleC => 0.0)
"""
mass(t::Type{T}) where {T <: ABCParticle}
Return the mass (at rest) of the given particle type.
"""
mass(t::Type{T}) where {T <: ABCParticle} = PARTICLE_MASSES[t]
"""
interaction_result(t1::Type{T1}, t2::Type{T2}) where {T1 <: ABCParticle, T2 <: ABCParticle}
For 2 given (non-equal) particle types, return the third of ABC.
"""
function interaction_result(t1::Type{T1}, t2::Type{T2}) where {T1 <: ABCParticle, T2 <: ABCParticle}
@assert t1 != t2
if t1 != ParticleA && t2 != ParticleA
return ParticleA
elseif t1 != ParticleB && t2 != ParticleB
return ParticleB
else
return ParticleC
end
end
"""
types(::ABCModel)
Return a Vector of the possible types of particle in the [`ABCModel`](@ref).
"""
function types(::ABCModel)
return [ParticleA, ParticleB, ParticleC]
end
"""
square(p::ABCParticle)
Return the square of the particle's momentum as a `Float` value.
Takes 7 effective FLOP.
"""
function square(p::ABCParticle)
return getMass2(p.momentum)
end
"""
ABC_inner_edge(p::ABCParticle)
Return the factor of the inner edge with the given (virtual) particle.
Takes 10 effective FLOP. (3 here + 7 in square(p))
"""
function ABC_inner_edge(p::ABCParticle)
return 1.0 / (square(p) - mass(typeof(p)) * mass(typeof(p)))
end
"""
ABC_outer_edge(p::ABCParticle)
Return the factor of the outer edge with the given (real) particle.
Takes 0 effective FLOP.
"""
function ABC_outer_edge(p::ABCParticle)
return 1.0
end
"""
ABC_vertex()
Return the factor of a vertex.
Takes 0 effective FLOP since it's constant.
"""
function ABC_vertex()
i = 1.0
lambda = 1.0 / 137.0
return i * lambda
end
"""
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_conserve_momentum(p1::ABCParticle, p2::ABCParticle)
t3 = interaction_result(typeof(p1), typeof(p2))
p3 = t3(p1.momentum + p2.momentum)
return p3
end
model(::ABCProcessDescription) = ABCModel()
model(::ABCProcessInput) = ABCModel()
function type_index_from_name(::ABCModel, name::String)
if startswith(name, "A")
return (ParticleA, parse(Int, name[2:end]))
elseif startswith(name, "B")
return (ParticleB, parse(Int, name[2:end]))
elseif startswith(name, "C")
return (ParticleC, parse(Int, name[2:end]))
else
throw("Invalid name for a particle in the ABC model")
end
end
function String(::Type{ParticleA})
return "A"
end
function String(::Type{ParticleB})
return "B"
end
function String(::Type{ParticleC})
return "C"
end
function in_particles(process::ABCProcessDescription)
return process.inParticles
end
function in_particles(input::ABCProcessInput)
return input.inParticles
end
function out_particles(process::ABCProcessDescription)
return process.outParticles
end
function out_particles(input::ABCProcessInput)
return input.outParticles
end

58
src/models/abc/print.jl Normal file
View File

@ -0,0 +1,58 @@
"""
show(io::IO, process::ABCProcessDescription)
Pretty print an [`ABCProcessDescription`](@ref) (no newlines).
```jldoctest
julia> using MetagraphOptimization
julia> print(parse_process("AB->ABBB", ABCModel()))
ABC Process: 'AB->ABBB'
```
"""
function show(io::IO, process::ABCProcessDescription)
# types() gives the types in order (ABC) instead of random like keys() would
print(io, "ABC Process: \'")
for type in types(ABCModel())
for _ in 1:get(process.inParticles, type, 0)
print(io, String(type))
end
end
print(io, "->")
for type in types(ABCModel())
for _ in 1:get(process.outParticles, type, 0)
print(io, String(type))
end
end
print(io, "'")
return nothing
end
"""
show(io::IO, processInput::ABCProcessInput)
Pretty print an [`ABCProcessInput`](@ref) (with newlines).
"""
function show(io::IO, processInput::ABCProcessInput)
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 <: ABCParticle}
Pretty print an [`ABCParticle`](@ref) (no newlines).
"""
function show(io::IO, particle::T) where {T <: ABCParticle}
print(io, "$(String(typeof(particle))): $(particle.momentum)")
return nothing
end

View File

@ -0,0 +1,134 @@
"""
compute_effort(t::ComputeTaskABC_S1)
Return the compute effort of an S1 task.
"""
compute_effort(t::ComputeTaskABC_S1)::Float64 = 11.0
"""
compute_effort(t::ComputeTaskABC_S2)
Return the compute effort of an S2 task.
"""
compute_effort(t::ComputeTaskABC_S2)::Float64 = 12.0
"""
compute_effort(t::ComputeTaskABC_U)
Return the compute effort of a U task.
"""
compute_effort(t::ComputeTaskABC_U)::Float64 = 1.0
"""
compute_effort(t::ComputeTaskABC_V)
Return the compute effort of a V task.
"""
compute_effort(t::ComputeTaskABC_V)::Float64 = 6.0
"""
compute_effort(t::ComputeTaskABC_P)
Return the compute effort of a P task.
"""
compute_effort(t::ComputeTaskABC_P)::Float64 = 0.0
"""
compute_effort(t::ComputeTaskABC_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 ABC-Model,
this doesn't matter.
"""
compute_effort(t::ComputeTaskABC_Sum)::Float64 = 1.0
"""
show(io::IO, t::ComputeTaskABC_S1)
Print the S1 task to io.
"""
show(io::IO, t::ComputeTaskABC_S1) = print(io, "ComputeS1")
"""
show(io::IO, t::ComputeTaskABC_S2)
Print the S2 task to io.
"""
show(io::IO, t::ComputeTaskABC_S2) = print(io, "ComputeS2")
"""
show(io::IO, t::ComputeTaskABC_P)
Print the P task to io.
"""
show(io::IO, t::ComputeTaskABC_P) = print(io, "ComputeP")
"""
show(io::IO, t::ComputeTaskABC_U)
Print the U task to io.
"""
show(io::IO, t::ComputeTaskABC_U) = print(io, "ComputeU")
"""
show(io::IO, t::ComputeTaskABC_V)
Print the V task to io.
"""
show(io::IO, t::ComputeTaskABC_V) = print(io, "ComputeV")
"""
show(io::IO, t::ComputeTaskABC_Sum)
Print the sum task to io.
"""
show(io::IO, t::ComputeTaskABC_Sum) = print(io, "ComputeSum")
"""
children(::ComputeTaskABC_S1)
Return the number of children of a ComputeTaskABC_S1 (always 1).
"""
children(::ComputeTaskABC_S1) = 1
"""
children(::ComputeTaskABC_S2)
Return the number of children of a ComputeTaskABC_S2 (always 2).
"""
children(::ComputeTaskABC_S2) = 2
"""
children(::ComputeTaskABC_P)
Return the number of children of a ComputeTaskABC_P (always 1).
"""
children(::ComputeTaskABC_P) = 1
"""
children(::ComputeTaskABC_U)
Return the number of children of a ComputeTaskABC_U (always 1).
"""
children(::ComputeTaskABC_U) = 1
"""
children(::ComputeTaskABC_V)
Return the number of children of a ComputeTaskABC_V (always 2).
"""
children(::ComputeTaskABC_V) = 2
"""
children(::ComputeTaskABC_Sum)
Return the number of children of a ComputeTaskABC_Sum.
"""
children(t::ComputeTaskABC_Sum) = t.children_number
function add_child!(t::ComputeTaskABC_Sum)
t.children_number += 1
return nothing
end

51
src/models/abc/types.jl Normal file
View File

@ -0,0 +1,51 @@
"""
ComputeTaskABC_S1 <: AbstractComputeTask
S task with a single child.
"""
struct ComputeTaskABC_S1 <: AbstractComputeTask end
"""
ComputeTaskABC_S2 <: AbstractComputeTask
S task with two children.
"""
struct ComputeTaskABC_S2 <: AbstractComputeTask end
"""
ComputeTaskABC_P <: AbstractComputeTask
P task with no children.
"""
struct ComputeTaskABC_P <: AbstractComputeTask end
"""
ComputeTaskABC_V <: AbstractComputeTask
v task with two children.
"""
struct ComputeTaskABC_V <: AbstractComputeTask end
"""
ComputeTaskABC_U <: AbstractComputeTask
u task with a single child.
"""
struct ComputeTaskABC_U <: AbstractComputeTask end
"""
ComputeTaskABC_Sum <: AbstractComputeTask
Task that sums all its inputs, n children.
"""
mutable struct ComputeTaskABC_Sum <: AbstractComputeTask
children_number::Int
end
"""
ABC_TASKS
Constant vector of all tasks of the ABC-Model.
"""
ABC_TASKS =
[ComputeTaskABC_S1, ComputeTaskABC_S2, ComputeTaskABC_P, ComputeTaskABC_V, ComputeTaskABC_U, ComputeTaskABC_Sum]

112
src/models/interface.jl Normal file
View File

@ -0,0 +1,112 @@
import QEDbase.mass
import QEDbase.AbstractParticle
"""
AbstractPhysicsModel
Base type for a model, e.g. ABC-Model or QED. This is used to dispatch many functions.
"""
abstract type AbstractPhysicsModel end
"""
ParticleValue{ParticleType <: AbstractParticle}
A struct describing a particle during a calculation of a Feynman Diagram, together with the value that's being calculated. `AbstractParticle` is the type from the QEDbase package.
`sizeof(ParticleValue())` = 48 Byte
"""
struct ParticleValue{ParticleType <: AbstractParticle, ValueType}
p::ParticleType
v::ValueType
end
"""
AbstractProcessDescription
Base type for process descriptions. An object of this type of a corresponding [`AbstractPhysicsModel`](@ref) should uniquely identify a process in that model.
See also: [`parse_process`](@ref)
"""
abstract type AbstractProcessDescription end
"""
AbstractProcessInput
Base type for process inputs. An object of this type contains the input values (e.g. momenta) of the particles in a process.
See also: [`gen_process_input`](@ref)
"""
abstract type AbstractProcessInput end
"""
interaction_result(t1::Type{T1}, t2::Type{T2}) where {T1 <: AbstractParticle, T2 <: AbstractParticle}
Interface function that must be implemented for every subtype of [`AbstractParticle`](@ref), returning the result particle type when the two given particles interact.
"""
function interaction_result end
"""
types(::AbstractPhysicsModel)
Interface function that must be implemented for every subtype of [`AbstractPhysicsModel`](@ref), returning a `Vector` of the available particle types in the model.
"""
function types end
"""
in_particles(::AbstractProcessDescription)
Interface function that must be implemented for every subtype of [`AbstractProcessDescription`](@ref).
Returns a `<: Dict{Type{AbstractParticle}, Int}` object, representing the number of incoming particles for the process per particle type.
in_particles(::AbstractProcessInput)
Interface function that must be implemented for every subtype of [`AbstractProcessInput`](@ref).
Returns a `<: Vector{AbstractParticle}` object with the values of all incoming particles for the corresponding `ProcessDescription`.
"""
function in_particles end
"""
out_particles(::AbstractProcessDescription)
Interface function that must be implemented for every subtype of [`AbstractProcessDescription`](@ref).
Returns a `<: Dict{Type{AbstractParticle}, Int}` object, representing the number of outgoing particles for the process per particle type.
out_particles(::AbstractProcessInput)
Interface function that must be implemented for every subtype of [`AbstractProcessInput`](@ref).
Returns a `<: Vector{AbstractParticle}` object with the values of all outgoing particles for the corresponding `ProcessDescription`.
"""
function out_particles end
"""
parse_process(::AbstractString, ::AbstractPhysicsModel)
Interface function that must be implemented for every subtype of [`AbstractPhysicsModel`](@ref).
Returns a `ProcessDescription` object.
"""
function parse_process end
"""
gen_process_input(::AbstractProcessDescription)
Interface function that must be implemented for every specific [`AbstractProcessDescription`](@ref).
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

10
src/models/print.jl Normal file
View File

@ -0,0 +1,10 @@
"""
show(io::IO, particleValue::ParticleValue)
Pretty print a [`ParticleValue`](@ref), no newlines.
"""
function show(io::IO, particleValue::ParticleValue)
print(io, "($(particleValue.p), value: $(particleValue.v))")
return nothing
end

198
src/models/qed/compute.jl Normal file
View File

@ -0,0 +1,198 @@
"""
compute(::ComputeTaskQED_P, data::QEDParticleValue)
Return the particle as is and initialize the Value.
"""
function compute(::ComputeTaskQED_P, data::QEDParticleValue{P})::QEDParticleValue{P} where {P <: QEDParticle}
# TODO do we actually need this for anything?
return QEDParticleValue{P}(data.p, one(DiracMatrix))
end
"""
compute(::ComputeTaskQED_U, data::QEDParticleValue)
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::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,
state, # will return a SLorentzVector{ComplexF64}, BiSpinor or AdjointBiSpinor
)
end
"""
compute(::ComputeTaskQED_V, data1::QEDParticleValue, data2::QEDParticleValue)
Compute a vertex. Preserve momentum and particle types (e + gamma->p etc.) to create resulting particle, multiply values together and times a vertex factor.
"""
function compute(
::ComputeTaskQED_V,
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)
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
"""
compute(::ComputeTaskQED_S2, data1::QEDParticleValue, data2::QEDParticleValue)
Compute a final inner edge (2 input particles, no output particle).
For valid inputs, both input particles should have the same momenta at this point.
12 FLOP.
"""
function compute(
::ComputeTaskQED_S2,
data1::ParticleValue{P1},
data2::ParticleValue{P2},
)::ComplexF64 where {
P1 <: Union{AntiFermionStateful, FermionStateful},
P2 <: Union{AntiFermionStateful, FermionStateful},
}
@assert isapprox(data1.p.momentum, data2.p.momentum, rtol = sqrt(eps()), atol = sqrt(eps())) "$(data1.p.momentum) vs. $(data2.p.momentum)"
inner = QED_inner_edge(propagation_result(P1)(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
"""
compute(::ComputeTaskQED_S1, data::QEDParticleValue)
Compute inner edge (1 input particle, 1 output particle).
"""
function compute(::ComputeTaskQED_S1, data::QEDParticleValue{P})::QEDParticleValue where {P <: QEDParticle}
newP = propagation_result(P)
new_p = newP(data.p)
# inner edge is just a scalar, can multiply from either side
if typeof(data.v) <: BiSpinor
return ParticleValue(new_p, QED_inner_edge(new_p) * data.v)
else
return ParticleValue(new_p, data.v * QED_inner_edge(new_p))
end
end
"""
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{ComplexF64})::ComplexF64
# TODO: want to use sum_kbn here but it doesn't seem to support ComplexF64, do it element-wise?
return sum(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

172
src/models/qed/create.jl Normal file
View File

@ -0,0 +1,172 @@
ComputeTaskQED_Sum() = ComputeTaskQED_Sum(0)
"""
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
push!(outputParticles, particle(final_momenta[index]))
index += 1
end
end
processInput = QEDProcessInput(processDescription, inputParticles, outputParticles)
return return processInput
end
"""
gen_graph(process_description::QEDProcessDescription)
For a given [`QEDProcessDescription`](@ref), return the [`DAG`](@ref) that computes it.
"""
function gen_graph(process_description::QEDProcessDescription)
initial_diagram = FeynmanDiagram(process_description)
diagrams = gen_diagrams(initial_diagram)
graph = DAG()
COMPLEX_SIZE = sizeof(ComplexF64)
PARTICLE_VALUE_SIZE = 96.0
# TODO: Not all diagram outputs should always be summed at the end, if they differ by fermion exchange they need to be diffed
# Should not matter for n-Photon Compton processes though
sum_node = insert_node!(graph, make_node(ComputeTaskQED_Sum(0)), track = false, invalidate_cache = false)
global_data_out = insert_node!(graph, make_node(DataTask(COMPLEX_SIZE)), track = false, invalidate_cache = false)
insert_edge!(graph, sum_node, global_data_out, track = false, invalidate_cache = false)
# remember the data out nodes for connection
dataOutNodes = Dict()
for particle in initial_diagram.particles
# generate data in and U tasks
data_in = insert_node!(
graph,
make_node(DataTask(PARTICLE_VALUE_SIZE), String(particle)),
track = false,
invalidate_cache = false,
) # read particle data node
compute_u = insert_node!(graph, make_node(ComputeTaskQED_U()), track = false, invalidate_cache = false) # compute U node
data_out =
insert_node!(graph, make_node(DataTask(PARTICLE_VALUE_SIZE)), track = false, invalidate_cache = false) # transfer data out from u (one ABCParticleValue object)
insert_edge!(graph, data_in, compute_u, track = false, invalidate_cache = false)
insert_edge!(graph, compute_u, data_out, track = false, invalidate_cache = false)
# remember the data_out node for future edges
dataOutNodes[String(particle)] = data_out
end
#dataOutBackup = copy(dataOutNodes)
for diagram in diagrams
# the intermediate (virtual) particles change across
#dataOutNodes = copy(dataOutBackup)
tie = diagram.tie[]
# handle the vertices
for vertices in diagram.vertices
for vertex in vertices
data_in1 = dataOutNodes[String(vertex.in1)]
data_in2 = dataOutNodes[String(vertex.in2)]
compute_V = insert_node!(graph, make_node(ComputeTaskQED_V()), track = false, invalidate_cache = false) # compute vertex
insert_edge!(graph, data_in1, compute_V, track = false, invalidate_cache = false)
insert_edge!(graph, data_in2, compute_V, track = false, invalidate_cache = false)
data_V_out = insert_node!(
graph,
make_node(DataTask(PARTICLE_VALUE_SIZE)),
track = false,
invalidate_cache = false,
)
insert_edge!(graph, compute_V, data_V_out, track = false, invalidate_cache = false)
if (vertex.out == tie.in1 || vertex.out == tie.in2)
# out particle is part of the tie -> there will be an S2 task with it later, don't make S1 task
dataOutNodes[String(vertex.out)] = data_V_out
continue
end
# otherwise, add S1 task
compute_S1 =
insert_node!(graph, make_node(ComputeTaskQED_S1()), track = false, invalidate_cache = false) # compute propagator
insert_edge!(graph, data_V_out, compute_S1, track = false, invalidate_cache = false)
data_S1_out = insert_node!(
graph,
make_node(DataTask(PARTICLE_VALUE_SIZE)),
track = false,
invalidate_cache = false,
)
insert_edge!(graph, compute_S1, data_S1_out, track = false, invalidate_cache = false)
# overrides potentially different nodes from previous diagrams, which is intentional
dataOutNodes[String(vertex.out)] = data_S1_out
end
end
# handle the tie
data_in1 = dataOutNodes[String(tie.in1)]
data_in2 = dataOutNodes[String(tie.in2)]
compute_S2 = insert_node!(graph, make_node(ComputeTaskQED_S2()), track = false, invalidate_cache = false)
data_S2 = insert_node!(graph, make_node(DataTask(PARTICLE_VALUE_SIZE)), track = false, invalidate_cache = false)
insert_edge!(graph, data_in1, compute_S2, track = false, invalidate_cache = false)
insert_edge!(graph, data_in2, compute_S2, track = false, invalidate_cache = false)
insert_edge!(graph, compute_S2, data_S2, track = false, invalidate_cache = false)
insert_edge!(graph, data_S2, sum_node, track = false, invalidate_cache = false)
add_child!(task(sum_node))
end
return graph
end

484
src/models/qed/diagrams.jl Normal file
View File

@ -0,0 +1,484 @@
import Base.copy
import Base.hash
import Base.==
import Base.show
"""
FeynmanParticle
Representation of a particle for use in [`FeynmanDiagram`](@ref)s. Consist of the [`QEDParticle`](@ref) type and an id.
"""
struct FeynmanParticle
particle::Type{<:QEDParticle}
id::Int
end
"""
FeynmanVertex
Representation of a vertex in a [`FeynmanDiagram`](@ref). Stores two input [`FeynmanParticle`](@ref)s and one output.
"""
struct FeynmanVertex
in1::FeynmanParticle
in2::FeynmanParticle
out::FeynmanParticle
end
"""
FeynmanTie
Representation of a "tie" in a [`FeynmanDiagram`](@ref). A tie ties two virtual particles in a diagram together and thus represent an inner line of the diagram. Not all inner lines are [`FeynmanTie`](@ref)s, in fact, a connected diagram only ever has exactly one tie.
"""
struct FeynmanTie
in1::FeynmanParticle
in2::FeynmanParticle
end
"""
FeynmanDiagram
Representation of a feynman diagram. It consists of its initial input/output particles, and a vector of sets of [`FeynmanVertex`](@ref)s. The vertices are to be applied level by level.
A [`FeynmanVertex`](@ref) will always be at the lowest level possible, i.e. the lowest level at which all input particles for it exist.
The [`FeynmanTie`](@ref) represents the final inner edge of the diagram.
"""
struct FeynmanDiagram
vertices::Vector{Set{FeynmanVertex}}
tie::Ref{Union{FeynmanTie, Missing}}
particles::Vector{FeynmanParticle}
type_ids::Dict{Type, Int64} # lut for number of used ids for a particle type
end
"""
FeynmanDiagram(pd::QEDProcessDescription)
Create an initial [`FeynmanDiagram`](@ref) with only its initial particles set and no vertices or ties.
Use [`gen_diagrams`](@ref) to generate all possible diagrams from this one.
"""
function FeynmanDiagram(pd::QEDProcessDescription)
parts = Vector{FeynmanParticle}()
for (type, n) in pd.inParticles
for i in 1:n
push!(parts, FeynmanParticle(type, i))
end
end
for (type, n) in pd.outParticles
for i in 1:n
push!(parts, FeynmanParticle(type, i))
end
end
ids = Dict{Type, Int64}()
for t in types(QEDModel())
if (isincoming(t))
ids[t] = get(pd.inParticles, t, 0)
else
ids[t] = get(pd.outParticles, t, 0)
end
end
return FeynmanDiagram([], missing, parts, ids)
end
function particle_after_tie(p::FeynmanParticle, t::FeynmanTie)
if p == t.in1 || p == t.in2
return FeynmanParticle(FermionStateful{Incoming}, -1) # placeholder particle and id for tied particles
end
return p
end
function vertex_after_tie(v::FeynmanVertex, t::FeynmanTie)
return FeynmanVertex(particle_after_tie(v.in1, t), particle_after_tie(v.in2, t), particle_after_tie(v.out, t))
end
function vertex_after_tie(v::FeynmanVertex, t::Missing)
return v
end
function vertex_set_after_tie(vs::Set{FeynmanVertex}, t::FeynmanTie)
return Set{FeynmanVertex}(vertex_after_tie(v, t) for v in vs)
end
function vertex_set_after_tie(vs::Set{FeynmanVertex}, t::Missing)
return vs
end
function vertex_set_after_tie(vs::Set{FeynmanVertex}, t1::Union{FeynmanTie, Missing}, t2::Union{FeynmanTie, Missing})
return Set{FeynmanVertex}(vertex_after_tie(vertex_after_tie(v, t1), t2) for v in vs)
end
"""
String(p::FeynmanParticle)
Return a string representation of the [`FeynmanParticle`](@ref) in a format that is readable by [`type_index_from_name`](@ref).
"""
function String(p::FeynmanParticle)
return "$(String(p.particle))$(String(direction(p.particle)))$(p.id)"
end
function hash(v::FeynmanVertex)
return hash(v.in1) * hash(v.in2)
end
function hash(t::FeynmanTie)
return hash(t.in1) * hash(t.in2)
end
function hash(d::FeynmanDiagram)
return hash((d.vertices, d.particles))
end
function ==(v1::FeynmanVertex, v2::FeynmanVertex)
return (v1.in1 == v2.in1 && v1.in2 == v2.in1) || (v1.in2 == v2.in1 && v1.in1 == v2.in2)
end
function ==(t1::FeynmanTie, t2::FeynmanTie)
return (t1.in1 == t2.in1 && t1.in2 == t2.in1) || (t1.in2 == t2.in1 && t1.in1 == t2.in2)
end
function ==(d1::FeynmanDiagram, d2::FeynmanDiagram)
if (!ismissing(d1.tie[]) && ismissing(d2.tie[])) || (ismissing(d1.tie[]) && !ismissing(d2.tie[]))
return false
end
if d1.particles != d2.particles
return false
end
if length(d1.vertices) != length(d2.vertices)
return false
end
# TODO can i prove that this works?
for (v1, v2) in zip(d1.vertices, d2.vertices)
if vertex_set_after_tie(v1, d1.tie[], d2.tie[]) != vertex_set_after_tie(v2, d1.tie[], d2.tie[])
return false
end
end
return true
#=return isequal.(
vertex_set_after_tie(d1.vertices, d1.tie, d2.tie),
vertex_set_after_tie(d2.vertices, d1.tie, d2.tie),
)=#
end
copy(fd::FeynmanDiagram) =
FeynmanDiagram(deepcopy(fd.vertices), copy(fd.tie[]), deepcopy(fd.particles), copy(fd.type_ids))
"""
id_for_type(d::FeynmanDiagram, t::Type{<:QEDParticle})
Return the highest id of any particle of the given type in the diagram + 1.
"""
function id_for_type(d::FeynmanDiagram, t::Type{<:QEDParticle})
return d.type_ids[t] + 1
end
"""
can_apply_vertex(particles::Vector{FeynmanParticle}, vertex::FeynmanVertex)
Return true if the given [`FeynmanVertex`](@ref) can be applied to the given particles, i.e. both input particles of the vertex are in the vector and the output particle is not.
"""
function can_apply_vertex(particles::Vector{FeynmanParticle}, vertex::FeynmanVertex)
return vertex.in1 in particles && vertex.in2 in particles && !(vertex.out in particles)
end
"""
apply_vertex!(particles::Vector{FeynmanParticle}, vertex::FeynmanVertex)
Apply a [`FeynmanVertex`](@ref) to the given vector of [`FeynmanParticle`](@ref)s.
"""
function apply_vertex!(particles::Vector{FeynmanParticle}, vertex::FeynmanVertex)
#@assert can_apply_vertex(particles, vertex)
length_before = length(particles)
filter!(x -> x != vertex.in1 && x != vertex.in2, particles)
push!(particles, vertex.out)
#@assert length(particles) == length_before - 1
return nothing
end
"""
can_apply_tie(particles::Vector{FeynmanParticle}, tie::FeynmanTie)
Return true if the given [`FeynmanTie`](@ref) can be applied to the given particles, i.e. both input particles of the tie are in the vector.
"""
function can_apply_tie(particles::Vector{FeynmanParticle}, tie::FeynmanTie)
return tie.in1 in particles && tie.in2 in particles
end
"""
apply_tie!(particles::Vector{FeynmanParticle}, tie::FeynmanTie)
Apply a [`FeynmanTie`](@ref) to the given vector of [`FeynmanParticle`](@ref)s.
"""
function apply_tie!(particles::Vector{FeynmanParticle}, tie::FeynmanTie)
@assert length(particles) == 2
@assert can_apply_tie(particles, tie)
@assert can_tie(tie.in1.particle, tie.in2.particle)
empty!(particles)
@assert length(particles) == 0
return nothing
end
function apply_tie!(::Vector{FeynmanParticle}, ::Missing)
return nothing
end
"""
get_particles(fd::FeynmanDiagram, level::Int)
Return a vector of the particles after applying the vertices and tie of the diagram up to the given level. If no level is given, apply all. The tie comes last and is its own "level".
"""
function get_particles(fd::FeynmanDiagram, level::Int = -1)
if level == -1
level = length(fd.vertices) + 1
end
working_particles = copy(fd.particles)
for l in 1:length(fd.vertices)
if l > level
break
end
for v in fd.vertices[l]
apply_vertex!(working_particles, v)
end
end
if (level > length(fd.vertices))
apply_tie!(working_particles, fd.tie[])
end
return working_particles
end
"""
add_vertex!(fd::FeynmanDiagram, vertex::FeynmanVertex)
Add the given vertex to the diagram, at the earliest level possible.
"""
function add_vertex!(fd::FeynmanDiagram, vertex::FeynmanVertex)
for i in eachindex(fd.vertices)
if (can_apply_vertex(get_particles(fd, i - 1), vertex))
push!(fd.vertices[i], vertex)
fd.type_ids[vertex.out.particle] += 1
return nothing
end
end
if !can_apply_vertex(get_particles(fd), vertex)
#@assert false "Can't add vertex $vertex to diagram"
end
push!(fd.vertices, Set{FeynmanVertex}())
push!(fd.vertices[end], vertex)
fd.type_ids[vertex.out.particle] += 1
return nothing
end
"""
add_vertex(fd::FeynmanDiagram, vertex::FeynmanVertex)
Add the given vertex to the diagram, at the earliest level possible. Return the new diagram without muting the given one.
"""
function add_vertex(fd::FeynmanDiagram, vertex::FeynmanVertex)
newfd = copy(fd)
add_vertex!(newfd, vertex)
return newfd
end
"""
add_tie!(fd::FeynmanDiagram, tie::FeynmanTie)
Add the given tie to the diagram, always at the last level.
"""
function add_tie!(fd::FeynmanDiagram, tie::FeynmanTie)
if !can_apply_tie(get_particles(fd), tie)
@assert false "Can't add tie $tie to diagram"
end
fd.tie[] = tie
#=
@assert length(fd.vertices) >= 2
#if the last vertex is involved in the tie and alone, lower it one level down
if (length(fd.vertices[end]) != 1)
return nothing
end
vert = fd.vertices[end][1]
if (vert != vertex_after_tie(vert, tie))
return nothing
end
pop!(fd.vertices)
push!(fd.vertices[end], vert)
=#
return nothing
end
"""
add_tie(fd::FeynmanDiagram, tie::FeynmanTie)
Add the given tie to the diagram, at the earliest level possible. Return the new diagram without muting the given one.
"""
function add_tie(fd::FeynmanDiagram, tie::FeynmanTie)
newfd = copy(fd)
add_tie!(newfd, tie)
return newfd
end
"""
isvalid(fd::FeynmanDiagram)
Return whether the given diagram is valid. A diagram is valid iff the following are true:
- After applying all vertices and the tie, there are no more particles left
- The diagram is connected
"""
function isvalid(fd::FeynmanDiagram)
if ismissing(fd.tie[])
# diagram is connected iff there is one tie
return false
end
if get_particles(fd) != []
return false
end
return true
end
"""
possible_vertices(fd::FeynmanDiagram)
Return a vector of all possible vertices that can be applied to the diagram at its current state.
"""
function possible_vertices(fd::FeynmanDiagram)
possibilities = Vector{FeynmanVertex}()
fully_generated_particles = get_particles(fd)
min_level = max(0, length(fd.vertices) - 1)
for l in min_level:length(fd.vertices)
particles = get_particles(fd, l)
for i in 1:length(particles)
for j in (i + 1):length(particles)
p1 = particles[i]
p2 = particles[j]
if (caninteract(p1.particle, p2.particle))
interaction_res = propagation_result(interaction_result(p1.particle, p2.particle))
v = FeynmanVertex(p1, p2, FeynmanParticle(interaction_res, id_for_type(fd, interaction_res)))
#@assert !(v.out in particles) "$v is in $fd"
if !can_apply_vertex(fully_generated_particles, v)
continue
end
push!(possibilities, v)
end
end
end
if (!isempty(possibilities))
return possibilities
end
end
return possibilities
end
"""
can_tie(p1::Type, p2::Type)
For two given [`QEDParitcle`](@ref) types, return whether they can be tied together.
They can be tied iff one is the [`propagation_result`](@ref) of the other, or if both are photons, in which case their direction does not matter.
"""
function can_tie(p1::Type, p2::Type)
if p1 == propagation_result(p2)
return true
end
if (p1 <: PhotonStateful && p2 <: PhotonStateful)
return true
end
return false
end
"""
possible_tie(fd::FeynmanDiagram)
Return a possible tie or `missing` for the diagram at its current state.
"""
function possible_tie(fd::FeynmanDiagram)
particles = get_particles(fd)
if (length(particles) != 2)
return missing
end
if (particles[1] in fd.particles || particles[2] in fd.particles)
return missing
end
tie = FeynmanTie(particles[1], particles[2])
if (can_apply_tie(particles, tie))
return tie
end
return missing
end
function remove_duplicates(compare_set::Set{FeynmanDiagram})
result = Set()
while !isempty(compare_set)
x = pop!(compare_set)
# we know there will only be one duplicate if any, so search for that and delete it
for y in compare_set
if x == y
delete!(compare_set, y)
break
end
end
push!(result, x)
end
return result
end
"""
gen_diagrams(fd::FeynmanDiagram)
From a given feynman diagram in its initial state, e.g. when created through the [`FeynmanDiagram(pd::ProcessDescription)`](@ref) constructor, generate and return all possible [`FeynmanDiagram`](@ref)s that describe that process.
"""
function gen_diagrams(fd::FeynmanDiagram)
working = Set{FeynmanDiagram}()
results = Set{FeynmanDiagram}()
push!(working, fd)
# we know there will be particle_number - 2 vertices, followed by 1 tie
n_particles = length(fd.particles)
n_vertices = n_particles - 2
# doing this in iterations should reduce the intermediate number of diagrams by hash collisions
for _ in 1:n_vertices
next_iter_set = Set{FeynmanDiagram}()
while !isempty(working)
d = pop!(working)
possibilities = possible_vertices(d)
for v in possibilities
push!(next_iter_set, add_vertex(d, v))
end
end
working = next_iter_set
end
# add the tie
for d in working
tie = possible_tie(d)
if ismissing(tie)
continue
end
add_tie!(d, tie)
if isvalid(d)
push!(results, d)
end
end
return remove_duplicates(results)
end

44
src/models/qed/parse.jl Normal file
View File

@ -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

348
src/models/qed/particle.jl Normal file
View File

@ -0,0 +1,348 @@
using QEDprocesses
import QEDbase.mass
# TODO check
const e = sqrt(4π / 137)
"""
QEDModel <: AbstractPhysicsModel
Singleton definition for identification of the QED-Model.
"""
struct QEDModel <: AbstractPhysicsModel end
"""
QEDParticle
Base type for all particles in the [`QEDModel`](@ref).
Its template parameter specifies the particle's direction.
The concrete types contain singletons of the types that they are, like `Photon` and `Electron` from QEDbase, and their state descriptions.
"""
abstract type QEDParticle{Direction <: ParticleDirection} <: AbstractParticle end
"""
QEDProcessDescription <: AbstractProcessDescription
A description of a process in the QED-Model. Contains the input and output particles.
See also: [`in_particles`](@ref), [`out_particles`](@ref), [`parse_process`](@ref)
"""
struct QEDProcessDescription <: AbstractProcessDescription
inParticles::Dict{Type{<:QEDParticle{Incoming}}, Int}
outParticles::Dict{Type{<:QEDParticle{Outgoing}}, Int}
end
"""
QEDProcessInput <: AbstractProcessInput
Input for a QED Process. Contains the [`QEDProcessDescription`](@ref) of the process it is an input for, and the values of the in and out particles.
See also: [`gen_process_input`](@ref)
"""
struct QEDProcessInput <: AbstractProcessInput
process::QEDProcessDescription
inParticles::Vector{QEDParticle}
outParticles::Vector{QEDParticle}
end
QEDParticleValue{ParticleType <: QEDParticle} = Union{
ParticleValue{ParticleType, BiSpinor},
ParticleValue{ParticleType, AdjointBiSpinor},
ParticleValue{ParticleType, DiracMatrix},
ParticleValue{ParticleType, SLorentzVector{Float64}},
ParticleValue{ParticleType, ComplexF64},
}
"""
PhotonStateful <: QEDParticle
A photon of the [`QEDModel`](@ref) with its state.
"""
struct PhotonStateful{Direction <: ParticleDirection} <: QEDParticle{Direction}
momentum::SFourMomentum
# this will maybe change to the full polarization vector? or do i need both
polarization::AbstractDefinitePolarization
end
PhotonStateful{Direction}(mom::SFourMomentum) where {Direction <: ParticleDirection} =
PhotonStateful{Direction}(mom, PolX()) # TODO: make allpol possible
PhotonStateful{Dir1}(ph::PhotonStateful{Dir2}) where {Dir1 <: ParticleDirection, Dir2 <: ParticleDirection} =
PhotonStateful{Dir1}(ph.momentum, ph.polarization)
"""
FermionStateful <: QEDParticle
A fermion of the [`QEDModel`](@ref) with its state.
"""
struct FermionStateful{Direction <: ParticleDirection} <: QEDParticle{Direction}
momentum::SFourMomentum
spin::AbstractDefiniteSpin
# TODO: mass for electron/muon/tauon representation?
end
FermionStateful{Direction}(mom::SFourMomentum) where {Direction <: ParticleDirection} =
FermionStateful{Direction}(mom, SpinUp()) # TODO: make allspin possible
FermionStateful{Dir1}(f::FermionStateful{Dir2}) where {Dir1 <: ParticleDirection, Dir2 <: ParticleDirection} =
FermionStateful{Dir1}(f.momentum, f.spin)
"""
AntiFermionStateful <: QEDParticle
An anti-fermion of the [`QEDModel`](@ref) with its state.
"""
struct AntiFermionStateful{Direction <: ParticleDirection} <: QEDParticle{Direction}
momentum::SFourMomentum
spin::AbstractDefiniteSpin
# TODO: mass for electron/muon/tauon representation?
end
AntiFermionStateful{Direction}(mom::SFourMomentum) where {Direction <: ParticleDirection} =
AntiFermionStateful{Direction}(mom, SpinUp()) # TODO: make allspin possible
AntiFermionStateful{Dir1}(f::AntiFermionStateful{Dir2}) where {Dir1 <: ParticleDirection, Dir2 <: ParticleDirection} =
AntiFermionStateful{Dir1}(f.momentum, f.spin)
"""
interaction_result(t1::Type{T1}, t2::Type{T2}) where {T1 <: QEDParticle, T2 <: QEDParticle}
For two given particle types that can interact, return the third.
"""
function interaction_result(t1::Type{T1}, t2::Type{T2}) where {T1 <: QEDParticle, T2 <: QEDParticle}
@assert false "Invalid interaction between particles of types $t1 and $t2"
end
interaction_result(::Type{FermionStateful{Incoming}}, ::Type{FermionStateful{Outgoing}}) = PhotonStateful{Incoming}
interaction_result(::Type{FermionStateful{Incoming}}, ::Type{AntiFermionStateful{Incoming}}) = PhotonStateful{Incoming}
interaction_result(::Type{FermionStateful{Incoming}}, ::Type{<:PhotonStateful}) = FermionStateful{Outgoing}
interaction_result(::Type{FermionStateful{Outgoing}}, ::Type{FermionStateful{Incoming}}) = PhotonStateful{Incoming}
interaction_result(::Type{FermionStateful{Outgoing}}, ::Type{AntiFermionStateful{Outgoing}}) = PhotonStateful{Incoming}
interaction_result(::Type{FermionStateful{Outgoing}}, ::Type{<:PhotonStateful}) = FermionStateful{Incoming}
# antifermion mirror
interaction_result(::Type{AntiFermionStateful{Incoming}}, t2::Type{<:QEDParticle}) =
interaction_result(FermionStateful{Outgoing}, t2)
interaction_result(::Type{AntiFermionStateful{Outgoing}}, t2::Type{<:QEDParticle}) =
interaction_result(FermionStateful{Incoming}, t2)
# photon commutativity
interaction_result(t1::Type{<:PhotonStateful}, t2::Type{<:QEDParticle}) = interaction_result(t2, t1)
# but prevent stack overflow
function interaction_result(t1::Type{<:PhotonStateful}, t2::Type{<:PhotonStateful})
@assert false "Invalid interaction between particles of types $t1 and $t2"
end
"""
propagation_result(t1::Type{T}) where {T <: QEDParticle}
Return the type of the inverted direction. E.g.
"""
propagation_result(::Type{FermionStateful{Incoming}}) = FermionStateful{Outgoing}
propagation_result(::Type{FermionStateful{Outgoing}}) = FermionStateful{Incoming}
propagation_result(::Type{AntiFermionStateful{Incoming}}) = AntiFermionStateful{Outgoing}
propagation_result(::Type{AntiFermionStateful{Outgoing}}) = AntiFermionStateful{Incoming}
propagation_result(::Type{PhotonStateful{Incoming}}) = PhotonStateful{Outgoing}
propagation_result(::Type{PhotonStateful{Outgoing}}) = PhotonStateful{Incoming}
"""
types(::QEDModel)
Return a Vector of the possible types of particle in the [`QEDModel`](@ref).
"""
function types(::QEDModel)
return [
PhotonStateful{Incoming},
PhotonStateful{Outgoing},
FermionStateful{Incoming},
FermionStateful{Outgoing},
AntiFermionStateful{Incoming},
AntiFermionStateful{Outgoing},
]
end
# type piracy?
String(::Type{Incoming}) = "Incoming"
String(::Type{Outgoing}) = "Outgoing"
String(::Incoming) = "i"
String(::Outgoing) = "o"
function String(::Type{<:PhotonStateful})
return "k"
end
function String(::Type{<:FermionStateful})
return "e"
end
function String(::Type{<:AntiFermionStateful})
return "p"
end
@inline particle(::PhotonStateful) = Photon()
@inline particle(::FermionStateful) = Electron()
@inline particle(::AntiFermionStateful) = Positron()
@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
@inline spin_or_pol(p::AntiFermionStateful)::AbstractSpin = p.spin
@inline direction(::PhotonStateful{Dir}) where {Dir <: ParticleDirection} = Dir()
@inline direction(::FermionStateful{Dir}) where {Dir <: ParticleDirection} = Dir()
@inline direction(::AntiFermionStateful{Dir}) where {Dir <: ParticleDirection} = Dir()
@inline direction(::Type{PhotonStateful{Dir}}) where {Dir <: ParticleDirection} = Dir()
@inline direction(::Type{FermionStateful{Dir}}) where {Dir <: ParticleDirection} = Dir()
@inline direction(::Type{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
@inline invert_momentum(p::FermionStateful{Dir}) where {Dir <: ParticleDirection} =
FermionStateful{Dir}(-p.momentum, p.spin)
@inline invert_momentum(p::AntiFermionStateful{Dir}) where {Dir <: ParticleDirection} =
AntiFermionStateful{Dir}(-p.momentum, p.spin)
@inline invert_momentum(k::PhotonStateful{Dir}) where {Dir <: ParticleDirection} =
PhotonStateful{Dir}(-k.momentum, k.polarization)
"""
caninteract(T1::Type{<:QEDParticle}, T2::Type{<:QEDParticle})
For two given [`QEDParticle`](@ref) types, return whether they can interact at a vertex. This is equivalent to `!issame(T1, T2)`.
See also: [`issame`](@ref) and [`interaction_result`](@ref)
"""
function caninteract(T1::Type{<:QEDParticle}, T2::Type{<:QEDParticle})
if (T1 == T2)
return false
end
if (T1 <: PhotonStateful && T2 <: PhotonStateful)
return false
end
for (P1, P2) in [(T1, T2), (T2, T1)]
if (P1 == FermionStateful{Incoming} && P2 == AntiFermionStateful{Outgoing})
return false
end
if (P1 == FermionStateful{Outgoing} && P2 == AntiFermionStateful{Incoming})
return false
end
end
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})
For two given [`QEDParticle`](@ref) types, return whether they are equivalent for the purpose of a Feynman Diagram. That means e.g. an `Incoming` `AntiFermion` is the same as an `Outgoing` `Fermion`. This is equivalent to `!caninteract(T1, T2)`.
See also: [`caninteract`](@ref) and [`interaction_result`](@ref)
"""
function issame(T1::Type{<:QEDParticle}, T2::Type{<:QEDParticle})
return !caninteract(T1, T2)
end
"""
QED_vertex()
Return the factor of a vertex in a QED feynman diagram.
"""
@inline function QED_vertex()::SLorentzVector{DiracMatrix}
# Peskin-Schroeder notation
return -1im * e * gamma()
end
@inline function QED_inner_edge(p::QEDParticle)
pos_mom = p.momentum
return propagator(particle(p), pos_mom)
end
"""
QED_conserve_momentum(p1::QEDParticle, p2::QEDParticle)
Calculate and return a new particle from two given interacting ones at a vertex.
"""
function QED_conserve_momentum(p1::QEDParticle, p2::QEDParticle)
#println("Conserving momentum of \n$(direction(p1)) $(p1)\n and \n$(direction(p2)) $(p2)")
T3 = interaction_result(typeof(p1), typeof(p2))
# TODO: probably also need to do something about the spin/pol
p1_mom = p1.momentum
if (typeof(direction(p1)) <: Outgoing)
p1_mom *= -1
end
p2_mom = p2.momentum
if (typeof(direction(p2)) <: Outgoing)
p2_mom *= -1
end
p3_mom = p1_mom + p2_mom
if (typeof(direction(T3)) <: Incoming)
return T3(-p3_mom)
end
return T3(p3_mom)
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

115
src/models/qed/print.jl Normal file
View File

@ -0,0 +1,115 @@
"""
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
"""
show(io::IO, particle::FeynmanParticle)
Pretty print a [`FeynmanParticle`](@ref) (no newlines).
"""
show(io::IO, p::FeynmanParticle) = print(io, "$(String(p.particle))_$(String(direction(p.particle)))_$(p.id)")
"""
show(io::IO, particle::FeynmanVertex)
Pretty print a [`FeynmanVertex`](@ref) (no newlines).
"""
show(io::IO, v::FeynmanVertex) = print(io, "$(v.in1) + $(v.in2) -> $(v.out)")
"""
show(io::IO, particle::FeynmanTie)
Pretty print a [`FeynmanTie`](@ref) (no newlines).
"""
show(io::IO, t::FeynmanTie) = print(io, "$(t.in1) -- $(t.in2)")
"""
show(io::IO, particle::FeynmanDiagram)
Pretty print a [`FeynmanDiagram`](@ref) (with newlines).
"""
function show(io::IO, d::FeynmanDiagram)
print(io, "Initial Particles: [")
first = true
for p in d.particles
if first
first = false
print(io, "$p")
else
print(io, ", $p")
end
end
print(io, "]\n")
for l in eachindex(d.vertices)
print(io, " Virtuality Level $l Vertices: [")
first = true
for v in d.vertices[l]
if first
first = false
print(io, "$v")
else
print(io, ", $v")
end
end
print(io, "]\n")
end
return print(io, " Tie: $(d.tie[])\n")
end

View File

@ -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

51
src/models/qed/types.jl Normal file
View File

@ -0,0 +1,51 @@
"""
ComputeTaskQED_S1 <: AbstractComputeTask
S task with a single child.
"""
struct ComputeTaskQED_S1 <: AbstractComputeTask end
"""
ComputeTaskQED_S2 <: AbstractComputeTask
S task with two children.
"""
struct ComputeTaskQED_S2 <: AbstractComputeTask end
"""
ComputeTaskQED_P <: AbstractComputeTask
P task with no children.
"""
struct ComputeTaskQED_P <: AbstractComputeTask end
"""
ComputeTaskQED_V <: AbstractComputeTask
v task with two children.
"""
struct ComputeTaskQED_V <: AbstractComputeTask end
"""
ComputeTaskQED_U <: AbstractComputeTask
u task with a single child.
"""
struct ComputeTaskQED_U <: AbstractComputeTask end
"""
ComputeTaskQED_Sum <: AbstractComputeTask
Task that sums all its inputs, n children.
"""
mutable struct ComputeTaskQED_Sum <: AbstractComputeTask
children_number::Int
end
"""
QED_TASKS
Constant vector of all tasks of the QED-Model.
"""
QED_TASKS =
[ComputeTaskQED_S1, ComputeTaskQED_S2, ComputeTaskQED_P, ComputeTaskQED_V, ComputeTaskQED_U, ComputeTaskQED_Sum]

35
src/node/compare.jl Normal file
View File

@ -0,0 +1,35 @@
"""
==(e1::Edge, e2::Edge)
Equality comparison between two edges.
"""
function ==(e1::Edge, e2::Edge)
return e1.edge[1] == e2.edge[1] && e1.edge[2] == e2.edge[2]
end
"""
==(n1::Node, n2::Node)
Fallback equality comparison between two nodes. For equal node types, the more specific versions of this function will be called.
"""
function ==(n1::Node, n2::Node)
return false
end
"""
==(n1::ComputeTaskNode, n2::ComputeTaskNode)
Equality comparison between two [`ComputeTaskNode`](@ref)s.
"""
function ==(n1::ComputeTaskNode{TaskType}, n2::ComputeTaskNode{TaskType}) where {TaskType <: AbstractComputeTask}
return n1.id == n2.id
end
"""
==(n1::DataTaskNode, n2::DataTaskNode)
Equality comparison between two [`DataTaskNode`](@ref)s.
"""
function ==(n1::DataTaskNode{TaskType}, n2::DataTaskNode{TaskType}) where {TaskType <: AbstractDataTask}
return n1.id == n2.id
end

Some files were not shown because too many files have changed in this diff Show More