Skip to content

Commit

Permalink
Merge pull request #168 from numericalEFT/computgraph_daniel
Browse files Browse the repository at this point in the history
Add transformation/optimization to remove zero-valued subgraphs
  • Loading branch information
dcerkoney authored Dec 22, 2023
2 parents 7485eab + ad2b25d commit aac010c
Show file tree
Hide file tree
Showing 8 changed files with 279 additions and 75 deletions.
2 changes: 1 addition & 1 deletion src/FeynmanDiagram.jl
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@ export multi_product, linear_combination, feynman_diagram, propagator, interacti
# export reducibility, connectivity
# export 𝐺ᶠ, 𝐺ᵇ, 𝐺ᵠ, 𝑊, Green2, Interaction
# export Coupling_yukawa, Coupling_phi3, Coupling_phi4, Coupling_phi6
export haschildren, onechild, isleaf, isbranch, ischain, isfactorless, eldest
export haschildren, onechild, isleaf, isbranch, ischain, isfactorless, has_zero_subfactors, eldest
export relabel!, standardize_labels!, replace_subgraph!, merge_linear_combination!, merge_multi_product!, merge_chains!
export relabel, standardize_labels, replace_subgraph, merge_linear_combination, merge_multi_product, merge_chains

Expand Down
149 changes: 84 additions & 65 deletions src/backend/to_dot.jl

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion src/computational_graph/ComputationalGraph.jl
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ export multi_product, linear_combination, feynman_diagram, propagator, interacti


include("tree_properties.jl")
export haschildren, onechild, isleaf, isbranch, ischain, isfactorless, eldest, count_operation
export haschildren, onechild, isleaf, isbranch, ischain, isfactorless, has_zero_subfactors, eldest, count_operation

include("operation.jl")
include("io.jl")
Expand Down
10 changes: 10 additions & 0 deletions src/computational_graph/abstractgraph.jl
Original file line number Diff line number Diff line change
Expand Up @@ -254,6 +254,16 @@ function set_subgraph_factors!(g::AbstractGraph, subgraph_factors::AbstractVecto
end
end

"""
function disconnect_subgraphs!(g::G) where {G<:AbstractGraph}
Empty the subgraphs and subgraph_factors of graph `g`. Any child nodes of g
not referenced elsewhere in the full computational graph are effectively deleted.
"""
function disconnect_subgraphs!(g::AbstractGraph)
empty!(subgraphs(g))
empty!(subgraph_factors(g))
end

### Methods ###

Expand Down
59 changes: 53 additions & 6 deletions src/computational_graph/optimize.jl
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ function optimize!(graphs::Union{Tuple,AbstractVector{<:AbstractGraph}}; verbose
remove_duplicated_leaves!(graphs, verbose=verbose, normalize=normalize)
flatten_all_chains!(graphs, verbose=verbose)
merge_all_linear_combinations!(graphs, verbose=verbose)

remove_all_zero_valued_subgraphs!(graphs, verbose=verbose)
return graphs
end
end
Expand Down Expand Up @@ -65,7 +65,7 @@ end
"""
function flatten_all_chains!(graphs::Union{Tuple,AbstractVector{<:AbstractGraph}}; verbose=0)
Flattens all nodes representing trivial unary chains in-place in given graphs.
Flattens all nodes representing trivial unary chains in-place in the given graphs.
# Arguments:
- `graphs`: A collection of graphs to be processed.
Expand All @@ -84,10 +84,57 @@ function flatten_all_chains!(graphs::Union{Tuple,AbstractVector{<:AbstractGraph}
return graphs
end

"""
function remove_all_zero_valued_subgraphs!(g::AbstractGraph; verbose=0)
Recursively removes all zero-valued subgraph(s) in-place in the given graph `g`.
# Arguments:
- `g`: An AbstractGraph.
- `verbose`: Level of verbosity (default: 0).
# Returns:
- Optimized graph.
#
"""
function remove_all_zero_valued_subgraphs!(g::AbstractGraph; verbose=0)
verbose > 0 && println("merge nodes representing a linear combination of a non-unique list of graphs.")
# Post-order DFS
for sub_g in subgraphs(g)
remove_all_zero_valued_subgraphs!(sub_g)
remove_zero_valued_subgraphs!(sub_g)
end
remove_zero_valued_subgraphs!(g)
return g
end

"""
function remove_all_zero_valued_subgraphs!(graphs::Union{Tuple,AbstractVector{<:AbstractGraph}}; verbose=0)
Recursively removes all zero-valued subgraph(s) in-place in the given graphs.
# Arguments:
- `graphs`: A collection of graphs to be processed.
- `verbose`: Level of verbosity (default: 0).
# Returns:
- Optimized graphs.
#
"""
function remove_all_zero_valued_subgraphs!(graphs::Union{Tuple,AbstractVector{<:AbstractGraph}}; verbose=0)
verbose > 0 && println("merge nodes representing a linear combination of a non-unique list of graphs.")
# Post-order DFS
for g in graphs
remove_all_zero_valued_subgraphs!(subgraphs(g))
remove_zero_valued_subgraphs!(g)
end
return graphs
end

"""
function merge_all_linear_combinations!(g::AbstractGraph; verbose=0)
Merges all nodes representing a linear combination of a non-unique list of subgraphs in-place within a single graph.
Merges all nodes representing a linear combination of a non-unique list of subgraphs in-place in the given graph `g`.
# Arguments:
- `g`: An AbstractGraph.
Expand All @@ -111,7 +158,7 @@ end
"""
function merge_all_linear_combinations!(graphs::Union{Tuple,AbstractVector{<:AbstractGraph}}; verbose=0)
Merges all nodes representing a linear combination of a non-unique list of subgraphs in-place in given graphs.
Merges all nodes representing a linear combination of a non-unique list of subgraphs in-place in the given graphs.
# Arguments:
- `graphs`: A collection of graphs to be processed.
Expand All @@ -134,7 +181,7 @@ end
"""
function merge_all_multi_products!(g::Graph; verbose=0)
Merges all nodes representing a multi product of a non-unique list of subgraphs in-place within a single graph.
Merges all nodes representing a multi product of a non-unique list of subgraphs in-place in the given graph `g`.
# Arguments:
- `g::Graph`: A Graph.
Expand All @@ -158,7 +205,7 @@ end
"""
function merge_all_multi_products!(graphs::Union{Tuple,AbstractVector{<:Graph}}; verbose=0)
Merges all nodes representing a multi product of a non-unique list of subgraphs in-place in given graphs.
Merges all nodes representing a multi product of a non-unique list of subgraphs in-place in the given graphs.
# Arguments:
- `graphs`: A collection of graphs to be processed.
Expand Down
46 changes: 44 additions & 2 deletions src/computational_graph/transform.jl
Original file line number Diff line number Diff line change
Expand Up @@ -183,15 +183,57 @@ end
function flatten_chains(g::AbstractGraph)
Recursively flattens chains of subgraphs within a given graph `g` by merging certain trivial unary subgraphs into their parent graphs,
This function returns a new graph with flatten chains, dervied from the input graph `g` remaining unchanged.
This function returns a new graph with flatten chains, derived from the input graph `g` remaining unchanged.
# Arguments:
- `g::AbstractGraph`: graph to be modified
"""
flatten_chains(g::AbstractGraph) = flatten_chains!(deepcopy(g))

"""
function merge_linear_combination(g::AbstractGraph)
function remove_zero_valued_subgraphs!(g::AbstractGraph)
Removes zero-valued (zero subgraph_factor) subgraph(s) of a computational graph `g`. If all subgraphs are zero-valued, the first one (`eldest(g)`) will be retained.
# Arguments:
- `g::AbstractGraph`: graph to be modified
"""
function remove_zero_valued_subgraphs!(g::AbstractGraph)
if isleaf(g) || isbranch(g) # we must retain at least one subgraph
return g
end
subg = collect(subgraphs(g))
subg_fac = collect(subgraph_factors(g))
zero_sgf = zero(subg_fac[1]) # F(0)
# Find subgraphs with all-zero subgraph_factors and propagate subfactor one level up
for (i, sub_g) in enumerate(subg)
if has_zero_subfactors(sub_g)
subg_fac[i] = zero_sgf
end
end
# Remove marked zero subgraph factor subgraph(s) of g
mask_zeros = findall(x -> x != zero(x), subg_fac)
if isempty(mask_zeros)
mask_zeros = [1] # retain eldest(g) if all subfactors are zero
end
set_subgraphs!(g, subg[mask_zeros])
set_subgraph_factors!(g, subg_fac[mask_zeros])
return g
end

"""
function remove_zero_valued_subgraphs(g::AbstractGraph)
Returns a copy of graph `g` with zero-valued (zero subgraph_factor) subgraph(s) removed.
If all subgraphs are zero-valued, the first one (`eldest(g)`) will be retained.
# Arguments:
- `g::AbstractGraph`: graph to be modified
"""
remove_zero_valued_subgraphs(g::AbstractGraph) = remove_zero_valued_subgraphs!(deepcopy(g))

"""
function merge_linear_combination!(g::AbstractGraph)
Modifies a computational graph `g` by factorizing multiplicative prefactors, e.g.,
3*g1 + 5*g2 + 7*g1 + 9*g2 ↦ 10*g1 + 14*g2 = linear_combination(g1, g2, 10, 14).
Expand Down
19 changes: 19 additions & 0 deletions src/computational_graph/tree_properties.jl
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,25 @@ function isfactorless(g::AbstractGraph)
end
end

"""
function has_zero_subfactors(g)
Returns whether the graph g has only zero-valued subgraph factor(s).
Note that this function does not recurse through subgraphs of g, so that one may have, e.g.,
`isfactorless(g) == true` but `isfactorless(eldest(g)) == false`.
By convention, returns `false` if g is a leaf.
# Arguments:
- `g::AbstractGraph`: graph to be analyzed
"""
function has_zero_subfactors(g::AbstractGraph)
if isleaf(g)
return false # convention: subgraph_factors = [] ⟹ subfactorless = false
else
return iszero(subgraph_factors(g))
end
end

"""
function eldest(g::AbstractGraph)
Expand Down
67 changes: 67 additions & 0 deletions test/computational_graph.jl
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,12 @@ Graphs.unary_istrivial(::Type{O}) where {O<:Union{O1,O2,O3}} = true
Graphs.set_subgraph_factors!(g, [5.0, 2.0, 3.0], [3, 1, 2]) # default method
@test Graphs.subgraph_factors(g) == [2.0, 3.0, 5.0]
end
@testset "Disconnect subgraphs" begin
g_dc = deepcopy(g)
Graphs.disconnect_subgraphs!(g_dc)
@test isempty(Graphs.subgraphs(g_dc))
@test isempty(Graphs.subgraph_factors(g_dc))
end
@testset "Equivalence" begin
Graphs.set_name!(g, Graphs.name(gp))
@test g == g
Expand Down Expand Up @@ -302,6 +308,32 @@ end
@test r2 == Graphs.flatten_chains(rvec[2])
@test r3 == Graphs.flatten_chains(rvec[3])
end
@testset "Remove zero-valued subgraphs" begin
# leaves
l1 = Graph([]; factor=1)
l2 = Graph([]; factor=2)
l3 = Graph([]; factor=3)
l4 = Graph([]; factor=4)
l5 = Graph([]; factor=5)
l6 = Graph([]; factor=6)
l7 = Graph([]; factor=7)
l8 = Graph([]; factor=8)
# subgraphs
sg1 = l1
sg2 = Graph([l2, l3]; subgraph_factors=[1.0, 0.0], operator=O1())
sg3 = Graph([l4]; subgraph_factors=[0], operator=O2())
sg4 = Graph([l5, l6, l7]; subgraph_factors=[0, 0, 0], operator=O3())
sg5 = l8
# graphs
g = Graph([sg1, sg2, sg3, sg4, sg5]; subgraph_factors=[1, 1, 1, 1, 0], operator=O())
g_test = Graph([sg1, sg2]; subgraph_factors=[1, 1], operator=O())
gp = Graph([sg3, sg4, sg5]; subgraph_factors=[1, 1, 0], operator=O())
gp_test = Graph([sg3]; subgraph_factors=[0], operator=O())
Graphs.remove_zero_valued_subgraphs!(g)
Graphs.remove_zero_valued_subgraphs!(gp)
@test isequiv(g, g_test, :id)
@test isequiv(gp, gp_test, :id)
end
end
@testset verbose = true "Optimizations" begin
@testset "Flatten all chains" begin
Expand Down Expand Up @@ -330,6 +362,35 @@ end
Graphs.flatten_all_chains!(rvec)
@test rvec == [r1, r2, r3]
end
@testset "Remove all zero-valued subgraphs" begin
# leaves
l1 = Graph([]; factor=1)
l2 = Graph([]; factor=2)
l3 = Graph([]; factor=3)
l4 = Graph([]; factor=4)
l5 = Graph([]; factor=5)
l6 = Graph([]; factor=6)
l7 = Graph([]; factor=7)
l8 = Graph([]; factor=8)
# sub-subgraph
ssg1 = Graph([l7]; subgraph_factors=[0], operator=O())
# subgraphs
sg1 = l1
sg2 = Graph([l2, l3]; subgraph_factors=[1.0, 0.0], operator=O1())
sg2_test = Graph([l2]; subgraph_factors=[1.0], operator=O1())
sg3 = Graph([l4]; subgraph_factors=[0], operator=O2())
sg4 = Graph([l5, l6, ssg1]; subgraph_factors=[0, 0, 1], operator=O3())
sg5 = l8
# graphs
g = Graph([sg1, sg2, sg3, sg4, sg5]; subgraph_factors=[1, 1, 1, 1, 0], operator=O())
g_test = Graph([sg1, sg2_test]; subgraph_factors=[1, 1], operator=O())
gp = Graph([sg3, sg4, sg5]; subgraph_factors=[1, 1, 0], operator=O())
gp_test = Graph([sg3]; subgraph_factors=[0], operator=O())
Graphs.remove_all_zero_valued_subgraphs!(g)
Graphs.remove_all_zero_valued_subgraphs!(gp)
@test isequiv(g, g_test, :id)
@test isequiv(gp, gp_test, :id)
end
@testset "Merge all linear combinations" begin
g1 = Graph([])
g2 = 2 * g1
Expand Down Expand Up @@ -1037,13 +1098,16 @@ end
g3 = 1 * g1
g4 = 1 * g2
g5 = 2 * g1
h1 = 0 * g1
# Chains: Ⓧ --- Ⓧ --- gᵢ (simplified by default)
g6 = Graph([g5,]; subgraph_factors=[1,], operator=Graphs.Prod())
g7 = Graph([g3,]; subgraph_factors=[2,], operator=Graphs.Prod())
# General trees
g8 = 2 * (3 * g1 + 5 * g2)
g9 = g1 + 2 * (3 * g1 + 5 * g2)
g10 = g1 * g2 + g8 * g9
h2 = Graph([g1, g2]; subgraph_factors=[0, 0], operator=Graphs.Sum())
h3 = Graph([g1, g2]; subgraph_factors=[1, 0], operator=Graphs.Sum())
glist = [g1, g2, g8, g9, g10]

@testset "Leaves" begin
Expand All @@ -1068,6 +1132,7 @@ end
@test isfactorless(g4)
@test isfactorless(g5) == false
@test isleaf(eldest(g3))
@test has_zero_subfactors(h1)
end
@testset "Chains" begin
@test haschildren(g6)
Expand All @@ -1090,6 +1155,8 @@ end
@test count_operation(g8) == [1, 0]
@test count_operation(g9) == [2, 0]
@test count_operation(g10) == [4, 2]
@test has_zero_subfactors(h2)
@test has_zero_subfactors(h3) == false
end
@testset "Iteration" begin
count_pre = sum(1 for node in PreOrderDFS(g9))
Expand Down

0 comments on commit aac010c

Please sign in to comment.