Initial Commit
This commit is contained in:
commit
a959137e22
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
.vscode/
|
||||||
|
**/Manifest.toml
|
4
Project.toml
Normal file
4
Project.toml
Normal 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
6
README.md
Normal 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.
|
9
src/FeynmanDiagramGenerator.jl
Normal file
9
src/FeynmanDiagramGenerator.jl
Normal 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
102
src/trees/iterator.jl
Normal 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
8
src/trees/print.jl
Normal 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
60
src/trees/trees.jl
Normal 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
3
test/Project.toml
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
[deps]
|
||||||
|
SafeTestsets = "1bc83da4-3b8d-516f-aca4-4fe02f6d838f"
|
||||||
|
Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40"
|
5
test/runtests.jl
Normal file
5
test/runtests.jl
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
using SafeTestsets
|
||||||
|
|
||||||
|
@safetestset "Trees" begin
|
||||||
|
include("trees.jl")
|
||||||
|
end
|
26
test/trees.jl
Normal file
26
test/trees.jl
Normal 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
|
Loading…
x
Reference in New Issue
Block a user