From e63ba06a85dbd2242316eb74443cd1e4f4a00e4a Mon Sep 17 00:00:00 2001 From: Tao Wang Date: Thu, 16 Nov 2023 11:45:12 -0500 Subject: [PATCH 1/3] add count operation for diagtree and AbstractGraph --- example/benchmark.jl | 10 +++--- src/computational_graph/tree_properties.jl | 6 ++-- src/diagram_tree/tree.jl | 37 ++++++++++++++++++++++ src/utility.jl | 21 +++++++++++- 4 files changed, 66 insertions(+), 8 deletions(-) diff --git a/example/benchmark.jl b/example/benchmark.jl index 334a8882..fc9a9c93 100644 --- a/example/benchmark.jl +++ b/example/benchmark.jl @@ -22,11 +22,11 @@ function assign_leaves(g::FeynmanGraph, taylormap) return leafmap, leafvec end -dict_g, fl, bl, leafmap = diagdictGV(:sigma, [(2, 0, 0), (2, 0, 1), (2, 0, 2), (2, 1, 0), (2, 1, 1), (2, 2, 0), (2, 1, 2), (2, 2, 2)], 3) +#dict_g, fl, bl, leafmap = diagdictGV(:sigma, [(2, 0, 0), (2, 0, 1), (2, 0, 2), (2, 1, 0), (2, 1, 1), (2, 2, 0), (2, 1, 2), (2, 2, 2)], 3) +dict_g, fl, bl, leafmap = diagdictGV(:sigma, [(3, 0, 0), (3, 0, 3), (3, 0, 2), (3, 0, 1)], 3) +g = dict_g[(3, 0, 0)] -g = dict_g[(2, 0, 0)] - -set_variables("x y", orders=[2, 2]) +set_variables("x y", orders=[1, 3]) propagator_var = ([true, false], [false, true]) # Specify variable dependence of fermi (first element) and bose (second element) particles. t, taylormap = taylorexpansion!(g[1][1], propagator_var, (fl, bl)) @@ -36,6 +36,8 @@ for (order, graph) in dict_g else idx = 2 end + print("$(count_operation(t.coeffs[[order[2],order[3]]]))\n") + print("$(count_operation(graph[1][idx]))\n") print("$(order) $(eval!(graph[1][idx])) $(eval!(t.coeffs[[order[2],order[3]]]))\n") end diff --git a/src/computational_graph/tree_properties.jl b/src/computational_graph/tree_properties.jl index 82f4cce4..84e2819b 100644 --- a/src/computational_graph/tree_properties.jl +++ b/src/computational_graph/tree_properties.jl @@ -119,7 +119,7 @@ end # Arguments: - `g::Graph`: graph for which to find the total number of operations. """ -function count_operation(g::Graph) +function count_operation(g::G) where {G<:AbstractGraph} totalsum = 0 totalprod = 0 for node in PreOrderDFS(g) @@ -134,7 +134,7 @@ function count_operation(g::Graph) return [totalsum, totalprod] end -function count_operation(g::Array{G}) where {G<:Graph} +function count_operation(g::Vector{G}) where {G<:AbstractGraph} visited = Set{Int}() totalsum = 0 totalprod = 0 @@ -156,7 +156,7 @@ function count_operation(g::Array{G}) where {G<:Graph} end -function count_operation(g::Dict{Vector{Int},G}) where {G<:Graph} +function count_operation(g::Dict{Vector{Int},G}) where {G<:AbstractGraph} visited = Set{Int}() totalsum = 0 totalprod = 0 diff --git a/src/diagram_tree/tree.jl b/src/diagram_tree/tree.jl index 8f34f9ab..fc30a5c1 100644 --- a/src/diagram_tree/tree.jl +++ b/src/diagram_tree/tree.jl @@ -236,3 +236,40 @@ AbstractTrees.nodetype(::Diagram{W}) where {W} = Diagram{W} # (They are not sufficient to solve all internal inference issues, however.) Base.eltype(::Type{<:TreeIterator{Diagram{W}}}) where {W} = Diagram{W} Base.IteratorEltype(::Type{<:TreeIterator{Diagram{W}}}) where {W} = Base.HasEltype() + +function count_operation(g::T) where {T<:Diagram} + totalsum = 0 + totalprod = 0 + for node in PreOrderDFS(g) + #print(node.hash) + if length(node.subdiagram) > 0 + if node.operator isa Prod + totalprod += length(node.subdiagram) - 1 + elseif node.operator isa Sum + totalsum += length(node.subdiagram) - 1 + end + end + end + return [totalsum, totalprod] +end + +function count_operation(g::Vector{T}) where {T<:Diagram} + visited = Set{Int}() + totalsum = 0 + totalprod = 0 + for graph in g + for node in PreOrderDFS(graph) + if !(node.hash in visited) + push!(visited, node.hash) + if length(node.subdiagram) > 0 + if node.operator isa Prod + totalprod += length(node.subdiagram) - 1 + elseif node.operator isa Sum + totalsum += length(node.subdiagram) - 1 + end + end + end + end + end + return [totalsum, totalprod] +end diff --git a/src/utility.jl b/src/utility.jl index 26bcf668..52b69039 100644 --- a/src/utility.jl +++ b/src/utility.jl @@ -186,7 +186,14 @@ function taylorexpansion!(graphs::Vector{G}, var_dependence::Dict{Int,Vector{Boo return result, taylormap end - +function taylorexpansion!(graphs::Vector{Diagram{W}}, propagator_var::Dict{DataType,Vector{Bool}}; taylormap::Dict{Int,TaylorSeries{Graph{W,W}}}=Dict{Int,TaylorSeries{Graph{W,W}}}()) where {W} + result = Vector{TaylorSeries{Graph{W,W}}}() + for graph in graphs + taylor, _ = taylorexpansion!(graph, propagator_var; taylormap=taylormap) + push!(result, taylor) + end + return result, taylormap +end """ taylorexpansion_withmap(g::G; coeffmode=true, var::Vector{Int}=collect(1:get_numvars())) where {G<:Graph} @@ -372,4 +379,16 @@ function count_operation(graphs::Vector{TaylorSeries{G}}) where {G<:Graph} end end +function count_operation(graphs::Vector{TaylorSeries{G}}, order::Vector{Int}) where {G<:Graph} + if length(graphs) == 0 + return [0, 0] + else + allcoeffs = Vector{G}() + for g in graphs + push!(allcoeffs, g.coeffs[order]) + end + return count_operation(allcoeffs) + end +end + end \ No newline at end of file From feba9f46403a3373012e2ee01bee1d0cbe13a069 Mon Sep 17 00:00:00 2001 From: Tao Wang Date: Thu, 16 Nov 2023 21:23:59 -0500 Subject: [PATCH 2/3] add from coeff map wip --- example/benchmark.jl | 4 +- src/utility.jl | 93 +++++++++++++++++++++++++------------------- 2 files changed, 54 insertions(+), 43 deletions(-) diff --git a/example/benchmark.jl b/example/benchmark.jl index fc9a9c93..653909a7 100644 --- a/example/benchmark.jl +++ b/example/benchmark.jl @@ -23,12 +23,12 @@ function assign_leaves(g::FeynmanGraph, taylormap) end #dict_g, fl, bl, leafmap = diagdictGV(:sigma, [(2, 0, 0), (2, 0, 1), (2, 0, 2), (2, 1, 0), (2, 1, 1), (2, 2, 0), (2, 1, 2), (2, 2, 2)], 3) -dict_g, fl, bl, leafmap = diagdictGV(:sigma, [(3, 0, 0), (3, 0, 3), (3, 0, 2), (3, 0, 1)], 3) +dict_g, lp, leafmap = diagdictGV(:sigma, [(3, 0, 0), (3, 0, 3), (3, 0, 2), (3, 0, 1)]) g = dict_g[(3, 0, 0)] set_variables("x y", orders=[1, 3]) propagator_var = ([true, false], [false, true]) # Specify variable dependence of fermi (first element) and bose (second element) particles. -t, taylormap = taylorexpansion!(g[1][1], propagator_var, (fl, bl)) +t, taylormap, from_coeff_map = taylorexpansion!(g[1][1], propagator_var) for (order, graph) in dict_g if graph[2][1] == g[2][1] diff --git a/src/utility.jl b/src/utility.jl index 8e5c43cd..f399af7d 100644 --- a/src/utility.jl +++ b/src/utility.jl @@ -19,18 +19,18 @@ using ..Taylor """ - function taylorexpansion!(graph::G, var_dependence::Dict{Int,Vector{Bool}}=Dict{Int,Vector{Bool}}(); taylormap::Dict{Int,TaylorSeries{G}}=Dict{Int,TaylorSeries{G}}()) where {G<:Graph} + function taylorexpansion!(graph::G, var_dependence::Dict{Int,Vector{Bool}}=Dict{Int,Vector{Bool}}(); to_coeff_map::Dict{Int,TaylorSeries{G}}=Dict{Int,TaylorSeries{G}}()) where {G<:Graph} Return a taylor series of graph g, together with a map of between nodes of g and correponding taylor series. # Arguments: - `graph` Target graph - `var_dependence::Dict{Int,Vector{Bool}}` A dictionary that specifies the variable dependence of target graph leaves. Should map the id of each leaf to a Bool vector. The length of the vector should be the same as number of variables. -- `taylormap::Dict{Int,TaylorSeries}` A dicitonary that maps id of each node of target graph to its correponding taylor series. +- `to_coeff_map::Dict{Int,TaylorSeries}` A dicitonary that maps id of each node of target graph to its correponding taylor series. """ -function taylorexpansion!(graph::G, var_dependence::Dict{Int,Vector{Bool}}=Dict{Int,Vector{Bool}}(); taylormap::Dict{Int,TaylorSeries{G}}=Dict{Int,TaylorSeries{G}}()) where {G<:Graph} - if haskey(taylormap, graph.id) #If already exist, use taylor series in taylormap. - return taylormap[graph.id], taylormap +function taylorexpansion!(graph::G, var_dependence::Dict{Int,Vector{Bool}}=Dict{Int,Vector{Bool}}(); to_coeff_map::Dict{Int,TaylorSeries{G}}=Dict{Int,TaylorSeries{G}}()) where {G<:Graph} + if haskey(to_coeff_map, graph.id) #If already exist, use taylor series in to_coeff_map. + return to_coeff_map[graph.id], to_coeff_map elseif isleaf(graph) if haskey(var_dependence, graph.id) @@ -49,27 +49,37 @@ function taylorexpansion!(graph::G, var_dependence::Dict{Int,Vector{Bool}}=Dict{ result.coeffs[o] = coeff end end - taylormap[graph.id] = result - return result, taylormap + to_coeff_map[graph.id] = result + return result, to_coeff_map else - taylormap[graph.id] = graph.factor * apply(graph.operator, [taylorexpansion!(sub, var_dependence; taylormap=taylormap)[1] for sub in graph.subgraphs], graph.subgraph_factors) - return taylormap[graph.id], taylormap + to_coeff_map[graph.id] = graph.factor * apply(graph.operator, [taylorexpansion!(sub, var_dependence; to_coeff_map=to_coeff_map)[1] for sub in graph.subgraphs], graph.subgraph_factors) + return to_coeff_map[graph.id], to_coeff_map end end """ - function taylorexpansion!(graph::FeynmanGraph{F,W}, var_dependence::Dict{Int,Vector{Bool}}=Dict{Int,Vector{Bool}}(); taylormap::Dict{Int,TaylorSeries{G}}=Dict{Int,TaylorSeries{G}}()) where {F,W} + function taylorexpansion!(graph::FeynmanGraph{F,W}, var_dependence::Dict{Int,Vector{Bool}}=Dict{Int,Vector{Bool}}(); to_coeff_map::Dict{Int,TaylorSeries{G}}=Dict{Int,TaylorSeries{G}}()) where {F,W} Return a taylor series of FeynmanGraph g, together with a map of between nodes of g and correponding taylor series. # Arguments: - `graph` Target FeynmanGraph - `var_dependence::Dict{Int,Vector{Bool}}` A dictionary that specifies the variable dependence of target graph leaves. Should map the id of each leaf to a Bool vector. The length of the vector should be the same as number of variables. -- `taylormap::Dict{Int,TaylorSeries}` A dicitonary that maps id of each node of target graph to its correponding taylor series. +- `to_coeff_map::Dict{Int,TaylorSeries}` A dicitonary that maps id of each node of target graph to its correponding taylor series. +- `from_coeff_map::Dict{Int,Tuple{Int,Vector{Bool}}}` A dicitonary that maps a taylor coefficient to its owner FeynmanGraph. The key should be the id of coefficient graph, and value should be a tuple of (feynmangraph.id, order). """ -function taylorexpansion!(graph::FeynmanGraph{F,W}, var_dependence::Dict{Int,Vector{Bool}}=Dict{Int,Vector{Bool}}(); taylormap::Dict{Int,TaylorSeries{Graph{F,W}}}=Dict{Int,TaylorSeries{Graph{F,W}}}()) where {F,W} - if haskey(taylormap, graph.id) #If already exist, use taylor series in taylormap. - return taylormap[graph.id], taylormap +function taylorexpansion!(graph::FeynmanGraph{F,W}, var_dependence::Dict{Int,Vector{Bool}}=Dict{Int,Vector{Bool}}(); to_coeff_map::Dict{Int,TaylorSeries{Graph{F,W}}}=Dict{Int,TaylorSeries{Graph{F,W}}}(), from_coeff_map::Dict{Int,Tuple{Int,Vector{Int}}}=Dict{Int,Tuple{Int,Vector{Int}}}()) where {F,W} + if haskey(to_coeff_map, graph.id) #If already exist, use taylor series in to_coeff_map. + if isleaf(graph) + for (order, coeff) in to_coeff_map[graph.id].coeffs + if haskey(from_coeff_map, coeff.id) + @assert from_coeff_map[coeff.id] == (graph.id, order) "The graph g$(graph.id) is mapped to two different leaf taylor series!" + else + from_coeff_map[coeff.id] = (graph.id, order) + end + end + end + return to_coeff_map[graph.id], to_coeff_map, from_coeff_map elseif isleaf(graph) if haskey(var_dependence, graph.id) @@ -83,28 +93,29 @@ function taylorexpansion!(graph::FeynmanGraph{F,W}, var_dependence::Dict{Int,Vec o = collect(order) coeff = Graph([]; operator=ComputationalGraphs.Sum(), factor=graph.factor) result.coeffs[o] = coeff + from_coeff_map[coeff.id] = (graph.id, o) end - taylormap[graph.id] = result - return result, taylormap + to_coeff_map[graph.id] = result + return result, to_coeff_map, from_coeff_map else - taylormap[graph.id] = graph.factor * apply(graph.operator, [taylorexpansion!(sub, var_dependence; taylormap=taylormap)[1] for sub in graph.subgraphs], graph.subgraph_factors) - return taylormap[graph.id], taylormap + to_coeff_map[graph.id] = graph.factor * apply(graph.operator, [taylorexpansion!(sub, var_dependence; to_coeff_map=to_coeff_map, from_coeff_map=from_coeff_map)[1] for sub in graph.subgraphs], graph.subgraph_factors) + return to_coeff_map[graph.id], to_coeff_map, from_coeff_map end end """ - function taylorexpansion!(graph::Diagram{W}, var_dependence::Dict{Int,Vector{Bool}}=Dict{Int,Vector{Bool}}(); taylormap::Dict{Int,TaylorSeries{G}}=Dict{Int,TaylorSeries{G}}()) where {W} + function taylorexpansion!(graph::Diagram{W}, var_dependence::Dict{Int,Vector{Bool}}=Dict{Int,Vector{Bool}}(); to_coeff_map::Dict{Int,TaylorSeries{G}}=Dict{Int,TaylorSeries{G}}()) where {W} Return a taylor series of Diagram g, together with a map of between nodes of g and correponding taylor series. # Arguments: - `graph` Target diagram - `var_dependence::Dict{Int,Vector{Bool}}` A dictionary that specifies the variable dependence of target diagram leaves. Should map the id of each leaf to a Bool vector. The length of the vector should be the same as number of variables. -- `taylormap::Dict{Int,TaylorSeries}` A dicitonary that maps id of each node of target diagram to its correponding taylor series. +- `to_coeff_map::Dict{Int,TaylorSeries}` A dicitonary that maps id of each node of target diagram to its correponding taylor series. """ -function taylorexpansion!(graph::Diagram{W}, var_dependence::Dict{Int,Vector{Bool}}=Dict{Int,Vector{Bool}}(); taylormap::Dict{Int,TaylorSeries{Graph{W,W}}}=Dict{Int,TaylorSeries{Graph{W,W}}}()) where {W} - if haskey(taylormap, graph.hash) #If already exist, use taylor series in taylormap. - return taylormap[graph.hash], taylormap +function taylorexpansion!(graph::Diagram{W}, var_dependence::Dict{Int,Vector{Bool}}=Dict{Int,Vector{Bool}}(); to_coeff_map::Dict{Int,TaylorSeries{Graph{W,W}}}=Dict{Int,TaylorSeries{Graph{W,W}}}()) where {W} + if haskey(to_coeff_map, graph.hash) #If already exist, use taylor series in to_coeff_map. + return to_coeff_map[graph.hash], to_coeff_map elseif isempty(graph.subdiagram) if haskey(var_dependence, graph.hash) @@ -119,16 +130,16 @@ function taylorexpansion!(graph::Diagram{W}, var_dependence::Dict{Int,Vector{Boo coeff = Graph([]; operator=ComputationalGraphs.Sum(), factor=graph.factor) result.coeffs[o] = coeff end - taylormap[graph.hash] = result - return result, taylormap + to_coeff_map[graph.hash] = result + return result, to_coeff_map else - taylormap[graph.hash] = graph.factor * apply(typeof(graph.operator), [taylorexpansion!(sub, var_dependence; taylormap=taylormap)[1] for sub in graph.subdiagram], ones(W, length(graph.subdiagram))) - return taylormap[graph.hash], taylormap + to_coeff_map[graph.hash] = graph.factor * apply(typeof(graph.operator), [taylorexpansion!(sub, var_dependence; to_coeff_map=to_coeff_map)[1] for sub in graph.subdiagram], ones(W, length(graph.subdiagram))) + return to_coeff_map[graph.hash], to_coeff_map end end """ - function taylorexpansion!(graph::FeynmanGraph{F,W}, propagator_var::Tuple{Vector{Bool},Vector{Bool}}, label::Tuple{LabelProduct,LabelProduct}; taylormap::Dict{Int,TaylorSeries{Graph{F,W}}}=Dict{Int,TaylorSeries{Graph{F,W}}}()) where {F,W} + function taylorexpansion!(graph::FeynmanGraph{F,W}, propagator_var::Tuple{Vector{Bool},Vector{Bool}}, label::Tuple{LabelProduct,LabelProduct}; to_coeff_map::Dict{Int,TaylorSeries{Graph{F,W}}}=Dict{Int,TaylorSeries{Graph{F,W}}}()) where {F,W} Return a taylor series of FeynmanGraph g, together with a map of between nodes of g and correponding taylor series. In this set up, the leaves that are the same type of propagators (fermi or bose) depend on the same set of variables, whereas other types of Feynman diagrams (such as vertices) depends on no variables that need to be differentiated (for AD purpose, they are just constants). @@ -137,9 +148,9 @@ end - `propagator_var::Tuple{Vector{Bool},Vector{Bool}}` A Tuple that specifies the variable dependence of fermi (first element) and bose propagator (second element). The dependence is given by a vector of the length same as the number of variables. - `label::Tuple{LabelProduct,LabelProduct}` A Tuple fermi (first element) and bose LabelProduct (second element). -- `taylormap::Dict{Int,TaylorSeries}` A dicitonary that maps id of each node of target diagram to its correponding taylor series. +- `to_coeff_map::Dict{Int,TaylorSeries}` A dicitonary that maps id of each node of target diagram to its correponding taylor series. """ -function taylorexpansion!(graph::FeynmanGraph{F,W}, propagator_var::Tuple{Vector{Bool},Vector{Bool}}; taylormap::Dict{Int,TaylorSeries{Graph{F,W}}}=Dict{Int,TaylorSeries{Graph{F,W}}}()) where {F,W} +function taylorexpansion!(graph::FeynmanGraph{F,W}, propagator_var::Tuple{Vector{Bool},Vector{Bool}}; to_coeff_map::Dict{Int,TaylorSeries{Graph{F,W}}}=Dict{Int,TaylorSeries{Graph{F,W}}}(), from_coeff_map::Dict{Int,Tuple{Int,Vector{Int}}}=Dict{Int,Tuple{Int,Vector{Int}}}()) where {F,W} var_dependence = Dict{Int,Vector{Bool}}() for leaf in Leaves(graph) if ComputationalGraphs.diagram_type(leaf) == ComputationalGraphs.Propagator @@ -153,11 +164,11 @@ function taylorexpansion!(graph::FeynmanGraph{F,W}, propagator_var::Tuple{Vector end end end - return taylorexpansion!(graph, var_dependence; taylormap=taylormap) + return taylorexpansion!(graph, var_dependence; to_coeff_map=to_coeff_map, from_coeff_map=from_coeff_map) end """ - function taylorexpansion!(graph::Diagram{W}, propagator_var::Dict{DataType,Vector{Bool}}; taylormap::Dict{Int,TaylorSeries{Graph{W,W}}}=Dict{Int,TaylorSeries{Graph{W,W}}}()) where {W} + function taylorexpansion!(graph::Diagram{W}, propagator_var::Dict{DataType,Vector{Bool}}; to_coeff_map::Dict{Int,TaylorSeries{Graph{W,W}}}=Dict{Int,TaylorSeries{Graph{W,W}}}()) where {W} Return a taylor series of Diagram g, together with a map of between nodes of g and correponding taylor series. In this set up, the leaves that are the same type of diagrams (such as Green functions) depend on the same set of variables. @@ -165,34 +176,34 @@ end - `graph` Target Diagram - `propagator_var::Dict{DataType,Vector{Bool}}` A dictionary that specifies the variable dependence of different types of diagrams. Should be a map between DataTypes in DiagramID and Bool vectors. The dependence is given by a vector of the length same as the number of variables. -- `taylormap::Dict{Int,TaylorSeries}` A dicitonary that maps id of each node of target diagram to its correponding taylor series. +- `to_coeff_map::Dict{Int,TaylorSeries}` A dicitonary that maps id of each node of target diagram to its correponding taylor series. """ -function taylorexpansion!(graph::Diagram{W}, propagator_var::Dict{DataType,Vector{Bool}}; taylormap::Dict{Int,TaylorSeries{Graph{W,W}}}=Dict{Int,TaylorSeries{Graph{W,W}}}()) where {W} +function taylorexpansion!(graph::Diagram{W}, propagator_var::Dict{DataType,Vector{Bool}}; to_coeff_map::Dict{Int,TaylorSeries{Graph{W,W}}}=Dict{Int,TaylorSeries{Graph{W,W}}}()) where {W} var_dependence = Dict{Int,Vector{Bool}}() for leaf in Leaves(graph) if haskey(propagator_var, typeof(leaf.id)) var_dependence[leaf.hash] = [propagator_var[typeof(leaf.id)][idx] ? true : false for idx in 1:get_numvars()] end end - return taylorexpansion!(graph, var_dependence; taylormap=taylormap) + return taylorexpansion!(graph, var_dependence; to_coeff_map=to_coeff_map) end -function taylorexpansion!(graphs::Vector{G}, var_dependence::Dict{Int,Vector{Bool}}=Dict{Int,Vector{Bool}}(); taylormap::Dict{Int,TaylorSeries{G}}=Dict{Int,TaylorSeries{G}}()) where {G<:Graph} +function taylorexpansion!(graphs::Vector{G}, var_dependence::Dict{Int,Vector{Bool}}=Dict{Int,Vector{Bool}}(); to_coeff_map::Dict{Int,TaylorSeries{G}}=Dict{Int,TaylorSeries{G}}()) where {G<:Graph} result = Vector{TaylorSeries{G}}() for graph in graphs - taylor, _ = taylorexpansion!(graph, var_dependence; taylormap=taylormap) + taylor, _ = taylorexpansion!(graph, var_dependence; to_coeff_map=to_coeff_map) push!(result, taylor) end - return result, taylormap + return result, to_coeff_map end -function taylorexpansion!(graphs::Vector{Diagram{W}}, propagator_var::Dict{DataType,Vector{Bool}}; taylormap::Dict{Int,TaylorSeries{Graph{W,W}}}=Dict{Int,TaylorSeries{Graph{W,W}}}()) where {W} +function taylorexpansion!(graphs::Vector{Diagram{W}}, propagator_var::Dict{DataType,Vector{Bool}}; to_coeff_map::Dict{Int,TaylorSeries{Graph{W,W}}}=Dict{Int,TaylorSeries{Graph{W,W}}}()) where {W} result = Vector{TaylorSeries{Graph{W,W}}}() for graph in graphs - taylor, _ = taylorexpansion!(graph, propagator_var; taylormap=taylormap) + taylor, _ = taylorexpansion!(graph, propagator_var; to_coeff_map=to_coeff_map) push!(result, taylor) end - return result, taylormap + return result, to_coeff_map end """ taylorexpansion_withmap(g::G; coeffmode=true, var::Vector{Int}=collect(1:get_numvars())) where {G<:Graph} From 6b959a5a6de0b95350a4a7246aa543eb1cc0cf84 Mon Sep 17 00:00:00 2001 From: Tao Wang Date: Fri, 17 Nov 2023 20:58:29 -0500 Subject: [PATCH 3/3] add from_coeff_map and test --- example/taylor_expansion.jl | 10 +++++-- src/utility.jl | 60 ++++++++++++++++++++++++++----------- test/taylor.jl | 27 ++++++++++++++--- 3 files changed, 72 insertions(+), 25 deletions(-) diff --git a/example/taylor_expansion.jl b/example/taylor_expansion.jl index 4a0aa067..72c6028e 100644 --- a/example/taylor_expansion.jl +++ b/example/taylor_expansion.jl @@ -6,18 +6,22 @@ using FeynmanDiagram.Utility: taylorexpansion!, build_derivative_backAD!, count_operation function benchmark_AD(glist::Vector{T}) where {T<:Graph} - taylormap = Dict{Int,TaylorSeries{T}}() + #taylormap = Dict{Int,TaylorSeries{T}}() totaloperation = [0, 0] taylorlist = Vector{TaylorSeries{T}}() for g in glist - @time t, taylormap = taylorexpansion!(g; taylormap=taylormap) + var_dependence = Dict{Int,Vector{Bool}}() + for leaf in FeynmanDiagram.Leaves(g) + var_dependence[leaf.id] = [true for _ in 1:get_numvars()] + end + @time t, taylormap, from_coeff_map = taylorexpansion!(g, var_dependence) operation = count_operation(t) totaloperation = totaloperation + operation push!(taylorlist, t) print("operation number: $(operation)\n") - t_compare = build_derivative_backAD!(g) + t_compare, leaftaylor = build_derivative_backAD!(g) for (order, coeff) in (t_compare.coeffs) @assert (eval!(coeff)) == (eval!(Taylor.taylor_factorial(order) * t.coeffs[order])) end diff --git a/src/utility.jl b/src/utility.jl index f399af7d..886f519a 100644 --- a/src/utility.jl +++ b/src/utility.jl @@ -27,10 +27,20 @@ using ..Taylor - `var_dependence::Dict{Int,Vector{Bool}}` A dictionary that specifies the variable dependence of target graph leaves. Should map the id of each leaf to a Bool vector. The length of the vector should be the same as number of variables. - `to_coeff_map::Dict{Int,TaylorSeries}` A dicitonary that maps id of each node of target graph to its correponding taylor series. +`from_coeff_map::Dict{Int,Tuple{Int,Vector{Bool}}}` A dicitonary that maps a taylor coefficient to its owner FeynmanGraph. The key should be the id of coefficient graph, and value should be a tuple of (feynmangraph.id, order). """ -function taylorexpansion!(graph::G, var_dependence::Dict{Int,Vector{Bool}}=Dict{Int,Vector{Bool}}(); to_coeff_map::Dict{Int,TaylorSeries{G}}=Dict{Int,TaylorSeries{G}}()) where {G<:Graph} +function taylorexpansion!(graph::G, var_dependence::Dict{Int,Vector{Bool}}=Dict{Int,Vector{Bool}}(); to_coeff_map::Dict{Int,TaylorSeries{G}}=Dict{Int,TaylorSeries{G}}(), from_coeff_map::Dict{Int,Tuple{Int,Vector{Int}}}=Dict{Int,Tuple{Int,Vector{Int}}}()) where {G<:Graph} if haskey(to_coeff_map, graph.id) #If already exist, use taylor series in to_coeff_map. - return to_coeff_map[graph.id], to_coeff_map + if isleaf(graph) + for (order, coeff) in to_coeff_map[graph.id].coeffs + if haskey(from_coeff_map, coeff.id) + @assert from_coeff_map[coeff.id] == (graph.id, order) "The graph g$(graph.id) is mapped to two different leaf taylor series!" + else + from_coeff_map[coeff.id] = (graph.id, order) + end + end + end + return to_coeff_map[graph.id], to_coeff_map, from_coeff_map elseif isleaf(graph) if haskey(var_dependence, graph.id) @@ -48,12 +58,13 @@ function taylorexpansion!(graph::G, var_dependence::Dict{Int,Vector{Bool}}=Dict{ coeff = Graph([]; operator=ComputationalGraphs.Sum(), factor=graph.factor) result.coeffs[o] = coeff end + from_coeff_map[result.coeffs[o].id] = (graph.id, o) end to_coeff_map[graph.id] = result - return result, to_coeff_map + return result, to_coeff_map, from_coeff_map else - to_coeff_map[graph.id] = graph.factor * apply(graph.operator, [taylorexpansion!(sub, var_dependence; to_coeff_map=to_coeff_map)[1] for sub in graph.subgraphs], graph.subgraph_factors) - return to_coeff_map[graph.id], to_coeff_map + to_coeff_map[graph.id] = graph.factor * apply(graph.operator, [taylorexpansion!(sub, var_dependence; to_coeff_map=to_coeff_map, from_coeff_map=from_coeff_map)[1] for sub in graph.subgraphs], graph.subgraph_factors) + return to_coeff_map[graph.id], to_coeff_map, from_coeff_map end end @@ -112,10 +123,20 @@ end - `var_dependence::Dict{Int,Vector{Bool}}` A dictionary that specifies the variable dependence of target diagram leaves. Should map the id of each leaf to a Bool vector. The length of the vector should be the same as number of variables. - `to_coeff_map::Dict{Int,TaylorSeries}` A dicitonary that maps id of each node of target diagram to its correponding taylor series. +`from_coeff_map::Dict{Int,Tuple{Int,Vector{Bool}}}` A dicitonary that maps a taylor coefficient to its owner FeynmanGraph. The key should be the id of coefficient graph, and value should be a tuple of (feynmangraph.id, order). """ -function taylorexpansion!(graph::Diagram{W}, var_dependence::Dict{Int,Vector{Bool}}=Dict{Int,Vector{Bool}}(); to_coeff_map::Dict{Int,TaylorSeries{Graph{W,W}}}=Dict{Int,TaylorSeries{Graph{W,W}}}()) where {W} +function taylorexpansion!(graph::Diagram{W}, var_dependence::Dict{Int,Vector{Bool}}=Dict{Int,Vector{Bool}}(); to_coeff_map::Dict{Int,TaylorSeries{Graph{W,W}}}=Dict{Int,TaylorSeries{Graph{W,W}}}(), from_coeff_map::Dict{Int,Tuple{Int,Vector{Int}}}=Dict{Int,Tuple{Int,Vector{Int}}}()) where {W} if haskey(to_coeff_map, graph.hash) #If already exist, use taylor series in to_coeff_map. - return to_coeff_map[graph.hash], to_coeff_map + if isempty(graph.subdiagram) + for (order, coeff) in to_coeff_map[graph.hash].coeffs + if haskey(from_coeff_map, coeff.id) + @assert from_coeff_map[coeff.id] == (graph.hash, order) "The graph g$(graph.hash) is mapped to two different leaf taylor series!" + else + from_coeff_map[coeff.id] = (graph.hash, order) + end + end + end + return to_coeff_map[graph.hash], to_coeff_map, from_coeff_map elseif isempty(graph.subdiagram) if haskey(var_dependence, graph.hash) @@ -129,12 +150,13 @@ function taylorexpansion!(graph::Diagram{W}, var_dependence::Dict{Int,Vector{Boo o = collect(order) coeff = Graph([]; operator=ComputationalGraphs.Sum(), factor=graph.factor) result.coeffs[o] = coeff + from_coeff_map[coeff.id] = (graph.hash, o) end to_coeff_map[graph.hash] = result - return result, to_coeff_map + return result, to_coeff_map, from_coeff_map else - to_coeff_map[graph.hash] = graph.factor * apply(typeof(graph.operator), [taylorexpansion!(sub, var_dependence; to_coeff_map=to_coeff_map)[1] for sub in graph.subdiagram], ones(W, length(graph.subdiagram))) - return to_coeff_map[graph.hash], to_coeff_map + to_coeff_map[graph.hash] = graph.factor * apply(typeof(graph.operator), [taylorexpansion!(sub, var_dependence; to_coeff_map=to_coeff_map, from_coeff_map=from_coeff_map)[1] for sub in graph.subdiagram], ones(W, length(graph.subdiagram))) + return to_coeff_map[graph.hash], to_coeff_map, from_coeff_map end end @@ -149,6 +171,7 @@ end The dependence is given by a vector of the length same as the number of variables. - `label::Tuple{LabelProduct,LabelProduct}` A Tuple fermi (first element) and bose LabelProduct (second element). - `to_coeff_map::Dict{Int,TaylorSeries}` A dicitonary that maps id of each node of target diagram to its correponding taylor series. +`from_coeff_map::Dict{Int,Tuple{Int,Vector{Bool}}}` A dicitonary that maps a taylor coefficient to its owner FeynmanGraph. The key should be the id of coefficient graph, and value should be a tuple of (feynmangraph.id, order). """ function taylorexpansion!(graph::FeynmanGraph{F,W}, propagator_var::Tuple{Vector{Bool},Vector{Bool}}; to_coeff_map::Dict{Int,TaylorSeries{Graph{F,W}}}=Dict{Int,TaylorSeries{Graph{F,W}}}(), from_coeff_map::Dict{Int,Tuple{Int,Vector{Int}}}=Dict{Int,Tuple{Int,Vector{Int}}}()) where {F,W} var_dependence = Dict{Int,Vector{Bool}}() @@ -177,33 +200,34 @@ end - `propagator_var::Dict{DataType,Vector{Bool}}` A dictionary that specifies the variable dependence of different types of diagrams. Should be a map between DataTypes in DiagramID and Bool vectors. The dependence is given by a vector of the length same as the number of variables. - `to_coeff_map::Dict{Int,TaylorSeries}` A dicitonary that maps id of each node of target diagram to its correponding taylor series. +- `from_coeff_map::Dict{Int,Tuple{Int,Vector{Bool}}}` A dicitonary that maps a taylor coefficient to its owner FeynmanGraph. The key should be the id of coefficient graph, and value should be a tuple of (feynmangraph.id, order). """ -function taylorexpansion!(graph::Diagram{W}, propagator_var::Dict{DataType,Vector{Bool}}; to_coeff_map::Dict{Int,TaylorSeries{Graph{W,W}}}=Dict{Int,TaylorSeries{Graph{W,W}}}()) where {W} +function taylorexpansion!(graph::Diagram{W}, propagator_var::Dict{DataType,Vector{Bool}}; to_coeff_map::Dict{Int,TaylorSeries{Graph{W,W}}}=Dict{Int,TaylorSeries{Graph{W,W}}}(), from_coeff_map::Dict{Int,Tuple{Int,Vector{Int}}}=Dict{Int,Tuple{Int,Vector{Int}}}()) where {W} var_dependence = Dict{Int,Vector{Bool}}() for leaf in Leaves(graph) if haskey(propagator_var, typeof(leaf.id)) var_dependence[leaf.hash] = [propagator_var[typeof(leaf.id)][idx] ? true : false for idx in 1:get_numvars()] end end - return taylorexpansion!(graph, var_dependence; to_coeff_map=to_coeff_map) + return taylorexpansion!(graph, var_dependence; to_coeff_map=to_coeff_map, from_coeff_map=from_coeff_map) end -function taylorexpansion!(graphs::Vector{G}, var_dependence::Dict{Int,Vector{Bool}}=Dict{Int,Vector{Bool}}(); to_coeff_map::Dict{Int,TaylorSeries{G}}=Dict{Int,TaylorSeries{G}}()) where {G<:Graph} +function taylorexpansion!(graphs::Vector{G}, var_dependence::Dict{Int,Vector{Bool}}=Dict{Int,Vector{Bool}}(); to_coeff_map::Dict{Int,TaylorSeries{G}}=Dict{Int,TaylorSeries{G}}(), from_coeff_map::Dict{Int,Tuple{Int,Vector{Int}}}=Dict{Int,Tuple{Int,Vector{Int}}}()) where {G<:Graph} result = Vector{TaylorSeries{G}}() for graph in graphs - taylor, _ = taylorexpansion!(graph, var_dependence; to_coeff_map=to_coeff_map) + taylor, _ = taylorexpansion!(graph, var_dependence; to_coeff_map=to_coeff_map, from_coeff_map=from_coeff_map) push!(result, taylor) end - return result, to_coeff_map + return result, to_coeff_map, from_coeff_map end -function taylorexpansion!(graphs::Vector{Diagram{W}}, propagator_var::Dict{DataType,Vector{Bool}}; to_coeff_map::Dict{Int,TaylorSeries{Graph{W,W}}}=Dict{Int,TaylorSeries{Graph{W,W}}}()) where {W} +function taylorexpansion!(graphs::Vector{Diagram{W}}, propagator_var::Dict{DataType,Vector{Bool}}; to_coeff_map::Dict{Int,TaylorSeries{Graph{W,W}}}=Dict{Int,TaylorSeries{Graph{W,W}}}(), from_coeff_map::Dict{Int,Tuple{Int,Vector{Int}}}=Dict{Int,Tuple{Int,Vector{Int}}}()) where {W} result = Vector{TaylorSeries{Graph{W,W}}}() for graph in graphs - taylor, _ = taylorexpansion!(graph, propagator_var; to_coeff_map=to_coeff_map) + taylor, _ = taylorexpansion!(graph, propagator_var; to_coeff_map=to_coeff_map, from_coeff_map=from_coeff_map) push!(result, taylor) end - return result, to_coeff_map + return result, to_coeff_map, from_coeff_map end """ taylorexpansion_withmap(g::G; coeffmode=true, var::Vector{Int}=collect(1:get_numvars())) where {G<:Graph} diff --git a/test/taylor.jl b/test/taylor.jl index 6320e62b..acbd6eda 100644 --- a/test/taylor.jl +++ b/test/taylor.jl @@ -62,7 +62,13 @@ end var_dependence[leaf.id] = [true for _ in 1:get_numvars()] end end - T, taylormap = taylorexpansion!(G, var_dependence) + T, taylormap, from_coeff_map = taylorexpansion!(G, var_dependence) + for leaf in Leaves(G) + t = taylormap[leaf.id] + for (order, coeff) in t.coeffs + @test from_coeff_map[coeff.id] == (leaf.id, order) + end + end T_compare, taylormap_compare = build_derivative_backAD!(G) leafmap1, leafvec1, leafmap2, leafvec2 = assign_random_numbers(G, taylormap, taylormap_compare) for (order, coeff) in T_compare.coeffs @@ -82,8 +88,13 @@ end set_variables("x y", orders=[2, 2]) propagator_var = ([true, false], [false, true]) # Specify variable dependence of fermi (first element) and bose (second element) particles. - t, taylormap = taylorexpansion!(g[1][1], propagator_var) - + t, taylormap, from_coeff_map = taylorexpansion!(g[1][1], propagator_var) + for leaf in Leaves(g[1][1]) + taylor = taylormap[leaf.id] + for (order, coeff) in taylor.coeffs + @test from_coeff_map[coeff.id] == (leaf.id, order) + end + end for (order, graph) in dict_g if graph[2][1] == g[2][1] idx = 1 @@ -206,7 +217,15 @@ end set_variables("x y"; orders=[2, 2]) propagator_var = Dict(DiagTree.BareGreenId => [true, false], DiagTree.BareInteractionId => [false, true]) # Specify variable dependence of fermi (first element) and bose (second element) particles. - t, taylormap = taylorexpansion!(root, propagator_var) + t, taylormap, from_coeff_map = taylorexpansion!(root, propagator_var) + for leaf in PostOrderDFS(root) + if isempty(leaf.subdiagram) + taylor = taylormap[leaf.hash] + for (order, coeff) in taylor.coeffs + @test from_coeff_map[coeff.id] == (leaf.hash, order) + end + end + end taylorleafmap, taylorleafvec = assign_leaves(root, taylormap) @test eval!(t.coeffs[[0, 0]], taylorleafmap, taylorleafvec) ≈ root.weight @test eval!(t.coeffs[[0, 1]], taylorleafmap, taylorleafvec) ≈ droot_dv.weight / taylor_factorial([0, 1])