Initial Commit

This commit is contained in:
Anton Reinhard 2024-04-01 21:52:05 +02:00
commit a959137e22
10 changed files with 225 additions and 0 deletions

2
.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
.vscode/
**/Manifest.toml

4
Project.toml Normal file
View File

@ -0,0 +1,4 @@
name = "FeynmanDiagramGenerator"
uuid = "8f7ec768-9801-4863-9e03-72391fd2204f"
authors = ["antonr <s1509337@msx.tu-dresden.de>"]
version = "0.1.0"

6
README.md Normal file
View File

@ -0,0 +1,6 @@
# FeynmanDiagrams.jl
Generator for FeynmanDiagrams of any QFT as long as all vertices have exactly 3 legs.
Very much WIP.

View File

@ -0,0 +1,9 @@
module FeynmanDiagramGenerator
export Forest
include("trees/trees.jl")
include("trees/iterator.jl")
include("trees/print.jl")
end # module FeynmanDiagramGenerator

102
src/trees/iterator.jl Normal file
View File

@ -0,0 +1,102 @@
mutable struct ForestIterator
# how many leaves do the left subtrees have
left_leaves::Int
left_subiterator::Union{ForestIterator,Missing}
# how many leaves do the right subtrees have
right_leaves::Int
right_subiterator::Union{ForestIterator,Missing}
# counter is like an id and incremented each time _iterate is called
# important for symmetry breaking for iterators where n is even and the subtrees can have equal leave numbers
counter::Int
end
function ForestIterator(n::Int)
@assert n >= 1 "Cannot create a ForestIterator with fewer than 1 leaves"
if n == 1
return missing
end
return ForestIterator(1, ForestIterator(1), n - 1, ForestIterator(n - 1), 1)
end
ForestIterator(forest::Forest) = ForestIterator(forest.leaves)
"""
IteratorSize(::Forest)
Would be OEIS sequence A001190, Wedderburn-Etherington numbers: Number of unlabeled binary rooted trees with n leaves.
"""
Base.IteratorSize(::Forest) = Base.SizeUnknown()
Base.IteratorSize(::ForestIterator) = Base.SizeUnknown()
"""
is_end(::ForestIterator)
Return whether the given [`ForestIterator`](@ref) is exhausted.
"""
is_end(::Missing) = true
is_end(iterator::ForestIterator) = iterator.left_leaves + 1 >= iterator.right_leaves && is_end(iterator.left_subiterator) && is_end(iterator.right_subiterator)
"""
tree(iterator::ForestIterator)
Return an [`AbstractTree`](@ref) made from the current state of the iterator.
"""
tree(::Missing) = EmptyTree()
function tree(iterator::ForestIterator)
return Subtree(tree(iterator.left_subiterator), tree(iterator.right_subiterator))
end
"""
_iterate(iterator::ForestIterator)
Internal function for iterating the [`ForestIterator`](@ref) once.
"""
function _iterate(iterator::ForestIterator)
@assert !is_end(iterator) "Trying to iterate a forest iterator that is already at its end"
iterator.counter += 1
# reverse direction, iterate right first, then left (reset right), then try new balance
if !is_end(iterator.right_subiterator)
_iterate(iterator.right_subiterator)
return nothing
elseif !is_end(iterator.left_subiterator)
iterator.right_subiterator = ForestIterator(iterator.right_leaves)
if (iterator.left_leaves == iterator.right_leaves)
# if the subiterators have equal lengths, take care to start the one we reset where the other one currently is (to not get duplicates)
# this actually only changes things at forest(8) and higher
while (iterator.right_subiterator.counter <= iterator.left_subiterator.counter)
_iterate(iterator.right_subiterator)
end
end
_iterate(iterator.left_subiterator)
return nothing
else
iterator.right_leaves -= 1
iterator.left_leaves += 1
iterator.right_subiterator = ForestIterator(iterator.right_leaves)
iterator.left_subiterator = ForestIterator(iterator.left_leaves)
return nothing
end
end
function Base.iterate(forest::Forest)
state = ForestIterator(forest.leaves)
return (tree(state), state)
end
function Base.iterate(forest::Forest, state::Missing)
return nothing
end
function Base.iterate(forest::Forest, state::ForestIterator)
if (is_end(state))
return nothing
end
_iterate(state)
return (tree(state), state)
end

8
src/trees/print.jl Normal file
View File

@ -0,0 +1,8 @@
function Base.show(io::IO, tree::EmptyTree)
print(io, "T1")
end
function Base.show(io::IO, tree::Subtree)
print(io, "T$(leaves(tree))<$(tree.left)> <$(tree.right)>")
end

60
src/trees/trees.jl Normal file
View File

@ -0,0 +1,60 @@
# The subtrees of tree-level feynman diagrams
# the subtrees are always binary since we assume that all feynman vertices have 3 leaves
# the order of left and right don't matter because we are only interested in topologies
import Base.iterate
"""
AbstractTree
Base type for trees, such as [`EmptyTree`](@ref) or [`Subtree`](@ref).
Implementations provide [`leaves`](@ref), returning the number of leaves of the tree.
"""
abstract type AbstractTree end
"""
EmptyTree <: AbstractTree
A singleton type representing an empty tree, which has 1 leaf, see [`leaves`](@ref).
"""
struct EmptyTree <: AbstractTree end
"""
Subtree <: AbstractTree
Representation of a specific subtree topology, with two subtrees of its own.
"""
struct Subtree <: AbstractTree
left::AbstractTree
right::AbstractTree
end
"""
Forest
Representation of a forest containing all topologically unique trees with a given number of leaves.
Use [`iterate`](@ref) to iterate through the [`Subtree`](@ref)s.
"""
struct Forest
leaves::Int
function Forest(n::Int)
@assert n > 0 "Can not create forest of trees with $n leaves, must be at least 1"
new(n)
end
end
"""
leaves(tree::AbstractTree)
Returns the number of leaves or leaves of the tree.
"""
function leaves end
leaves(tree::EmptyTree) = 1
leaves(tree::Subtree) = leaves(tree.left) + leaves(tree.right)
leaves(forest::Forest) = forest.leaves

3
test/Project.toml Normal file
View File

@ -0,0 +1,3 @@
[deps]
SafeTestsets = "1bc83da4-3b8d-516f-aca4-4fe02f6d838f"
Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40"

5
test/runtests.jl Normal file
View File

@ -0,0 +1,5 @@
using SafeTestsets
@safetestset "Trees" begin
include("trees.jl")
end

26
test/trees.jl Normal file
View File

@ -0,0 +1,26 @@
using FeynmanDiagramGenerator
import FeynmanDiagramGenerator.EmptyTree
import FeynmanDiagramGenerator.Subtree
import FeynmanDiagramGenerator.leaves
import FeynmanDiagramGenerator.ForestIterator
@testset "Number of leaves" begin
@test leaves(EmptyTree()) == 1
@test leaves(Subtree(EmptyTree(), EmptyTree())) == 2
@test leaves(Subtree(EmptyTree(), Subtree(EmptyTree(), EmptyTree()))) == 3
end
@testset "Number of Forests" begin
@test_throws AssertionError Forest(0)
@test_throws AssertionError ForestIterator(0)
groundtruth_lengths = [1, 1, 1, 2, 3, 6, 11, 23, 46, 98, 207, 451, 983, 2179, 4850, 10905, 24631, 56011, 127912, 293547]
@testset "Forest with $i leaves" for i in 1:20
@test length([t for t in Forest(i)]) == groundtruth_lengths[i]
for t in Forest(i)
@test leaves(t) == i
end
end
end