From b3f7a26444c2c17c42fd475d8e21b1efc9280e2e Mon Sep 17 00:00:00 2001 From: houpc Date: Tue, 21 Nov 2023 14:58:24 +0800 Subject: [PATCH 1/5] udpate optimize and compile API (WIP) --- src/backend/static.jl | 112 +++++++++++++++------------- src/computational_graph/optimize.jl | 41 ++++++---- src/frontend/GV.jl | 65 ++++++++++++++++ 3 files changed, 150 insertions(+), 68 deletions(-) diff --git a/src/backend/static.jl b/src/backend/static.jl index 37cf4722..27fefde4 100644 --- a/src/backend/static.jl +++ b/src/backend/static.jl @@ -61,47 +61,47 @@ function to_static(::Type{ComputationalGraphs.Power{N}}, subgraphs::Vector{Feynm return "((g$(subgraphs[1].id))^$N$factor_str)" end -""" - function to_julia_str(graphs::AbstractVector{<:AbstractGraph}; root::AbstractVector{Int}=[id(g) for g in graphs], name::String="eval_graph!") - -Compile a list of graphs into a string for a julia static function. The function takes two arguments: `root` and `leaf`. -`root` is a vector of the root node ids of the graphs, and `leaf` is a vector of the leaf nodes' weights of the graphs. -""" -function to_julia_str(graphs::AbstractVector{<:AbstractGraph}; root::AbstractVector{Int}=[id(g) for g in graphs], name::String="eval_graph!") - head = "function $name(root::AbstractVector, leaf::AbstractVector)\n " - body = "" - leafidx = 1 - inds_visitedleaf = Int[] - inds_visitednode = Int[] - for graph in graphs - for g in PostOrderDFS(graph) #leaf first search - g_id = id(g) - target = "g$(g_id)" - isroot = false - if g_id in root - target_root = "root[$(findfirst(x -> x == g_id, root))]" - isroot = true - end - if isempty(subgraphs(g)) #leaf - g_id in inds_visitedleaf && continue - factor_str = factor(g) == 1 ? "" : " * $(factor(g))" - body *= " $target = leaf[$leafidx]$factor_str\n " - leafidx += 1 - push!(inds_visitedleaf, g_id) - else - g_id in inds_visitednode && continue - factor_str = factor(g) == 1 ? "" : " * $(factor(g))" - body *= " $target = $(to_static(operator(g), subgraphs(g), subgraph_factors(g)))$factor_str\n " - push!(inds_visitednode, g_id) - end - if isroot - body *= " $target_root = $target\n " - end - end - end - tail = "end" - return head * body * tail -end +# """ +# function to_julia_str(graphs::AbstractVector{<:AbstractGraph}; root::AbstractVector{Int}=[id(g) for g in graphs], name::String="eval_graph!") + +# Compile a list of graphs into a string for a julia static function. The function takes two arguments: `root` and `leaf`. +# `root` is a vector of the root node ids of the graphs, and `leaf` is a vector of the leaf nodes' weights of the graphs. +# """ +# function to_julia_str(graphs::AbstractVector{<:AbstractGraph}; root::AbstractVector{Int}=[id(g) for g in graphs], name::String="eval_graph!") +# head = "function $name(root::AbstractVector, leaf::AbstractVector)\n " +# body = "" +# leafidx = 1 +# inds_visitedleaf = Int[] +# inds_visitednode = Int[] +# for graph in graphs +# for g in PostOrderDFS(graph) #leaf first search +# g_id = id(g) +# target = "g$(g_id)" +# isroot = false +# if g_id in root +# target_root = "root[$(findfirst(x -> x == g_id, root))]" +# isroot = true +# end +# if isempty(subgraphs(g)) #leaf +# g_id in inds_visitedleaf && continue +# factor_str = factor(g) == 1 ? "" : " * $(factor(g))" +# body *= " $target = leaf[$leafidx]$factor_str\n " +# leafidx += 1 +# push!(inds_visitedleaf, g_id) +# else +# g_id in inds_visitednode && continue +# factor_str = factor(g) == 1 ? "" : " * $(factor(g))" +# body *= " $target = $(to_static(operator(g), subgraphs(g), subgraph_factors(g)))$factor_str\n " +# push!(inds_visitednode, g_id) +# end +# if isroot +# body *= " $target_root = $target\n " +# end +# end +# end +# tail = "end" +# return head * body * tail +# end """ function to_julia_str(graphs::AbstractVector{<:AbstractGraph}, leafMap::Dict{Int,Int}; root::AbstractVector{Int}=[id(g) for g in graphs], @@ -116,12 +116,15 @@ Compile a list of Feynman graphs into a string for a julia static function. The - `root` (AbstractVector{Int}, optional): The vector of the root node ids of the graphs (defaults to `[id(g) for g in graphs]`). - `name` (String,optional): The name of the complied function (defaults to `"eval_graph!"`). """ -function to_julia_str(graphs::AbstractVector{<:AbstractGraph}, leafMap::Dict{Int,Int}; root::AbstractVector{Int}=[id(g) for g in graphs], +function to_julia_str(graphs::AbstractVector{<:AbstractGraph}; root::AbstractVector{Int}=[id(g) for g in graphs], name::String="eval_graph!") head = "function $name(root::AbstractVector, leafVal::AbstractVector)\n " body = "" inds_visitedleaf = Int[] inds_visitednode = Int[] + idx_leafVal = 1 + # map_leafVal2id = Dict{Int,Int}() # mapping from the index of the leafVal to the leaf.id + map_leafid_validx = Dict{Int,Int}() # mapping from the leaf.id to the index of the leafVal for graph in graphs for g in PostOrderDFS(graph) #leaf first search g_id = id(g) @@ -134,7 +137,11 @@ function to_julia_str(graphs::AbstractVector{<:AbstractGraph}, leafMap::Dict{Int if isempty(subgraphs(g)) #leaf g_id in inds_visitedleaf && continue factor_str = factor(g) == 1 ? "" : " * $(factor(g))" - body *= " $target = leafVal[$(leafMap[g_id])]$factor_str\n " + # body *= " $target = leafVal[$(leafMap[g_id])]$factor_str\n " + body *= " $target = leafVal[$idx_leafVal]$factor_str\n " + # map_leafVal2id[idx_leafVal] = g_id + map_leafid_validx[g_id] = idx_leafVal + idx_leafVal += 1 push!(inds_visitedleaf, g_id) else g_id in inds_visitednode && continue @@ -148,7 +155,8 @@ function to_julia_str(graphs::AbstractVector{<:AbstractGraph}, leafMap::Dict{Int end end tail = "end" - return head * body * tail + # return head * body * tail, map_leafVal2id + return head * body * tail, map_leafid_validx end """ @@ -176,15 +184,15 @@ leaf = [1.0, 2.0] function compile(graphs::AbstractVector{<:AbstractGraph}; root::AbstractVector{Int}=[id(g) for g in graphs]) # this function return a runtime generated function defined by compile() - func_string = to_julia_str(graphs; root=root, name="func_name!") + func_string, leafmap = to_julia_str(graphs; root=root, name="func_name!") func_expr = Meta.parse(func_string) return @RuntimeGeneratedFunction(func_expr) end -function compile(graphs::AbstractVector{<:AbstractGraph}, leafMap::Dict{Int,Int}; - root::AbstractVector{Int}=[id(g) for g in graphs]) - # this function return a runtime generated function defined by compile() - func_string = to_julia_str(graphs, leafMap; root=root, name="func_name!") - func_expr = Meta.parse(func_string) - return @RuntimeGeneratedFunction(func_expr) -end \ No newline at end of file +# function compile(graphs::AbstractVector{<:AbstractGraph}, leafMap::Dict{Int,Int}; +# root::AbstractVector{Int}=[id(g) for g in graphs]) +# # this function return a runtime generated function defined by compile() +# func_string = to_julia_str(graphs, leafMap; root=root, name="func_name!") +# func_expr = Meta.parse(func_string) +# return @RuntimeGeneratedFunction(func_expr) +# end \ No newline at end of file diff --git a/src/computational_graph/optimize.jl b/src/computational_graph/optimize.jl index e37b669e..0b9a038d 100644 --- a/src/computational_graph/optimize.jl +++ b/src/computational_graph/optimize.jl @@ -16,10 +16,13 @@ function optimize!(graphs::Union{Tuple,AbstractVector{<:AbstractGraph}}; verbose return nothing else graphs = collect(graphs) - leaf_mapping = remove_duplicated_leaves!(graphs, verbose=verbose, normalize=normalize) + # leaf_mapping = remove_duplicated_leaves!(graphs, verbose=verbose, normalize=normalize) + remove_duplicated_leaves!(graphs, verbose=verbose, normalize=normalize) flatten_all_chains!(graphs, verbose=verbose) merge_all_linear_combinations!(graphs, verbose=verbose) - return leaf_mapping + + return graphs + # return leaf_mapping end end @@ -197,27 +200,30 @@ end function unique_leaves(graphs::AbstractVector{<:AbstractGraph}) ############### find the unique Leaves ##################### unique_graphs = [] - unique_graphs_id = Int[] - mapping = Dict{Int,Int}() + # unique_graphs_id = Int[] + mapping = Dict{Int,eltype{graphs}}() idx = 1 for g in graphs flag = true for (ie, e) in enumerate(unique_graphs) if isequiv(e, g, :id) - mapping[id(g)] = ie + # mapping[id(g)] = ie + mapping[id(g)] = e flag = false break end end if flag push!(unique_graphs, g) - push!(unique_graphs_id, g.id) - mapping[g.id] = idx - idx += 1 + # push!(unique_graphs_id, g.id) + # mapping[g.id] = idx + # idx += 1 + mapping[id(g)] = g end end - return unique_graphs, unique_graphs_id, mapping + # return unique_graphs, unique_graphs_id, mapping + return mapping end """ @@ -248,24 +254,27 @@ function remove_duplicated_leaves!(graphs::Union{Tuple,AbstractVector{<:Abstract sort!(leaves, by=x -> id(x)) #sort the id of the leaves in an asscend order unique!(x -> id(x), leaves) #filter out the leaves with the same id number - _unique_leaves, uniqueleaves_id, mapping = unique_leaves(leaves) + # _unique_leaves, uniqueleaves_id, mapping = unique_leaves(leaves) + mapping = unique_leaves(leaves) verbose > 0 && length(leaves) > 0 && println("Number of independent Leaves $(length(leaves)) → $(length(_unique_leaves))") - leafmap = Dict{Int,Int}() + # leafmap = Dict{Int,Int}() for g in graphs for n in PreOrderDFS(g) for (si, sub_g) in enumerate(subgraphs(n)) if isleaf(sub_g) - set_subgraph!(n, _unique_leaves[mapping[id(sub_g)]], si) - if sub_g.id ∈ uniqueleaves_id - leafmap[sub_g.id] = mapping[sub_g.id] - end + # set_subgraph!(n, _unique_leaves[mapping[id(sub_g)]], si) + set_subgraph!(n, mapping[id(sub_g)], si) + # if sub_g.id ∈ uniqueleaves_id + # leafmap[sub_g.id] = mapping[sub_g.id] + # end end end end end - return leafmap + return graphs + # return leafmap end """ diff --git a/src/frontend/GV.jl b/src/frontend/GV.jl index fbfc3e1b..5b97f0aa 100644 --- a/src/frontend/GV.jl +++ b/src/frontend/GV.jl @@ -275,4 +275,69 @@ function leafstates(FeynGraphs::Dict{T,Tuple{Vector{G},Vector{Vector{Int}}}}, return (leafValue, leafType, leafInTau, leafOutTau, leafLoopIndex), ExtT_index end + +function leafstates(FeynGraphs::Dict{T,Tuple{Vector{G},Vector{Vector{Int}}}}, + labelProd::LabelProduct, leafmap::Dict{Int,Int}, graph_keys::Vector{T}) where {T,G<:FeynmanGraph} + #read information of each leaf from the generated graph and its LabelProduct, the information include type, loop momentum, imaginary time. + num_g = length(graph_keys) + len_leaves = length(values(leafmap)) + + ExtT_index = [Vector{Vector{Int}}() for _ in 1:num_g] + + # leafType = [Vector{Int}() for _ in 1:num_g] + # leafInTau = [Vector{Int}() for _ in 1:num_g] + # leafOutTau = [Vector{Int}() for _ in 1:num_g] + # leafLoopIndex = [Vector{Int}() for _ in 1:num_g] + # leafValue = [Vector{Float64}() for _ in 1:num_g] + + + leafType = zeros(Int, len_leaves) + leafInTau = ones(Int, len_leaves) + leafOutTau = ones(Int, len_leaves) + leafLoopIndex = ones(Int, len_leaves) + leafValue = ones(Float64, len_leaves) + + leaves = Vector{G}() + for (ikey, key) in enumerate(graph_keys) + ExtT_index[ikey] = FeynGraphs[key][2] # external tau variables + for graph in FeynGraphs[key][1] + append!(leaves, collect(Leaves(graph))) + end + end + sort!(leaves, by=x -> x.id) #sort the id of the leaves in an asscend order + unique!(x -> x.id, leaves) #filter out the leaves with the same id number + @assert length(leaves) == len_leaves + + for g in leaves + # g.name == "visited" && continue + vertices = IR.vertices(g) + # if IR.diagram_type(g) == IR.Interaction + # push!(leafType[ikey], 0) + # In = Out = vertices[1][1].label + # push!(leafLoopIndex[ikey], 1) + # push!(leafInTau[ikey], labelProd[In][1]) + # push!(leafOutTau[ikey], labelProd[Out][1]) + # push!(leafValue[ikey], 1.0) + if IR.diagram_type(g) == IR.Propagator + idx = leafmap[g.id] + if (Op.isfermionic(vertices[1])) + In, Out = vertices[2][1].label, vertices[1][1].label + leafType[idx] = g.orders[1] * 2 + 1 + leafLoopIndex[idx] = FrontEnds.linear_to_index(labelProd, In)[end] #the label of LoopPool for each fermionic leaf + leafInTau[idx] = labelProd[In][1] + leafOutTau[idx] = labelProd[Out][1] + else + In, Out = vertices[2][1].label, vertices[1][1].label + push!(leafType[ikey], g.orders[2] * 2 + 2) + push!(leafLoopIndex[ikey], FrontEnds.linear_to_index(labelProd, In)[end]) #the label of LoopPool for each bosonic leaf + push!(leafInTau[ikey], labelProd[In][1]) + push!(leafOutTau[ikey], labelProd[Out][1]) + end + push!(leafValue[ikey], 1.0) + end + # g.name = "visited" + end + return (leafValue, leafType, leafInTau, leafOutTau, leafLoopIndex), ExtT_index +end + end \ No newline at end of file From 55b06e309be77199b3528d91b81ae992d23a312b Mon Sep 17 00:00:00 2001 From: houpc Date: Wed, 22 Nov 2023 23:13:43 +0800 Subject: [PATCH 2/5] update optimize and compiler to produce leafmap --- src/backend/static.jl | 12 +-- src/computational_graph/optimize.jl | 35 ++------ src/frontend/GV.jl | 121 +++++++++++++--------------- 3 files changed, 64 insertions(+), 104 deletions(-) diff --git a/src/backend/static.jl b/src/backend/static.jl index 27fefde4..8a12b2c3 100644 --- a/src/backend/static.jl +++ b/src/backend/static.jl @@ -123,8 +123,7 @@ function to_julia_str(graphs::AbstractVector{<:AbstractGraph}; root::AbstractVec inds_visitedleaf = Int[] inds_visitednode = Int[] idx_leafVal = 1 - # map_leafVal2id = Dict{Int,Int}() # mapping from the index of the leafVal to the leaf.id - map_leafid_validx = Dict{Int,Int}() # mapping from the leaf.id to the index of the leafVal + map_validx_leaf = Dict{Int,eltype(graphs)}() # mapping from the index of the leafVal to the leaf graph for graph in graphs for g in PostOrderDFS(graph) #leaf first search g_id = id(g) @@ -137,10 +136,8 @@ function to_julia_str(graphs::AbstractVector{<:AbstractGraph}; root::AbstractVec if isempty(subgraphs(g)) #leaf g_id in inds_visitedleaf && continue factor_str = factor(g) == 1 ? "" : " * $(factor(g))" - # body *= " $target = leafVal[$(leafMap[g_id])]$factor_str\n " body *= " $target = leafVal[$idx_leafVal]$factor_str\n " - # map_leafVal2id[idx_leafVal] = g_id - map_leafid_validx[g_id] = idx_leafVal + map_validx_leaf[idx_leafVal] = g idx_leafVal += 1 push!(inds_visitedleaf, g_id) else @@ -155,8 +152,7 @@ function to_julia_str(graphs::AbstractVector{<:AbstractGraph}; root::AbstractVec end end tail = "end" - # return head * body * tail, map_leafVal2id - return head * body * tail, map_leafid_validx + return head * body * tail, map_validx_leaf end """ @@ -186,7 +182,7 @@ function compile(graphs::AbstractVector{<:AbstractGraph}; # this function return a runtime generated function defined by compile() func_string, leafmap = to_julia_str(graphs; root=root, name="func_name!") func_expr = Meta.parse(func_string) - return @RuntimeGeneratedFunction(func_expr) + return @RuntimeGeneratedFunction(func_expr), leafmap end # function compile(graphs::AbstractVector{<:AbstractGraph}, leafMap::Dict{Int,Int}; diff --git a/src/computational_graph/optimize.jl b/src/computational_graph/optimize.jl index 0b9a038d..95e7cf39 100644 --- a/src/computational_graph/optimize.jl +++ b/src/computational_graph/optimize.jl @@ -7,22 +7,17 @@ - `graphs`: A tuple or vector of graphs. - `verbose`: Level of verbosity (default: 0). - `normalize`: Optional function to normalize the graphs (default: nothing). - -# Returns: -- A mapping dictionary from the id of each unique leaf node to its index in collect(1:length(leafs)). """ function optimize!(graphs::Union{Tuple,AbstractVector{<:AbstractGraph}}; verbose=0, normalize=nothing) if isempty(graphs) return nothing else graphs = collect(graphs) - # leaf_mapping = remove_duplicated_leaves!(graphs, verbose=verbose, normalize=normalize) remove_duplicated_leaves!(graphs, verbose=verbose, normalize=normalize) flatten_all_chains!(graphs, verbose=verbose) merge_all_linear_combinations!(graphs, verbose=verbose) return graphs - # return leaf_mapping end end @@ -38,12 +33,11 @@ end # Returns: - A tuple/vector of optimized graphs. -- A mapping dictionary from the id of each unique leaf node to its index in collect(1:length(leafs)). """ function optimize(graphs::Union{Tuple,AbstractVector{<:AbstractGraph}}; verbose=0, normalize=nothing) graphs_new = deepcopy(graphs) - leaf_mapping = optimize!(graphs_new, verbose=verbose, normalize=normalize) - return graphs_new, leaf_mapping + optimize!(graphs_new, verbose=verbose, normalize=normalize) + return graphs_new end """ @@ -193,22 +187,17 @@ end - `graphs`: A collection of graphs to be processed. # Returns: -- The vector of unique leaf nodes. -- The vector of unique leaf nodes' index. -- A mapping dictionary from the id of each unique leaf node to its index in collect(1:length(leafs)). +- A mapping dictionary from the id of each leaf to the unique leaf node. """ function unique_leaves(graphs::AbstractVector{<:AbstractGraph}) ############### find the unique Leaves ##################### unique_graphs = [] - # unique_graphs_id = Int[] - mapping = Dict{Int,eltype{graphs}}() + mapping = Dict{Int,eltype(graphs)}() - idx = 1 for g in graphs flag = true - for (ie, e) in enumerate(unique_graphs) + for e in unique_graphs if isequiv(e, g, :id) - # mapping[id(g)] = ie mapping[id(g)] = e flag = false break @@ -216,13 +205,9 @@ function unique_leaves(graphs::AbstractVector{<:AbstractGraph}) end if flag push!(unique_graphs, g) - # push!(unique_graphs_id, g.id) - # mapping[g.id] = idx - # idx += 1 mapping[id(g)] = g end end - # return unique_graphs, unique_graphs_id, mapping return mapping end @@ -235,9 +220,6 @@ end - `graphs`: A collection of graphs to be processed. - `verbose`: Level of verbosity (default: 0). - `normalize`: Optional function to normalize the graphs (default: nothing). - -# Returns: -- A mapping dictionary from the id of each unique leaf node to its index in collect(1:length(leafs)). """ function remove_duplicated_leaves!(graphs::Union{Tuple,AbstractVector{<:AbstractGraph}}; verbose=0, normalize=nothing, kwargs...) verbose > 0 && println("remove duplicated leaves.") @@ -254,27 +236,20 @@ function remove_duplicated_leaves!(graphs::Union{Tuple,AbstractVector{<:Abstract sort!(leaves, by=x -> id(x)) #sort the id of the leaves in an asscend order unique!(x -> id(x), leaves) #filter out the leaves with the same id number - # _unique_leaves, uniqueleaves_id, mapping = unique_leaves(leaves) mapping = unique_leaves(leaves) verbose > 0 && length(leaves) > 0 && println("Number of independent Leaves $(length(leaves)) → $(length(_unique_leaves))") - # leafmap = Dict{Int,Int}() for g in graphs for n in PreOrderDFS(g) for (si, sub_g) in enumerate(subgraphs(n)) if isleaf(sub_g) - # set_subgraph!(n, _unique_leaves[mapping[id(sub_g)]], si) set_subgraph!(n, mapping[id(sub_g)], si) - # if sub_g.id ∈ uniqueleaves_id - # leafmap[sub_g.id] = mapping[sub_g.id] - # end end end end end return graphs - # return leafmap end """ diff --git a/src/frontend/GV.jl b/src/frontend/GV.jl index 5b97f0aa..47412319 100644 --- a/src/frontend/GV.jl +++ b/src/frontend/GV.jl @@ -70,7 +70,6 @@ end Generates a FeynmanGraph Dict: the Feynman diagrams with static interactions in a given `type`, and spin-polarizaition parameter `spinPolarPara`, to given minmimum/maximum orders `MinOrder/MaxOrder`, with switchable couterterms. Generates a `LabelProduct`: `labelProd` for these FeynmanGraphs. - Generates a leafMap for mapping `g.id` to the index of unique leaf. # Arguments: - `type` (Symbol): The type of the Feynman diagrams, including `:spinPolar`, `:chargePolar`, `:sigma_old`, `:green`, or `:freeEnergy`. @@ -84,7 +83,6 @@ A tuple `(dict_graphs, fermi_labelProd, bose_labelProd, leafMap)` where - `dict_graphs` is a `Dict{Tuple{Int,Int,Int},Tuple{Vector{FeynmanGraph},Vector{Vector{Int}}}}` object representing the diagrams. The key is (order, Gorder, Vorder). The element is a Tuple (graphVector, extT_labels). - `labelProd` is a `LabelProduct` object containing the labels for the leaves of graphs, -- `leafMap` maps `g.id` to the index of unique leaf. """ function diagdictGV(type::Symbol, MaxOrder::Int, has_counterterm::Bool=false; MinOrder::Int=1, spinPolarPara::Float64=0.0) @@ -112,7 +110,6 @@ function diagdictGV(type::Symbol, MaxOrder::Int, has_counterterm::Bool=false; # Create label product labelProd = LabelProduct(tau_labels, loopbasis) - leafMap = Dict{Tuple{Int,Int,Int},Dict{Int,Int}}() if has_counterterm Gorders = 0:MaxOrder-MinOrder Vorders = 0:MaxOrder-1 @@ -126,7 +123,7 @@ function diagdictGV(type::Symbol, MaxOrder::Int, has_counterterm::Bool=false; labelProd=labelProd, spinPolarPara=spinPolarPara) key = (order, GOrder, VerOrder) dict_graphs[key] = (gvec, extT_labels) - leafMap[key] = IR.optimize!(gvec) + IR.optimize!(gvec) end end end @@ -136,11 +133,11 @@ function diagdictGV(type::Symbol, MaxOrder::Int, has_counterterm::Bool=false; labelProd=labelProd, spinPolarPara=spinPolarPara) key = (order, 0, 0) dict_graphs[key] = (gvec, extT_labels) - leafMap[key] = IR.optimize!(gvec) + IR.optimize!(gvec) end end - return dict_graphs, labelProd, leafMap + return dict_graphs, labelProd end """ @@ -149,7 +146,6 @@ end Generates a FeynmanGraph Dict: the Feynman diagrams with static interactions in the given `type` and spin-polarizaition parameter `spinPolarPara`, with given couterterm-orders (from `gkeys`). Generates a `LabelProduct`: `labelProd` for these FeynmanGraphs. - Generates a leafMap for mapping `g.id` to the index of unique leaf. # Arguments: - `type` (Symbol): The type of the Feynman diagrams, including `:spinPolar`, `:chargePolar`, `:sigma_old`, `:green`, or `:freeEnergy`. @@ -161,7 +157,6 @@ A tuple `(dict_graphs, fermi_labelProd, bose_labelProd, leafMap)` where - `dict_graphs` is a `Dict{Tuple{Int,Int,Int},Tuple{Vector{FeynmanGraph},Vector{Vector{Int}}}}` object representing the diagrams. The key is (order, Gorder, Vorder). The element is a Tuple (graphVector, extT_labels). - `labelProd` is a `LabelProduct` object containing the labels for the leaves of graphs, -- `leafMap` maps `g.id` to the index of unique leaf. """ function diagdictGV(type::Symbol, gkeys::Vector{Tuple{Int,Int,Int}}; spinPolarPara::Float64=0.0) dict_graphs = Dict{Tuple{Int,Int,Int},Tuple{Vector{FeynmanGraph{_dtype.factor,_dtype.weight}},Vector{Vector{Int}}}}() @@ -190,18 +185,16 @@ function diagdictGV(type::Symbol, gkeys::Vector{Tuple{Int,Int,Int}}; spinPolarPa labelProd = LabelProduct(tau_labels, loopbasis) # graphvector = Vector{_dtype.factor,_dtype.weight}() - leafMap = Dict{eltype(gkeys),Dict{Int,Int}}() for key in gkeys gvec, labelProd, extT_labels = eachorder_diag(type, key...; labelProd=labelProd, spinPolarPara=spinPolarPara) dict_graphs[key] = (gvec, extT_labels) - # loopPool = fermi_labelProd.labels[3] - leafMap[key] = IR.optimize!(gvec) + IR.optimize!(gvec) # append!(graphvector, gvec) end # IR.optimize!(graphvector) - return dict_graphs, labelProd, leafMap + return dict_graphs, labelProd end """ @@ -275,69 +268,65 @@ function leafstates(FeynGraphs::Dict{T,Tuple{Vector{G},Vector{Vector{Int}}}}, return (leafValue, leafType, leafInTau, leafOutTau, leafLoopIndex), ExtT_index end +""" + function leafstates(leaf_maps::Vector{Dict{Int,G}}, labelProd::LabelProduct) where {T,G<:FeynmanGraph} -function leafstates(FeynGraphs::Dict{T,Tuple{Vector{G},Vector{Vector{Int}}}}, - labelProd::LabelProduct, leafmap::Dict{Int,Int}, graph_keys::Vector{T}) where {T,G<:FeynmanGraph} - #read information of each leaf from the generated graph and its LabelProduct, the information include type, loop momentum, imaginary time. - num_g = length(graph_keys) - len_leaves = length(values(leafmap)) - - ExtT_index = [Vector{Vector{Int}}() for _ in 1:num_g] - - # leafType = [Vector{Int}() for _ in 1:num_g] - # leafInTau = [Vector{Int}() for _ in 1:num_g] - # leafOutTau = [Vector{Int}() for _ in 1:num_g] - # leafLoopIndex = [Vector{Int}() for _ in 1:num_g] - # leafValue = [Vector{Float64}() for _ in 1:num_g] + Extracts leaf information from the leaf mapping from the leaf value's index to the leaf node for all graph partitions + and their associated LabelProduct data (`labelProd`). + The information includes their initial value, type, in/out time, and loop momenta. + +# Arguments: +- `leaf_maps`: A vector of the dictionary mapping the leaf value's index to the FeynmanGraph of this leaf. + Each dict corresponds to a graph partition, such as (order, Gorder, Vorder). +- `labelProd`: A LabelProduct used to label the leaves of graphs. +# Returns +- A tuple of vectors containing information about the leaves of graphs, including their initial values, types, input and output time indexes, and loop-momenta indexes. +""" +function leafstates(leaf_maps::Vector{Dict{Int,G}}, labelProd::LabelProduct) where {G<:FeynmanGraph} + #read information of each leaf from the generated graph and its LabelProduct, the information include type, loop momentum, imaginary time. + num_g = length(leaf_maps) + leafType = [Vector{Int}() for _ in 1:num_g] + leafInTau = [Vector{Int}() for _ in 1:num_g] + leafOutTau = [Vector{Int}() for _ in 1:num_g] + leafLoopIndex = [Vector{Int}() for _ in 1:num_g] + leafValue = [Vector{Float64}() for _ in 1:num_g] - leafType = zeros(Int, len_leaves) - leafInTau = ones(Int, len_leaves) - leafOutTau = ones(Int, len_leaves) - leafLoopIndex = ones(Int, len_leaves) - leafValue = ones(Float64, len_leaves) + for (ikey, leafmap) in enumerate(leaf_maps) + len_leaves = length(keys(leafmap)) + sizehint!(leafType[ikey], len_leaves) + sizehint!(leafInTau[ikey], len_leaves) + sizehint!(leafOutTau[ikey], len_leaves) + sizehint!(leafLoopIndex[ikey], len_leaves) + leafValue[ikey] = ones(Float64, len_leaves) - leaves = Vector{G}() - for (ikey, key) in enumerate(graph_keys) - ExtT_index[ikey] = FeynGraphs[key][2] # external tau variables - for graph in FeynGraphs[key][1] - append!(leaves, collect(Leaves(graph))) - end - end - sort!(leaves, by=x -> x.id) #sort the id of the leaves in an asscend order - unique!(x -> x.id, leaves) #filter out the leaves with the same id number - @assert length(leaves) == len_leaves - - for g in leaves - # g.name == "visited" && continue - vertices = IR.vertices(g) - # if IR.diagram_type(g) == IR.Interaction - # push!(leafType[ikey], 0) - # In = Out = vertices[1][1].label - # push!(leafLoopIndex[ikey], 1) - # push!(leafInTau[ikey], labelProd[In][1]) - # push!(leafOutTau[ikey], labelProd[Out][1]) - # push!(leafValue[ikey], 1.0) - if IR.diagram_type(g) == IR.Propagator - idx = leafmap[g.id] - if (Op.isfermionic(vertices[1])) - In, Out = vertices[2][1].label, vertices[1][1].label - leafType[idx] = g.orders[1] * 2 + 1 - leafLoopIndex[idx] = FrontEnds.linear_to_index(labelProd, In)[end] #the label of LoopPool for each fermionic leaf - leafInTau[idx] = labelProd[In][1] - leafOutTau[idx] = labelProd[Out][1] - else - In, Out = vertices[2][1].label, vertices[1][1].label - push!(leafType[ikey], g.orders[2] * 2 + 2) - push!(leafLoopIndex[ikey], FrontEnds.linear_to_index(labelProd, In)[end]) #the label of LoopPool for each bosonic leaf + for idx in 1:len_leaves + g = leafmap[idx] + vertices = IR.vertices(g) + if IR.diagram_type(g) == IR.Interaction + push!(leafType[ikey], 0) + In = Out = vertices[1][1].label + push!(leafLoopIndex[ikey], 1) push!(leafInTau[ikey], labelProd[In][1]) push!(leafOutTau[ikey], labelProd[Out][1]) + elseif IR.diagram_type(g) == IR.Propagator + if (Op.isfermionic(vertices[1])) + In, Out = vertices[2][1].label, vertices[1][1].label + push!(leafType[ikey], g.orders[1] * 2 + 1) + push!(leafLoopIndex[ikey], FrontEnds.linear_to_index(labelProd, In)[end]) #the label of LoopPool for each fermionic leaf + push!(leafInTau[ikey], labelProd[In][1]) + push!(leafOutTau[ikey], labelProd[Out][1]) + else + In, Out = vertices[2][1].label, vertices[1][1].label + push!(leafType[ikey], g.orders[2] * 2 + 2) + push!(leafLoopIndex[ikey], FrontEnds.linear_to_index(labelProd, In)[end]) #the label of LoopPool for each bosonic leaf + push!(leafInTau[ikey], labelProd[In][1]) + push!(leafOutTau[ikey], labelProd[Out][1]) + end end - push!(leafValue[ikey], 1.0) end - # g.name = "visited" end - return (leafValue, leafType, leafInTau, leafOutTau, leafLoopIndex), ExtT_index + return (leafValue, leafType, leafInTau, leafOutTau, leafLoopIndex) end end \ No newline at end of file From e1a738eddd2c054a487fb6076711e8c6ec70a79b Mon Sep 17 00:00:00 2001 From: houpc Date: Sat, 25 Nov 2023 01:00:22 +0800 Subject: [PATCH 3/5] support generating source code in Compilers and update GV --- src/backend/static.jl | 86 +++++++++++----------------- src/frontend/GV.jl | 71 ----------------------- src/frontend/GV_diagrams/readfile.jl | 4 ++ test/compiler.jl | 6 +- test/computational_graph.jl | 18 +++--- test/taylor.jl | 2 +- 6 files changed, 50 insertions(+), 137 deletions(-) diff --git a/src/backend/static.jl b/src/backend/static.jl index 8a12b2c3..96b671a3 100644 --- a/src/backend/static.jl +++ b/src/backend/static.jl @@ -61,48 +61,6 @@ function to_static(::Type{ComputationalGraphs.Power{N}}, subgraphs::Vector{Feynm return "((g$(subgraphs[1].id))^$N$factor_str)" end -# """ -# function to_julia_str(graphs::AbstractVector{<:AbstractGraph}; root::AbstractVector{Int}=[id(g) for g in graphs], name::String="eval_graph!") - -# Compile a list of graphs into a string for a julia static function. The function takes two arguments: `root` and `leaf`. -# `root` is a vector of the root node ids of the graphs, and `leaf` is a vector of the leaf nodes' weights of the graphs. -# """ -# function to_julia_str(graphs::AbstractVector{<:AbstractGraph}; root::AbstractVector{Int}=[id(g) for g in graphs], name::String="eval_graph!") -# head = "function $name(root::AbstractVector, leaf::AbstractVector)\n " -# body = "" -# leafidx = 1 -# inds_visitedleaf = Int[] -# inds_visitednode = Int[] -# for graph in graphs -# for g in PostOrderDFS(graph) #leaf first search -# g_id = id(g) -# target = "g$(g_id)" -# isroot = false -# if g_id in root -# target_root = "root[$(findfirst(x -> x == g_id, root))]" -# isroot = true -# end -# if isempty(subgraphs(g)) #leaf -# g_id in inds_visitedleaf && continue -# factor_str = factor(g) == 1 ? "" : " * $(factor(g))" -# body *= " $target = leaf[$leafidx]$factor_str\n " -# leafidx += 1 -# push!(inds_visitedleaf, g_id) -# else -# g_id in inds_visitednode && continue -# factor_str = factor(g) == 1 ? "" : " * $(factor(g))" -# body *= " $target = $(to_static(operator(g), subgraphs(g), subgraph_factors(g)))$factor_str\n " -# push!(inds_visitednode, g_id) -# end -# if isroot -# body *= " $target_root = $target\n " -# end -# end -# end -# tail = "end" -# return head * body * tail -# end - """ function to_julia_str(graphs::AbstractVector{<:AbstractGraph}, leafMap::Dict{Int,Int}; root::AbstractVector{Int}=[id(g) for g in graphs], name::String="eval_graph!") @@ -112,13 +70,16 @@ Compile a list of Feynman graphs into a string for a julia static function. The # Arguments: - `graphs` (AbstractVector{G}): The vector object representing the Feynman graphs, -- `leafMap (Dict{Int,Int})`: The mapping dictionary from the id of each leaf to the index of the leaf weight's table `leafVal`. - `root` (AbstractVector{Int}, optional): The vector of the root node ids of the graphs (defaults to `[id(g) for g in graphs]`). -- `name` (String,optional): The name of the complied function (defaults to `"eval_graph!"`). +- `name` (String,optional): The name of the complied function (defaults to `"eval_graph!"`). + +# Returns: +- A String representing the compiled Julia function. +- `leafMap (Dict{Int,G})`: A dictionary that maps the index of the leaf weight's table `leafVal` to the leaf graph. """ function to_julia_str(graphs::AbstractVector{<:AbstractGraph}; root::AbstractVector{Int}=[id(g) for g in graphs], name::String="eval_graph!") - head = "function $name(root::AbstractVector, leafVal::AbstractVector)\n " + head = "\nfunction $name(root::AbstractVector, leafVal::AbstractVector)\n " body = "" inds_visitedleaf = Int[] inds_visitednode = Int[] @@ -151,7 +112,8 @@ function to_julia_str(graphs::AbstractVector{<:AbstractGraph}; root::AbstractVec end end end - tail = "end" + # tail = "end\n " + tail = "end " return head * body * tail, map_validx_leaf end @@ -180,15 +142,31 @@ leaf = [1.0, 2.0] function compile(graphs::AbstractVector{<:AbstractGraph}; root::AbstractVector{Int}=[id(g) for g in graphs]) # this function return a runtime generated function defined by compile() - func_string, leafmap = to_julia_str(graphs; root=root, name="func_name!") + func_string, leafmap = to_julia_str(graphs; root=root, name="eval_graph!") func_expr = Meta.parse(func_string) return @RuntimeGeneratedFunction(func_expr), leafmap end -# function compile(graphs::AbstractVector{<:AbstractGraph}, leafMap::Dict{Int,Int}; -# root::AbstractVector{Int}=[id(g) for g in graphs]) -# # this function return a runtime generated function defined by compile() -# func_string = to_julia_str(graphs, leafMap; root=root, name="func_name!") -# func_expr = Meta.parse(func_string) -# return @RuntimeGeneratedFunction(func_expr) -# end \ No newline at end of file +""" + compile_code(graphs::AbstractVector{<:AbstractGraph}, filename::String; root::AbstractVector{Int}=[id(g) for g in graphs], func_name="eval_graph!") -> Dict + + Compiles a set of graphs into Julia code and append the generated code to a file. + +# Arguments +- `graphs::AbstractVector{<:AbstractGraph}`: An array of graph objects. These graphs are processed to generate Julia code. +- `filename::String`: The name of the file to which the generated code will be appended. The file is created if it does not exist. +- `root::AbstractVector{Int}` (keyword): An array of integers representing root nodes for each graph in `graphs`. By default, it is an array of IDs obtained by calling `id(g)` for each graph `g` in `graphs`. +- `func_name::String` (keyword): The base name for the function(s) to be generated. Defaults to `"eval_graph!"`. + +# Returns +- A dictionary (`leafmap`) that maps the index of the leaf weight's table `leafVal` to the leaf graph. +""" +function compile_code(graphs::AbstractVector{<:AbstractGraph}, filename::String; + root::AbstractVector{Int}=[id(g) for g in graphs], func_name="eval_graph!") + # this function return a runtime generated function defined by compile() + func_string, leafmap = to_julia_str(graphs; root=root, name=func_name) + open(filename, "a") do f + write(f, func_string) + end + return leafmap +end diff --git a/src/frontend/GV.jl b/src/frontend/GV.jl index 47412319..51033120 100644 --- a/src/frontend/GV.jl +++ b/src/frontend/GV.jl @@ -197,77 +197,6 @@ function diagdictGV(type::Symbol, gkeys::Vector{Tuple{Int,Int,Int}}; spinPolarPa return dict_graphs, labelProd end -""" - function leafstates(FeynGraphs::Dict{T,Tuple{Vector{G},Vector{Vector{Int}}}}, - labelProd::LabelProduct, graph_keys::Vector{T}) where {T,G<:FeynmanGraph} - - Extracts leaf information from a Dict collection of Feynman graphs (`FeynGraphs` with its keys `graph_keys`) - and their associated LabelProduct data (`labelProd`). - The information includes their initial value, type, in/out time, and loop momenta. - -# Arguments: -- `FeynGraphs`: A dictionary mapping keys of type T to tuples containing a vector of `FeynmanGraph` objects and a vector of external time labels. -- `labelProd`: A LabelProduct used to label the leaves of graphs. -- `graph_keys`: A vector containing keys of type `T`, specifying which graphs to analyze. - -# Returns -- A tuple of vectors containing information about the leaves of graphs, including their initial values, types, input and output time indexes, and loop-momenta indexes. -- A Vector{Vector{Int}} representing the external tau variables of each vector of graph corresponding to each key of type `T`. -""" -function leafstates(FeynGraphs::Dict{T,Tuple{Vector{G},Vector{Vector{Int}}}}, - labelProd::LabelProduct, graph_keys::Vector{T}) where {T,G<:FeynmanGraph} - #read information of each leaf from the generated graph and its LabelProduct, the information include type, loop momentum, imaginary time. - num_g = length(graph_keys) - ExtT_index = [Vector{Vector{Int}}() for _ in 1:num_g] - - leafType = [Vector{Int}() for _ in 1:num_g] - leafInTau = [Vector{Int}() for _ in 1:num_g] - leafOutTau = [Vector{Int}() for _ in 1:num_g] - leafLoopIndex = [Vector{Int}() for _ in 1:num_g] - leafValue = [Vector{Float64}() for _ in 1:num_g] - - for (ikey, key) in enumerate(graph_keys) - ExtT_index[ikey] = FeynGraphs[key][2] # external tau variables - - leaves = Vector{G}() - for graph in FeynGraphs[key][1] - append!(leaves, collect(Leaves(graph))) - end - sort!(leaves, by=x -> x.id) #sort the id of the leaves in an asscend order - unique!(x -> x.id, leaves) #filter out the leaves with the same id number - - for g in leaves - g.name == "visited" && continue - vertices = IR.vertices(g) - if IR.diagram_type(g) == IR.Interaction - push!(leafType[ikey], 0) - In = Out = vertices[1][1].label - push!(leafLoopIndex[ikey], 1) - push!(leafInTau[ikey], labelProd[In][1]) - push!(leafOutTau[ikey], labelProd[Out][1]) - push!(leafValue[ikey], 1.0) - elseif IR.diagram_type(g) == IR.Propagator - if (Op.isfermionic(vertices[1])) - In, Out = vertices[2][1].label, vertices[1][1].label - push!(leafType[ikey], g.orders[1] * 2 + 1) - push!(leafLoopIndex[ikey], FrontEnds.linear_to_index(labelProd, In)[end]) #the label of LoopPool for each fermionic leaf - push!(leafInTau[ikey], labelProd[In][1]) - push!(leafOutTau[ikey], labelProd[Out][1]) - else - In, Out = vertices[2][1].label, vertices[1][1].label - push!(leafType[ikey], g.orders[2] * 2 + 2) - push!(leafLoopIndex[ikey], FrontEnds.linear_to_index(labelProd, In)[end]) #the label of LoopPool for each bosonic leaf - push!(leafInTau[ikey], labelProd[In][1]) - push!(leafOutTau[ikey], labelProd[Out][1]) - end - push!(leafValue[ikey], 1.0) - end - g.name = "visited" - end - end - return (leafValue, leafType, leafInTau, leafOutTau, leafLoopIndex), ExtT_index -end - """ function leafstates(leaf_maps::Vector{Dict{Int,G}}, labelProd::LabelProduct) where {T,G<:FeynmanGraph} diff --git a/src/frontend/GV_diagrams/readfile.jl b/src/frontend/GV_diagrams/readfile.jl index 333dc164..b46dc6b7 100644 --- a/src/frontend/GV_diagrams/readfile.jl +++ b/src/frontend/GV_diagrams/readfile.jl @@ -135,6 +135,10 @@ function read_diagrams(filename::AbstractString; labelProd::Union{Nothing,LabelP gr = _group(diagrams, extT_labels) unique!(extT_labels) graphvec = FeynmanGraph[] + staticextT_idx = findfirst(allequal, extT_labels) + if staticextT_idx > 1 + extT_labels[staticextT_idx], extT_labels[1] = extT_labels[1], extT_labels[staticextT_idx] + end for key in extT_labels push!(graphvec, IR.linear_combination(gr[key], ones(_dtype.factor, length(gr[key])))) end diff --git a/test/compiler.jl b/test/compiler.jl index 1d8da78c..0324208b 100644 --- a/test/compiler.jl +++ b/test/compiler.jl @@ -6,7 +6,7 @@ subgraphs = [external_vertex(V1[1]), external_vertex(V1[2])] g = FeynmanGraph(subgraphs; factor=factor) # println(g) - gs = Compilers.to_julia_str([g,], name="eval_graph!") + gs, leafmap = Compilers.to_julia_str([g,], name="eval_graph!") # println(gs) gexpr = Meta.parse(gs) # parse string to julia expression eval(gexpr) #create the function eval_graph! @@ -22,7 +22,7 @@ subgraphs = [external_vertex(V1[1]), external_vertex(V1[2])] g = FeynmanGraph(subgraphs; factor=factor) # println(g) - eval_graph! = Compilers.compile([g,]) + eval_graph!, leafmap = Compilers.compile([g,]) root = [0.0,] leaf = [1.0, 2.0] @test eval_graph!(root, leaf) ≈ (leaf[1] + leaf[2]) * factor @@ -34,7 +34,7 @@ function graph_compile(g; name="eval_graph!") # the name is not contained inside this function # it can leak out to the global scope if the name is not defined outside - gs = Compilers.to_julia_str([g,], name=name) + gs, leafmap = Compilers.to_julia_str([g,], name=name) gexpr = Meta.parse(gs) # parse string to julia expression eval(gexpr) #create the function eval_graph! return eval_graph! diff --git a/test/computational_graph.jl b/test/computational_graph.jl index c165f24c..bb36652a 100644 --- a/test/computational_graph.jl +++ b/test/computational_graph.jl @@ -379,12 +379,13 @@ end h = Graph([h1, g5]) _h = Graph([Graph([g1, g5], subgraph_factors=[-28, 1]), g5], subgraph_factors=[2, 1]) - hvec_op, leafMap = Graphs.optimize(repeat([deepcopy(h)], 3)) - leaf = rand(2) + hvec_op = Graphs.optimize(repeat([deepcopy(h)], 3)) + # leaf = rand(2) @test all(isequiv(h, _h, :id) for h in hvec_op) - @test Graphs.eval!(hvec_op[1], leafMap, leaf) ≈ Graphs.eval!(h, leafMap, leaf) + # @test Graphs.eval!(hvec_op[1], leafMap, leaf) ≈ Graphs.eval!(h, leafMap, leaf) + @test Graphs.eval!(hvec_op[1]) ≈ Graphs.eval!(h) - leafMap1 = Graphs.optimize!([h]) + Graphs.optimize!([h]) @test isequiv(h, _h, :id, :weight) end end @@ -621,12 +622,13 @@ end h = FeynmanGraph([h1, g5]) _h = FeynmanGraph([FeynmanGraph([g1, g5], subgraph_factors=[-28, 1]), g5], subgraph_factors=[2, 1]) - hvec_op, leafMap = Graphs.optimize(repeat([deepcopy(h)], 3)) - leaf = rand(2) + hvec_op = Graphs.optimize(repeat([deepcopy(h)], 3)) + # leaf = rand(2) @test all(isequiv(h, _h, :id) for h in hvec_op) - @test Graphs.eval!(hvec_op[1], leafMap, leaf) ≈ Graphs.eval!(h, leafMap, leaf) + # @test Graphs.eval!(hvec_op[1], leafMap, leaf) ≈ Graphs.eval!(h, leafMap, leaf) + @test Graphs.eval!(hvec_op[1]) ≈ Graphs.eval!(h) - leafMap1 = Graphs.optimize!([h]) + Graphs.optimize!([h]) @test isequiv(h, _h, :id, :weight) end end diff --git a/test/taylor.jl b/test/taylor.jl index acbd6eda..2afa5149 100644 --- a/test/taylor.jl +++ b/test/taylor.jl @@ -82,7 +82,7 @@ end @testset "Taylor AD of Sigma FeynmanGraph" begin - dict_g, lp, 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)]) + dict_g, lp = 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)]) g = dict_g[(2, 0, 0)] From 7d17f38fffd49b13a44cf53e7b624a93a819f9a1 Mon Sep 17 00:00:00 2001 From: houpc Date: Sat, 25 Nov 2023 01:11:00 +0800 Subject: [PATCH 4/5] remove 1.6 julia test --- .github/workflows/CI.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/CI.yml b/.github/workflows/CI.yml index 19a6d0f3..4817a84e 100644 --- a/.github/workflows/CI.yml +++ b/.github/workflows/CI.yml @@ -10,7 +10,7 @@ jobs: fail-fast: false matrix: version: - - "1.6" + # - "1.6" # - "nightly" - "1.9" os: From 16a84935204d570cbbfaa64917d46f1844519cf6 Mon Sep 17 00:00:00 2001 From: houpc Date: Thu, 30 Nov 2023 00:50:41 +0800 Subject: [PATCH 5/5] support compiler into C source --- src/backend/static.jl | 110 ++++++++++++++++++++++++++++++++++++++---- 1 file changed, 100 insertions(+), 10 deletions(-) diff --git a/src/backend/static.jl b/src/backend/static.jl index 96b671a3..11959749 100644 --- a/src/backend/static.jl +++ b/src/backend/static.jl @@ -79,7 +79,7 @@ Compile a list of Feynman graphs into a string for a julia static function. The """ function to_julia_str(graphs::AbstractVector{<:AbstractGraph}; root::AbstractVector{Int}=[id(g) for g in graphs], name::String="eval_graph!") - head = "\nfunction $name(root::AbstractVector, leafVal::AbstractVector)\n " + head = "\nfunction $name(root::AbstractVector, leafVal::AbstractVector)\n" body = "" inds_visitedleaf = Int[] inds_visitednode = Int[] @@ -97,26 +97,91 @@ function to_julia_str(graphs::AbstractVector{<:AbstractGraph}; root::AbstractVec if isempty(subgraphs(g)) #leaf g_id in inds_visitedleaf && continue factor_str = factor(g) == 1 ? "" : " * $(factor(g))" - body *= " $target = leafVal[$idx_leafVal]$factor_str\n " + body *= " $target = leafVal[$idx_leafVal]$factor_str\n" map_validx_leaf[idx_leafVal] = g idx_leafVal += 1 push!(inds_visitedleaf, g_id) else g_id in inds_visitednode && continue factor_str = factor(g) == 1 ? "" : " * $(factor(g))" - body *= " $target = $(to_static(operator(g), subgraphs(g), subgraph_factors(g)))$factor_str\n " + body *= " $target = $(to_static(operator(g), subgraphs(g), subgraph_factors(g)))$factor_str\n" push!(inds_visitednode, g_id) end if isroot - body *= " $target_root = $target\n " + body *= " $target_root = $target\n" end end end - # tail = "end\n " - tail = "end " + tail = "end" return head * body * tail, map_validx_leaf end +function julia_to_C_typestr(type::DataType) + if type == Float64 + return "double " + elseif type == Float32 + return "float " + elseif type == Int64 + return "long long " + elseif type == Int32 + return "int " + elseif type == ComplexF32 + return "complex float " + elseif type == ComplexF64 + return "complex double " + elseif type <: Array + return julia_to_C_typestr(eltype(type)) * "*" + else + error("Unsupported type") + end +end + +function to_Cstr(graphs::AbstractVector{<:AbstractGraph}; root::AbstractVector{Int}=[id(g) for g in graphs], + datatype::DataType=_dtype.weight, name::String="eval_graph") + # head = "#include " + ctype_str = julia_to_C_typestr(datatype) + head = "\nvoid $name($ctype_str*root, $ctype_str*leafVal)\n{\n" + + declare = " $ctype_str" + body = "" + inds_visitedleaf = Int[] + inds_visitednode = Int[] + idx_leafVal = 0 + map_validx_leaf = Dict{Int,eltype(graphs)}() # mapping from the index of the leafVal to the leaf graph + for graph in graphs + for g in PostOrderDFS(graph) #leaf first search + g_id = id(g) + target = "g$(g_id)" + isroot = false + if g_id in root + target_root = "root[$(findfirst(x -> x == g_id, root)-1)]" + isroot = true + end + if isempty(subgraphs(g)) #leaf + g_id in inds_visitedleaf && continue + declare *= " g$g_id," + factor_str = factor(g) == 1 ? "" : " * $(factor(g))" + body *= " $target = leafVal[$idx_leafVal]$factor_str;\n" + idx_leafVal += 1 + map_validx_leaf[idx_leafVal] = g + push!(inds_visitedleaf, g_id) + else + g_id in inds_visitednode && continue + declare *= " g$g_id," + factor_str = factor(g) == 1 ? "" : " * $(factor(g))" + body *= " $target = $(to_static(operator(g), subgraphs(g), subgraph_factors(g)))$factor_str;\n" + push!(inds_visitednode, g_id) + end + if isroot + body *= " $target_root = $target;\n" + end + end + end + declare = chop(declare) * ";\n" + tail = "}" + return head * declare * body * tail, map_validx_leaf +end + """ function compile(graphs::AbstractVector{<:AbstractGraph}; root::AbstractVector{Int}=[id(g) for g in graphs]) @@ -148,9 +213,10 @@ function compile(graphs::AbstractVector{<:AbstractGraph}; end """ - compile_code(graphs::AbstractVector{<:AbstractGraph}, filename::String; root::AbstractVector{Int}=[id(g) for g in graphs], func_name="eval_graph!") -> Dict + function compile_Julia(graphs::AbstractVector{<:AbstractGraph}, filename::String; + root::AbstractVector{Int}=[id(g) for g in graphs], func_name="eval_graph!") - Compiles a set of graphs into Julia code and append the generated code to a file. + Compiles a set of graphs into Julia code and append the generated code to a specified file. # Arguments - `graphs::AbstractVector{<:AbstractGraph}`: An array of graph objects. These graphs are processed to generate Julia code. @@ -161,12 +227,36 @@ end # Returns - A dictionary (`leafmap`) that maps the index of the leaf weight's table `leafVal` to the leaf graph. """ -function compile_code(graphs::AbstractVector{<:AbstractGraph}, filename::String; +function compile_Julia(graphs::AbstractVector{<:AbstractGraph}, filename::String; root::AbstractVector{Int}=[id(g) for g in graphs], func_name="eval_graph!") - # this function return a runtime generated function defined by compile() func_string, leafmap = to_julia_str(graphs; root=root, name=func_name) open(filename, "a") do f write(f, func_string) end return leafmap end + +""" + function compile_C(graphs::AbstractVector{<:AbstractGraph}, filename::String; + datatype::DataType=_dtype.weight, root::AbstractVector{Int}=[id(g) for g in graphs], func_name="eval_graph") + + Compiles a set of graphs into C language code and append the generated code to a specified file. + +# Arguments +- `datatype::DataType`: This type is used for variables types in the generated C code. +- `graphs::AbstractVector{<:AbstractGraph}`: An array of graph objects. These graphs are processed to generate Julia code. +- `filename::String`: The name of the file to which the generated code will be appended. The file is created if it does not exist. +- `root::AbstractVector{Int}` (keyword): An array of integers representing root nodes for each graph in `graphs`. By default, it is an array of IDs obtained by calling `id(g)` for each graph `g` in `graphs`. +- `func_name::String` (keyword): The base name for the function(s) to be generated. Defaults to `"eval_graph"`. + +# Returns +- A dictionary (`leafmap`) that maps the index of the leaf weight's table `leafVal` to the leaf graph. +""" +function compile_C(graphs::AbstractVector{<:AbstractGraph}, filename::String; + datatype::DataType=_dtype.weight, root::AbstractVector{Int}=[id(g) for g in graphs], func_name="eval_graph") + func_string, leafmap = to_Cstr(graphs; datatype=datatype, root=root, name=func_name) + open(filename, "a") do f + write(f, func_string) + end + return leafmap +end \ No newline at end of file