diff --git a/.vscode/settings.json b/.vscode/settings.json index 3ecb8fcd..351cd5d8 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -2,5 +2,6 @@ "[python]": { "editor.defaultFormatter": "ms-python.autopep8" }, - "python.formatting.provider": "none" -} + "python.formatting.provider": "none", + "julia.environmentPath": "/home/pchou/Documents/DiagMC/Code/numericalEFT/FeynmanDiagram.jl" +} \ No newline at end of file diff --git a/docs/make.jl b/docs/make.jl index f68e2ee4..b3d17f24 100644 --- a/docs/make.jl +++ b/docs/make.jl @@ -24,11 +24,11 @@ makedocs(; "API reference" => Any[ "lib/operator.md", "lib/computgraph.md", + "lib/taylorseries.md", "lib/frontend.md", "lib/GV.md", "lib/parquet.md", - "lib/diagtree.md", - "lib/exprtree.md", + "lib/backend.md", ] ] ) diff --git a/docs/src/index.md b/docs/src/index.md index e1045969..680935ee 100644 --- a/docs/src/index.md +++ b/docs/src/index.md @@ -18,11 +18,11 @@ Modules = [FeynmanDiagram] Pages = [ "lib/operator.md", "lib/computgraph.md", + "lib/taylorseries.md", "lib/frontend.md", "lib/GV.md", "lib/parquet.md", - "lib/diagtree.md", - "lib/exprtree.md", + "lib/backend.md", ] Depth = 2 ``` diff --git a/docs/src/lib/backend.md b/docs/src/lib/backend.md new file mode 100644 index 00000000..cf7e80c4 --- /dev/null +++ b/docs/src/lib/backend.md @@ -0,0 +1,7 @@ +# Compilers compile computational graphs to optimized source code for diverse platforms + +## API + +```@autodocs +Modules = [FeynmanDiagram.Compilers] +``` \ No newline at end of file diff --git a/docs/src/lib/diagtree.md b/docs/src/lib/diagtree.md deleted file mode 100644 index 85b5141c..00000000 --- a/docs/src/lib/diagtree.md +++ /dev/null @@ -1,7 +0,0 @@ -# Diagrams as an AbstractTree - -## API - -```@autodocs -Modules = [FeynmanDiagram.DiagTree] -``` \ No newline at end of file diff --git a/docs/src/lib/exprtree.md b/docs/src/lib/exprtree.md deleted file mode 100644 index f3699ff8..00000000 --- a/docs/src/lib/exprtree.md +++ /dev/null @@ -1,7 +0,0 @@ -# Diagrams as an Expression Tree - -## API - -```@autodocs -Modules = [FeynmanDiagram.ExprTree] -``` \ No newline at end of file diff --git a/docs/src/lib/frontend.md b/docs/src/lib/frontend.md index b157567b..f1a72f80 100644 --- a/docs/src/lib/frontend.md +++ b/docs/src/lib/frontend.md @@ -1,4 +1,4 @@ -# Front-end translates a source code into a computational graph +# Front-end generates Feynman diagrams and translates then into a computational graph ## API diff --git a/docs/src/lib/taylorseries.md b/docs/src/lib/taylorseries.md new file mode 100644 index 00000000..867f50f2 --- /dev/null +++ b/docs/src/lib/taylorseries.md @@ -0,0 +1,7 @@ +# Taylor expansions in independent variables (support AbstractGraph) + +## API + +```@autodocs +Modules = [FeynmanDiagram.Taylor] +``` \ No newline at end of file diff --git a/example/to_dot_parquetV2.jl b/example/to_dot_parquetV2.jl index 5831809a..21fdc14d 100644 --- a/example/to_dot_parquetV2.jl +++ b/example/to_dot_parquetV2.jl @@ -3,7 +3,7 @@ using FeynmanDiagram function recursive_print(diag) if typeof(diag) <: FeynmanDiagram.ComputationalGraphs.Graph if !isempty(diag.subgraphs) - print("$(diag.id) $(diag.factor) $(diag.subgraph_factors)\n") + print("$(diag.id) $(diag.subgraph_factors)\n") for subdiag in diag.subgraphs recursive_print(subdiag) end @@ -24,7 +24,7 @@ function main() KinL, KoutL, KinR = zeros(16), zeros(16), zeros(16) KinL[1], KoutL[2], KinR[3] = 1.0, 1.0, 1.0 # para = GV.diagPara(SigmaDiag, false, spin, order, [NoHartree], KinL - KoutL) - para = DiagParaF64(type=SigmaDiag, innerLoopNum=order, interaction=[Interaction(UpUp, [Instant,])], hasTau=true) + para = DiagPara(type=SigmaDiag, innerLoopNum=order, interaction=[Interaction(UpUp, [Instant,])], hasTau=true) # para = DiagParaF64(type=SigmaDiag, innerLoopNum=2, interaction=[Interaction(ChargeCharge, [Instant,])], hasTau=true) parquet_builder = Parquet.build(para) diag = parquet_builder.diagram @@ -38,8 +38,8 @@ function main() # print("new diag2\n") # recursive_print(eachd) # end - G = FrontEnds.Graph!(d[1]) - G = [eldest(G)] # drop extraneous Add node at root + # G = FrontEnds.Graph!(d[1]) + G = [eldest(d[1])] # drop extraneous Add node at root # for d in G # print("graph1\n") # recursive_print(d) diff --git a/src/FeynmanDiagram.jl b/src/FeynmanDiagram.jl index 9870d195..8f1d9e14 100644 --- a/src/FeynmanDiagram.jl +++ b/src/FeynmanDiagram.jl @@ -5,88 +5,6 @@ macro todo() return :(error("Not yet implemented!")) end -@enum DiagramType begin - VacuumDiag #vaccum diagram for the free energy - SigmaDiag #self-energy - GreenDiag #green's function - PolarDiag #polarization - Ver3Diag #3-point vertex function - Ver4Diag #4-point vertex function - GnDiag #n-point Green's function - GcDiag #n-point connected Green's function -end -Base.length(r::DiagramType) = 1 -Base.iterate(r::DiagramType) = (r, nothing) -function Base.iterate(r::DiagramType, ::Nothing) end - -abstract type DiagType end -abstract type Vacuum <: DiagType end -abstract type Tadpole <: DiagType end -abstract type FermiPropagator <: DiagType end -abstract type BosePropagator <: DiagType end -abstract type FermiSelfEnergy <: DiagType end -abstract type BoseSelfEnergy <: DiagType end -abstract type VertexDiag <: DiagType end -abstract type GncDiag <: DiagType end -abstract type GndDiag <: DiagType end - -@enum Filter begin - Wirreducible #remove all polarization subdiagrams - Girreducible #remove all self-energy inseration - NoHartree - NoFock - NoBubble # true to remove all bubble subdiagram - Proper #ver4, ver3, and polarization diagrams may require to be irreducible along the transfer momentum/frequency - DirectOnly # only direct interaction, this can be useful for debug purpose -end - -Base.length(r::Filter) = 1 -Base.iterate(r::Filter) = (r, nothing) -function Base.iterate(r::Filter, ::Nothing) end - -@enum Response begin - Composite - ChargeCharge - SpinSpin - ProperChargeCharge - ProperSpinSpin - UpUp - UpDown -end - -Base.length(r::Response) = 1 -Base.iterate(r::Response) = (r, nothing) -function Base.iterate(r::Response, ::Nothing) end - -@enum AnalyticProperty begin - Instant - Dynamic - D_Instant #derivative of instant interaction - D_Dynamic #derivative of the dynamic interaction -end - -Base.length(r::AnalyticProperty) = 1 -Base.iterate(r::AnalyticProperty) = (r, nothing) -function Base.iterate(r::AnalyticProperty, ::Nothing) end - -export SigmaDiag, PolarDiag, Ver3Diag, Ver4Diag, GreenDiag -export VacuumDiag, GnDiag, GcDiag -export Wirreducible, Girreducible, NoBubble, NoHartree, NoFock, Proper, DirectOnly -export Response, ChargeCharge, SpinSpin, UpUp, UpDown -export AnalyticProperty, Instant, Dynamic, D_Instant, D_Dynamic - -export DiagType -export FermiPropagator, BosePropagator, FermiSelfEnergy, BoseSelfEnergy, VertexDiag -export Vacuum, Tadpole, GncDiag, GndDiag - -include("common.jl") -export DiagPara, DiagParaF64 -export Interaction, interactionTauNum, innerTauNum - -include("common_new.jl") -export DiagramPara, DiagramParaF64 -# export Interaction, interactionTauNum, innerTauNum - include("quantum_operator/QuantumOperators.jl") using .QuantumOperators @@ -98,9 +16,6 @@ export fermionic_annihilation, fermionic_creation, majorana export bosonic_annihilation, bosonic_creation, real_classic export correlator_order, normal_order - - - include("computational_graph/ComputationalGraph.jl") using .ComputationalGraphs export ComputationalGraphs @@ -119,7 +34,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, has_zero_subfactors, eldest +export haschildren, onechild, isleaf, isbranch, ischain, 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 export open_parenthesis, open_parenthesis!, flatten_prod!, flatten_prod, flatten_sum!, flatten_sum @@ -129,39 +44,6 @@ include("TaylorSeries/TaylorSeries.jl") using .Taylor export Taylor -include("diagram_tree/DiagTree.jl") -using .DiagTree -export DiagTree -export TwoBodyChannel, Alli, PHr, PHEr, PPr, AnyChan -export Permutation, Di, Ex, DiEx -export Diagram, addSubDiagram!, toDataFrame -export evalDiagNode!, evalDiagTree!, evalDiagTreeKT! -export Operator, Sum, Prod -export DiagramId, GenericId, Ver4Id, Ver3Id, GreenId, SigmaId, PolarId -export PropagatorId, BareGreenId, BareInteractionId -export BareGreenNId, BareHoppingId, GreenNId, ConnectedGreenNId -export uidreset, toDataFrame, mergeby, plot_tree - - -include("parquet_builder/parquet.jl") -using .Parquet -export Parquet -export ParquetBlocks - -include("strong_coupling_expansion_builder/strong_coupling_expansion") -using .SCE -export SCE -export Gn - -include("expression_tree/ExpressionTree.jl") -using .ExprTree -export ExprTree -export Component, ExpressionTree -# export Propagator -export addpropagator!, addnode! -export setroot!, addroot! -export evalNaive, showTree - include("utility.jl") using .Utility export Utility @@ -172,46 +54,68 @@ using .FrontEnds export FrontEnds export LabelProduct +include("frontend/parquet/parquet.jl") +using .Parquet +export Parquet +export ParquetBlocks +export DiagramType, VacuumDiag, SigmaDiag, GreenDiag, PolarDiag, Ver3Diag, Ver4Diag +export Filter, Wirreducible, Girreducible, NoBubble, NoHartree, NoFock, Proper, DirectOnly +export Response, Composite, ChargeCharge, SpinSpin, ProperChargeCharge, ProperSpinSpin, UpUp, UpDown +export AnalyticProperty, Instant, Dynamic, D_Instant, D_Dynamic + +export DiagPara +export Interaction, interactionTauNum, innerTauNum +export TwoBodyChannel, Alli, PHr, PHEr, PPr, AnyChan +export Permutation, Di, Ex, DiEx +export DiagramId, GenericId, Ver4Id, Ver3Id, GreenId, SigmaId, PolarId +export PropagatorId, BareGreenId, BareInteractionId +export mergeby + include("frontend/GV.jl") using .GV export GV export diagdictGV, diagdict_parquet, leafstates, leafstates_diagtree +# include("frontend/strong_coupling_expansion_builder/strong_coupling_expansion.jl") +# using .SCE +# export SCE +# export Gn + include("backend/compiler.jl") using .Compilers export Compilers -##################### precompile ####################### -# precompile as the final step of the module definition: -if ccall(:jl_generating_output, Cint, ()) == 1 # if we're precompiling the package - let - para = DiagParaF64(type=Ver4Diag, innerLoopNum=2, hasTau=true) - # ver4 = Parquet.vertex4(para) # this will force precompilation - ver4 = Parquet.build(para) # this will force precompilation - - mergeby(ver4, [:response]) - mergeby(ver4.diagram) - mergeby(ver4.diagram, [:response]; idkey=[:extT, :response]) - - para = DiagParaF64(type=SigmaDiag, innerLoopNum=2, hasTau=true) - Parquet.build(para) # this will force precompilation - para = DiagParaF64(type=GreenDiag, innerLoopNum=2, hasTau=true) - Parquet.green(para) # this will force precompilation - para = DiagParaF64(type=PolarDiag, innerLoopNum=2, hasTau=true) - # Parquet.polarization(para) # this will force precompilation - Parquet.build(para) # this will force precompilation - para = DiagParaF64(type=Ver3Diag, innerLoopNum=2, hasTau=true) - # Parquet.vertex3(para) # this will force precompilation - Parquet.build(para) # this will force precompilation - - DiagTree.removeHartreeFock!(ver4.diagram) - DiagTree.derivative(ver4.diagram, BareGreenId) - DiagTree.derivative(ver4.diagram, BareInteractionId) - # DiagTree.removeHartreeFock!(ver4.diagram) - ExprTree.build(ver4.diagram, 3) - end -end +# ##################### precompile ####################### +# # precompile as the final step of the module definition: +# if ccall(:jl_generating_output, Cint, ()) == 1 # if we're precompiling the package +# let +# para = DiagParaF64(type=Ver4Diag, innerLoopNum=2, hasTau=true) +# # ver4 = Parquet.vertex4(para) # this will force precompilation +# ver4 = Parquet.build(para) # this will force precompilation + +# mergeby(ver4, [:response]) +# mergeby(ver4.diagram) +# mergeby(ver4.diagram, [:response]; idkey=[:extT, :response]) + +# para = DiagParaF64(type=SigmaDiag, innerLoopNum=2, hasTau=true) +# Parquet.build(para) # this will force precompilation +# para = DiagParaF64(type=GreenDiag, innerLoopNum=2, hasTau=true) +# Parquet.green(para) # this will force precompilation +# para = DiagParaF64(type=PolarDiag, innerLoopNum=2, hasTau=true) +# # Parquet.polarization(para) # this will force precompilation +# Parquet.build(para) # this will force precompilation +# para = DiagParaF64(type=Ver3Diag, innerLoopNum=2, hasTau=true) +# # Parquet.vertex3(para) # this will force precompilation +# Parquet.build(para) # this will force precompilation + +# DiagTree.removeHartreeFock!(ver4.diagram) +# DiagTree.derivative(ver4.diagram, BareGreenId) +# DiagTree.derivative(ver4.diagram, BareInteractionId) +# # DiagTree.removeHartreeFock!(ver4.diagram) +# ExprTree.build(ver4.diagram, 3) +# end +# end end diff --git a/src/backend/compiler.jl b/src/backend/compiler.jl index 64a3767a..f2566a85 100644 --- a/src/backend/compiler.jl +++ b/src/backend/compiler.jl @@ -1,10 +1,10 @@ module Compilers using PyCall using ..ComputationalGraphs -import ..ComputationalGraphs: id, name, set_name!, operator, subgraphs, subgraph_factors, factor, FeynmanProperties +import ..ComputationalGraphs: id, name, set_name!, operator, subgraphs, subgraph_factors, FeynmanProperties -using ..DiagTree -using ..DiagTree: Diagram, PropagatorId, BareGreenId, BareInteractionId +using ..Parquet +using ..Parquet: PropagatorId, BareGreenId, BareInteractionId using ..QuantumOperators import ..QuantumOperators: isfermionic diff --git a/src/backend/compiler_python.jl b/src/backend/compiler_python.jl index 1fbea267..a7a49822 100644 --- a/src/backend/compiler_python.jl +++ b/src/backend/compiler_python.jl @@ -96,15 +96,13 @@ function to_python_str(graphs::AbstractVector{<:AbstractGraph}, framework::Symbo 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" + body *= " $target = leaf[$(leafidx)]\n" gid_to_leafid[target] = leafidx leafidx += 1 push!(inds_visitedleaf, g_id) else g_id in inds_visitednode && continue - factor_str = factor(g) == 1 ? "" : " * $(factor(g))" - body *= " $target = $(to_pystatic(operator(g), subgraphs(g), subgraph_factors(g)))$factor_str\n" + body *= " $target = $(to_pystatic(operator(g), subgraphs(g), subgraph_factors(g)))\n" push!(inds_visitednode, g_id) end if isroot @@ -115,18 +113,18 @@ function to_python_str(graphs::AbstractVector{<:AbstractGraph}, framework::Symbo end head *= "def graphfunc(leaf):\n" output = ["root$(i)" for i in 0:rootidx-1] - output = join(output,",") + output = join(output, ",") tail = " return $output\n\n" if framework == :jax - tail *="graphfunc_jit = jit(graphfunc)" + tail *= "graphfunc_jit = jit(graphfunc)" end expr = head * body * tail - return expr, leafidx , gid_to_leafid + return expr, leafidx, gid_to_leafid end function compile_python(graphs::AbstractVector{<:AbstractGraph}, framework::Symbol=:jax, filename::String="GraphFunc.py") - py_string, leafnum, leafmap = to_python_str(graphs,framework) + py_string, leafnum, leafmap = to_python_str(graphs, framework) println("The number of leaves: $leafnum") open(filename, "w") do f write(f, py_string) diff --git a/src/backend/static.jl b/src/backend/static.jl index 11959749..40df4cc5 100644 --- a/src/backend/static.jl +++ b/src/backend/static.jl @@ -96,15 +96,13 @@ function to_julia_str(graphs::AbstractVector{<:AbstractGraph}; root::AbstractVec end 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]\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)))\n" push!(inds_visitednode, g_id) end if isroot @@ -160,16 +158,14 @@ function to_Cstr(graphs::AbstractVector{<:AbstractGraph}; root::AbstractVector{I 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" + body *= " $target = leafVal[$idx_leafVal];\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" + body *= " $target = $(to_static(operator(g), subgraphs(g), subgraph_factors(g)));\n" push!(inds_visitednode, g_id) end if isroot diff --git a/src/backend/to_dot.jl b/src/backend/to_dot.jl index 5228a818..410e63ab 100644 --- a/src/backend/to_dot.jl +++ b/src/backend/to_dot.jl @@ -1,33 +1,17 @@ -function to_dotstatic(operator::Type, id::Int, factor, subgraphs::AbstractVector{<:AbstractGraph}, subgraph_factors::AbstractVector) +function to_dotstatic(operator::Type, id::Int, subgraphs::AbstractVector{<:AbstractGraph}, subgraph_factors::AbstractVector) error( "Static representation for computational graph nodes with operator $(operator) not yet implemented! " ) end -function to_dotstatic(::Type{ComputationalGraphs.Sum}, id::Int, factor::F, subgraphs::Vector{Graph{F,W}}, subgraph_factors::Vector{F}) where {F,W} +function to_dotstatic(::Type{ComputationalGraphs.Sum}, id::Int, subgraphs::Vector{Graph{F,W}}, subgraph_factors::Vector{F}) where {F,W} node_temp = "" arrow_temp = "" - if factor != 1 - # opr_fac = "factor$(id)[label=$(factor), style=filled, fillcolor=lavender]\n" - # opr_name = "g$(id)_t" - # node_str = "g$(id)[shape=box, label = <⊗>, style=filled, fillcolor=cornsilk,]\n" - # arrow_temp *= "factor$(id)->g$(id)[arrowhead=vee,]\ng$(id)_t->g$(id)[arrowhead=vee,]\n" - # node_temp *= opr_fac * node_str - opr_node = "g$(id)[shape=box, label = <($factor)*⊕>, style=filled, fillcolor=cyan,fontsize=18]" - else - opr_node = "g$(id)[shape=box, label = <⊕>, style=filled, fillcolor=cyan,fontsize=18]" - # opr_name = "g$id" - end - opr_name = "g$id" - # opr_node = opr_name * "[shape=box, label = <⊕>, style=filled, fillcolor=cyan,]\n" + # opr_node = "g$(id)[shape=box, label = <($factor)*⊕>, style=filled, fillcolor=cyan,fontsize=18]" + opr_node = "g$(id)[shape=box, label = <⊕>, style=filled, fillcolor=cyan,fontsize=18]" node_temp *= opr_node - for (gix, (g, gfactor)) in enumerate(zip(subgraphs, subgraph_factors)) + for (g, gfactor) in zip(subgraphs, subgraph_factors) if gfactor != 1 - # factor_str = "factor$(g.id)_$(id)_$gix[label=$(gfactor), style=filled, fillcolor=lavender]\n" - # subg_str = "g$(g.id)_$(id)_$gix[shape=box, label = <⊗>, style=filled, fillcolor=cornsilk,]\n" - # node_temp *= factor_str * subg_str - # arrow_temp *= "factor$(g.id)_$(id)_$gix->g$(g.id)_$(id)_$gix[arrowhead=vee,]\ng$(g.id)->g$(g.id)_$(id)_$gix[arrowhead=vee,]\n" - # arrow_temp *= "g$(g.id)_$(id)_$gix->$opr_name[arrowhead=vee,]\n" arrow_temp *= "g$(g.id)->g$(id)[arrowhead=vee,label=$gfactor,fontsize=16]\n" else arrow_temp *= "g$(g.id)->g$(id)[arrowhead=vee,]\n" @@ -36,37 +20,14 @@ function to_dotstatic(::Type{ComputationalGraphs.Sum}, id::Int, factor::F, subgr return node_temp, arrow_temp end -function to_dotstatic(::Type{ComputationalGraphs.Prod}, id::Int, factor::F, subgraphs::Vector{Graph{F,W}}, subgraph_factors::Vector{F}) where {F,W} +function to_dotstatic(::Type{ComputationalGraphs.Prod}, id::Int, subgraphs::Vector{Graph{F,W}}, subgraph_factors::Vector{F}) where {F,W} node_temp = "" arrow_temp = "" - if factor != 1 - # opr_fac = "factor$(id)[label=$(factor), style=filled, fillcolor=lavender]\n" - # opr_name = "g$(id)_t" - # node_str = "g$(id)[shape=box, label = <⊗>, style=filled, fillcolor=cornsilk,]\n" - # arrow_temp *= "factor$(id)->g$(id)[arrowhead=vee,]\ng$(id)_t->g$(id)[arrowhead=vee,]\n" - # node_temp *= opr_fac * node_str - opr_node = "g$id[shape=box, label = <($factor)⊗>, style=filled, fillcolor=cornsilk,fontsize=18]\n" - else - opr_node = "g$id[shape=box, label = <⊗>, style=filled, fillcolor=cornsilk,fontsize=18]\n" - end - # opr_node = opr_name * "[shape=box, label = <⊗>, style=filled, fillcolor=cornsilk,]\n" + # opr_node = "g$id[shape=box, label = <($factor)⊗>, style=filled, fillcolor=cornsilk,fontsize=18]\n" + opr_node = "g$id[shape=box, label = <⊗>, style=filled, fillcolor=cornsilk,fontsize=18]\n" node_temp *= opr_node - # if length(subgraphs) == 1 - # if subgraph_factors[1] == 1 - # arrow_temp *= "g$(subgraphs[1].id)->$opr_name[arrowhead=vee,]\n" - # else - # factor_str = "factor$(subgraphs[1].id)_$(id)[label=$(subgraph_factors[1]), style=filled, fillcolor=lavender]\n" - # node_temp *= factor_str - # arrow_temp *= "factor$(subgraphs[1].id)_$(id)->$opr_name[arrowhead=vee,]\ng$(subgraphs[1].id)->$opr_name[arrowhead=vee,]\n" - # end - # else - for (gix, (g, gfactor)) in enumerate(zip(subgraphs, subgraph_factors)) + for (g, gfactor) in zip(subgraphs, subgraph_factors) if gfactor != 1 - # factor_str = "factor$(g.id)_$(id)_$gix[label=$(gfactor), style=filled, fillcolor=lavender]\n" - # subg_str = "g$(g.id)_$(id)_$gix[shape=box, label = <⊗>, style=filled, fillcolor=cornsilk,]\n" - # node_temp *= factor_str * subg_str - # arrow_temp *= "factor$(g.id)_$(id)_$gix->g$(g.id)_$(id)_$gix[arrowhead=vee,]\ng$(g.id)->g$(g.id)_$(id)_$gix[arrowhead=vee,]\n" - # arrow_temp *= "g$(g.id)_$(id)_$gix->$opr_name[arrowhead=vee,]\n" arrow_temp *= "g$(g.id)->g$(id)[arrowhead=vee,label=$gfactor,fontsize=16]\n" else arrow_temp *= "g$(g.id)->g$(id)[arrowhead=vee,]\n" @@ -76,29 +37,13 @@ function to_dotstatic(::Type{ComputationalGraphs.Prod}, id::Int, factor::F, subg return node_temp, arrow_temp end -function to_dotstatic(::Type{ComputationalGraphs.Power{N}}, id::Int, factor::F, subgraphs::Vector{Graph{F,W}}, subgraph_factors::Vector{F}) where {N,F,W} +function to_dotstatic(::Type{ComputationalGraphs.Power{N}}, id::Int, subgraphs::Vector{Graph{F,W}}, subgraph_factors::Vector{F}) where {N,F,W} node_temp = "" arrow_temp = "" - if factor != 1 - # opr_fac = "factor$(id)[label=$(factor), style=filled, fillcolor=lavender]\n" - # opr_name = "g$(id)_t" - # node_str = "g$(id)[shape=box, label = <⊗>, style=filled, fillcolor=cornsilk,]\n" - # arrow_temp *= "factor$(id)->g$(id)[arrowhead=vee,]\ng$(id)_t->g$(id)[arrowhead=vee,]\n" - # node_temp *= opr_fac * node_str - opr_node = "g$id[shape=box, label = <($factor)*Pow($N)>, style=filled, fillcolor=darkolivegreen,fontsize=18]\n" - else - opr_node = "g$id[shape=box, label = , style=filled, fillcolor=darkolivegreen,fontsize=18]\n" - end - # opr_node = "g$id[shape=box, label = , style=filled, fillcolor=darkolivegreen,]\n" - # order_node = "order$(id)[label=$N, style=filled, fillcolor=lavender]\n" - # node_temp *= opr_node * order_node + # opr_node = "g$id[shape=box, label = <($factor)*Pow($N)>, style=filled, fillcolor=darkolivegreen,fontsize=18]\n" + opr_node = "g$id[shape=box, label = , style=filled, fillcolor=darkolivegreen,fontsize=18]\n" node_temp *= opr_node - # arrow_temp *= "order$(id)->$opr_name[arrowhead=vee,]\n" if subgraph_factors[1] != 1 - # factor_str = "factor$(subgraphs[1].id)_$(id)[label=$(subgraph_factors[1]), style=filled, fillcolor=lavender]\n" - # subg_str = "g$(subgraphs[1].id)_$(id)[shape=box, label = <⊗>, style=filled, fillcolor=cornsilk,]\n" - # node_temp *= factor_str * subg_str - # arrow_temp *= "factor$(subgraphs[1].id)_$(id)->g$(subgraphs[1].id)_$(id)[arrowhead=vee,]\ng$(subgraphs[1].id)->g$(subgraphs[1].id)_$(id)[arrowhead=vee,]\n" arrow_temp *= "g$(subgraphs[1].id)->$opr_name[arrowhead=vee,label=$gfactor,fontsize=16]\n" else arrow_temp *= "g$(subgraphs[1].id)->$opr_name[arrowhead=vee,]\n" @@ -106,30 +51,15 @@ function to_dotstatic(::Type{ComputationalGraphs.Power{N}}, id::Int, factor::F, return node_temp, arrow_temp end -function to_dotstatic(::Type{ComputationalGraphs.Sum}, id::Int, factor::F, subgraphs::Vector{FeynmanGraph{F,W}}, subgraph_factors::Vector{F}) where {F,W} +function to_dotstatic(::Type{ComputationalGraphs.Sum}, id::Int, subgraphs::Vector{FeynmanGraph{F,W}}, subgraph_factors::Vector{F}) where {F,W} node_temp = "" arrow_temp = "" - if factor != 1 - # opr_fac = "factor$(id)[label=$(factor), style=filled, fillcolor=lavender]\n" - # opr_name = "g$(id)_t" - # node_str = "g$(id)[shape=box, label = <⊗>, style=filled, fillcolor=cornsilk,]\n" - # arrow_temp *= "factor$(id)->g$(id)[arrowhead=vee,]\ng$(id)_t->g$(id)[arrowhead=vee,]\n" - # node_temp *= opr_fac * node_str - opr_node = "g$(id)[shape=box, label = <($factor)*⊕>, style=filled, fillcolor=cyan,fontsize=18]" - else - opr_node = "g$(id)[shape=box, label = <⊕>, style=filled, fillcolor=cyan,fontsize=18]" - # opr_name = "g$id" - end + # opr_node = "g$(id)[shape=box, label = <($factor)*⊕>, style=filled, fillcolor=cyan,fontsize=18]" + opr_node = "g$(id)[shape=box, label = <⊕>, style=filled, fillcolor=cyan,fontsize=18]" opr_name = "g$id" - # opr_node = opr_name * "[shape=box, label = <⊕>, style=filled, fillcolor=cyan,]\n" node_temp *= opr_node - for (gix, (g, gfactor)) in enumerate(zip(subgraphs, subgraph_factors)) + for (g, gfactor) in zip(subgraphs, subgraph_factors) if gfactor != 1 - # factor_str = "factor$(g.id)_$(id)_$gix[label=$(gfactor), style=filled, fillcolor=lavender]\n" - # subg_str = "g$(g.id)_$(id)_$gix[shape=box, label = <⊗>, style=filled, fillcolor=cornsilk,]\n" - # node_temp *= factor_str * subg_str - # arrow_temp *= "factor$(g.id)_$(id)_$gix->g$(g.id)_$(id)_$gix[arrowhead=vee,]\ng$(g.id)->g$(g.id)_$(id)_$gix[arrowhead=vee,]\n" - # arrow_temp *= "g$(g.id)_$(id)_$gix->$opr_name[arrowhead=vee,]\n" arrow_temp *= "g$(g.id)->$opr_name[arrowhead=vee,label=$gfactor,fontsize=16]\n" else arrow_temp *= "g$(g.id)->$opr_name[arrowhead=vee,]\n" @@ -138,37 +68,14 @@ function to_dotstatic(::Type{ComputationalGraphs.Sum}, id::Int, factor::F, subgr return node_temp, arrow_temp end -function to_dotstatic(::Type{ComputationalGraphs.Prod}, id::Int, factor::F, subgraphs::Vector{FeynmanGraph{F,W}}, subgraph_factors::Vector{F}) where {F,W} +function to_dotstatic(::Type{ComputationalGraphs.Prod}, id::Int, subgraphs::Vector{FeynmanGraph{F,W}}, subgraph_factors::Vector{F}) where {F,W} node_temp = "" arrow_temp = "" - if factor != 1 - # opr_fac = "factor$(id)[label=$(factor), style=filled, fillcolor=lavender]\n" - # opr_name = "g$(id)_t" - # node_str = "g$(id)[shape=box, label = <⊗>, style=filled, fillcolor=cornsilk,]\n" - # arrow_temp *= "factor$(id)->g$(id)[arrowhead=vee,]\ng$(id)_t->g$(id)[arrowhead=vee,]\n" - # node_temp *= opr_fac * node_str - opr_node = "g$id[shape=box, label = <($factor)⊗>, style=filled, fillcolor=cornsilk,fontsize=18]\n" - else - opr_node = "g$id[shape=box, label = <⊗>, style=filled, fillcolor=cornsilk,fontsize=18]\n" - end - # opr_node = opr_name * "[shape=box, label = <⊗>, style=filled, fillcolor=cornsilk,]\n" + # opr_node = "g$id[shape=box, label = <($factor)⊗>, style=filled, fillcolor=cornsilk,fontsize=18]\n" + opr_node = "g$id[shape=box, label = <⊗>, style=filled, fillcolor=cornsilk,fontsize=18]\n" node_temp *= opr_node - # if length(subgraphs) == 1 - # if subgraph_factors[1] == 1 - # arrow_temp *= "g$(subgraphs[1].id)->$opr_name[arrowhead=vee,]\n" - # else - # factor_str = "factor$(subgraphs[1].id)_$(id)[label=$(subgraph_factors[1]), style=filled, fillcolor=lavender]\n" - # node_temp *= factor_str - # arrow_temp *= "factor$(subgraphs[1].id)_$(id)->$opr_name[arrowhead=vee,]\ng$(subgraphs[1].id)->$opr_name[arrowhead=vee,]\n" - # end - # else - for (gix, (g, gfactor)) in enumerate(zip(subgraphs, subgraph_factors)) + for (g, gfactor) in zip(subgraphs, subgraph_factors) if gfactor != 1 - # factor_str = "factor$(g.id)_$(id)_$gix[label=$(gfactor), style=filled, fillcolor=lavender]\n" - # subg_str = "g$(g.id)_$(id)_$gix[shape=box, label = <⊗>, style=filled, fillcolor=cornsilk,]\n" - # node_temp *= factor_str * subg_str - # arrow_temp *= "factor$(g.id)_$(id)_$gix->g$(g.id)_$(id)_$gix[arrowhead=vee,]\ng$(g.id)->g$(g.id)_$(id)_$gix[arrowhead=vee,]\n" - # arrow_temp *= "g$(g.id)_$(id)_$gix->$opr_name[arrowhead=vee,]\n" arrow_temp *= "g$(g.id)->g$(id)[arrowhead=vee,label=$gfactor,fontsize=16]\n" else arrow_temp *= "g$(g.id)->g$(id)[arrowhead=vee,]\n" @@ -178,30 +85,14 @@ function to_dotstatic(::Type{ComputationalGraphs.Prod}, id::Int, factor::F, subg return node_temp, arrow_temp end -function to_dotstatic(::Type{ComputationalGraphs.Power{N}}, id::Int, factor::F, subgraphs::Vector{FeynmanGraph{F,W}}, subgraph_factors::Vector{F}) where {N,F,W} +function to_dotstatic(::Type{ComputationalGraphs.Power{N}}, id::Int, subgraphs::Vector{FeynmanGraph{F,W}}, subgraph_factors::Vector{F}) where {N,F,W} node_temp = "" arrow_temp = "" - if factor != 1 - # opr_fac = "factor$(id)[label=$(factor), style=filled, fillcolor=lavender]\n" - # opr_name = "g$(id)_t" - # node_str = "g$(id)[shape=box, label = <⊗>, style=filled, fillcolor=cornsilk,]\n" - # arrow_temp *= "factor$(id)->g$(id)[arrowhead=vee,]\ng$(id)_t->g$(id)[arrowhead=vee,]\n" - # node_temp *= opr_fac * node_str - opr_node = "g$id[shape=box, label = <($factor)*Pow($N)>, style=filled, fillcolor=darkolivegreen,fontsize=18]\n" - else - opr_node = "g$id[shape=box, label = , style=filled, fillcolor=darkolivegreen,fontsize=18]\n" - end - # opr_node = "g$id[shape=box, label = , style=filled, fillcolor=darkolivegreen,]\n" - # order_node = "order$(id)[label=$N, style=filled, fillcolor=lavender]\n" - # node_temp *= opr_node * order_node + # opr_node = "g$id[shape=box, label = <($factor)*Pow($N)>, style=filled, fillcolor=darkolivegreen,fontsize=18]\n" + opr_node = "g$id[shape=box, label = , style=filled, fillcolor=darkolivegreen,fontsize=18]\n" node_temp *= opr_node - # arrow_temp *= "order$(id)->$opr_name[arrowhead=vee,]\n" if subgraph_factors[1] != 1 - # factor_str = "factor$(subgraphs[1].id)_$(id)[label=$(subgraph_factors[1]), style=filled, fillcolor=lavender]\n" - # subg_str = "g$(subgraphs[1].id)_$(id)[shape=box, label = <⊗>, style=filled, fillcolor=cornsilk,]\n" - # node_temp *= factor_str * subg_str - # arrow_temp *= "factor$(subgraphs[1].id)_$(id)->g$(subgraphs[1].id)_$(id)[arrowhead=vee,]\ng$(subgraphs[1].id)->g$(subgraphs[1].id)_$(id)[arrowhead=vee,]\n" - arrow_temp *= "g$(subgraphs[1].id)->$opr_name[arrowhead=vee,label=$gfactor,fontsize=16]\n" + arrow_temp *= "g$(subgraphs[1].id)->$opr_name[arrowhead=vee,label=$(subgraph_factors[1]),fontsize=16]\n" else arrow_temp *= "g$(subgraphs[1].id)->$opr_name[arrowhead=vee,]\n" end @@ -237,31 +128,13 @@ function to_dot_str(graphs::AbstractVector{<:AbstractGraph}, name::String="") if isempty(subgraphs(g)) #leaf g_id in inds_visitedleaf && continue leafname = get_leafname(g, leafidx) - if factor(g) == 1 - gnode_str = "g$g_id[label=<$leafname>, style=filled, fillcolor=paleturquoise,fontsize=18]\n" - body_node *= gnode_str - elseif factor(g) == -1 - # println("BareInteraction with -1 factor!") - # @assert typeof(g.properties) == BareInteractionId - # leafname = "<-V$leafidx>" - # gnode_str = "g$g_id[label=$leafname, style=filled, fillcolor=paleturquoise]\n" - # body_node *= gnode_str - gnode_str = "g$g_id[label=<-$leafname>, style=filled, fillcolor=paleturquoise,fontsize=18]\n" - body_node *= gnode_str - else - # factor_str = "factor$(leafidx)_inp[label=$(factor(g)), style=filled, fillcolor=lavender]\n" - # leaf_node = "l$(leafidx)[label=$leafname, style=filled, fillcolor=paleturquoise]\n" - # gnode_str = "g$g_id[shape=box, label = <⊗>, style=filled, fillcolor=cornsilk,]\n" - gnode_str = "l$(leafidx)[label=<$(factor(g))$leafname>, style=filled, fillcolor=paleturquoise,fontsize=18]\n" - # body_node *= factor_str * leaf_node * gnode_str - # body_node *= gnode_str - # body_arrow *= "factor$(leafidx)_inp->g$g_id[arrowhead=vee,]\nl$(leafidx)->g$g_id[arrowhead=vee,]\n" - end + gnode_str = "g$g_id[label=<$leafname>, style=filled, fillcolor=paleturquoise,fontsize=18]\n" + body_node *= gnode_str leafidx += 1 push!(inds_visitedleaf, g_id) else g_id in inds_visitednode && continue - temp_node, temp_arrow = to_dotstatic(operator(g), g_id, factor(g), subgraphs(g), subgraph_factors(g)) + temp_node, temp_arrow = to_dotstatic(operator(g), g_id, subgraphs(g), subgraph_factors(g)) body_node *= temp_node body_arrow *= temp_arrow push!(inds_visitednode, g_id) @@ -297,10 +170,9 @@ function get_leafname(g, leafidx) if leaftype == BareGreenId leafname = "G$leafidx" - println(leaftype, ": ", leafidx, " ", g.factor, " ", " ", g.properties.extK, " ", g.properties.extT, " ", g.properties.order) + println(leaftype, ": ", leafidx, " ", g.properties.extK, " ", g.properties.extT) elseif leaftype == BareInteractionId - println(leaftype, ": ", leafidx, " ", g.factor, " ", g.properties.response, " ", g.properties.type, - " ", g.properties.permutation, " ", g.properties.extK, " ", g.properties.extT, " ", g.properties.order) + println(leaftype, ": ", leafidx, " ", g.properties.response, " ", g.properties.type, " ", g.properties.extK, " ", g.properties.extT) leafname = "V$leafidx" elseif leaftype == PolarId leafname = "Π$leafidx" diff --git a/src/common_new.jl b/src/common_new.jl deleted file mode 100644 index a680bcd0..00000000 --- a/src/common_new.jl +++ /dev/null @@ -1,250 +0,0 @@ -# struct Interaction -# response::Response -# type::Set{AnalyticProperty} -# function Interaction(response, type) -# return new(response, Set(type)) -# end -# function Interaction(response, type::AnalyticProperty) -# return new(response, Set([type,])) -# end -# end - -# Base.isequal(a::Interaction, b::Interaction) = (a.response == b.response) && issetequal(a.type, b.type) -# Base.:(==)(a::Interaction, b::Interaction) = Base.isequal(a, b) - -# function short(inter::Interaction) -# return "$(short(inter.response))_$(reduce(*, [short(t) for t in inter.type]))" -# end - -# function short(name::Response) -# if name == ChargeCharge -# return "cc" -# elseif name == SpinSpin -# return "σσ" -# elseif name == UpUp -# return "↑↑" -# elseif name == UpDown -# return "↑↓" -# else -# @error("$name is not implemented!") -# end -# end - -# function short(type::AnalyticProperty) -# if type == Instant -# return "Ins" -# elseif type == Dynamic -# return "Dyn" -# elseif type == D_Instant -# return "dIns" -# elseif type == D_Dynamic -# return "dDyn" -# else -# @error("$type is not implemented!") -# end -# end - -# function symbol(name::Response, type::AnalyticProperty, addition=nothing) -# if isnothing(addition) -# return Symbol("$(short(name))$(short(type))") -# else -# return Symbol("$(short(name))$(short(type))$(addition)") -# end -# end - -@with_kw struct DiagramPara{W}#,T<:DiagType} - type::DataType - # type::T - innerLoopNum::Int - extNum::Int = 2 - - isFermi::Bool = true - spin::Int = 2 - # loopDim::Int = 3 - interaction::Vector{Interaction} = [Interaction(ChargeCharge, [Instant,]),] # :ChargeCharge, :SpinSpin, ... - - firstLoopIdx::Int = firstLoopIdx(type, extNum) - totalLoopNum::Int = firstLoopIdx + innerLoopNum - 1 - - #### turn the following parameters on if there is tau variables ######## - hasTau::Bool = false - firstTauIdx::Int = firstTauIdx(type, extNum) - totalTauNum::Int = firstTauIdx + innerTauNum(type, innerLoopNum, interactionTauNum(hasTau, interaction), extNum) - 1 - #if there is no imaginary-time at all, then set this number to zero! - ######################################################################## - filter::Vector{Filter} = [NoHartree,] #usually, the Hartree subdiagram should be removed - transferLoop::Vector{Float64} = [] #Set it to be the transfer momentum/frequency if you want to check the diagrams are proper or not - extra::Any = Nothing -end - -const DiagramParaF64 = DiagramPara{Float64} - -@inline interactionTauNum(para::DiagramPara) = interactionTauNum(para.hasTau, para.interaction) -@inline innerTauNum(para::DiagramPara) = innerTauNum(para.type, para.innerLoopNum, para.interactionTauNum) - -""" - Parameters.reconstruct(p::DiagramPara; kws...) - - Type-stable version of the Parameters.reconstruct -""" -function Parameters.reconstruct(::Type{DiagramPara{W}}, p::DiagramPara{W}, di) where {W} - di = !isa(di, AbstractDict) ? Dict(di) : copy(di) - get(p, di, key) = pop!(di, key, getproperty(p, key)) - return DiagramPara{W}( - # type = pop!(di, :type, p.type), - type=get(p, di, :type), - innerLoopNum=get(p, di, :innerLoopNum), - extNum=get(p, di, :extNum), - isFermi=get(p, di, :isFermi), - spin=get(p, di, :spin), - # loopDim=get(p, di, :loopDim), - interaction=get(p, di, :interaction), - firstLoopIdx=get(p, di, :firstLoopIdx), - totalLoopNum=get(p, di, :totalLoopNum), - hasTau=get(p, di, :hasTau), - firstTauIdx=get(p, di, :firstTauIdx), - totalTauNum=get(p, di, :totalTauNum), - filter=get(p, di, :filter), - transferLoop=get(p, di, :transferLoop), - extra=get(p, di, :extra) - ) - length(di) != 0 && error("Fields $(keys(di)) not in type $T") -end - -function derivepara(p::DiagramPara{W}; kwargs...) where {W} - di = !isa(kwargs, AbstractDict) ? Dict(kwargs) : copy(kwargs) - get(p, di, key) = pop!(di, key, getproperty(p, key)) - return DiagramPara{W}( - # type = pop!(di, :type, p.type), - type=get(p, di, :type), - innerLoopNum=get(p, di, :innerLoopNum), - extNum=get(p, di, :extNum), - isFermi=get(p, di, :isFermi), - spin=get(p, di, :spin), - # loopDim=get(p, di, :loopDim), - interaction=get(p, di, :interaction), - firstLoopIdx=get(p, di, :firstLoopIdx), - totalLoopNum=get(p, di, :totalLoopNum), - hasTau=get(p, di, :hasTau), - firstTauIdx=get(p, di, :firstTauIdx), - totalTauNum=get(p, di, :totalTauNum), - filter=get(p, di, :filter), - transferLoop=get(p, di, :transferLoop), - extra=get(p, di, :extra) - ) - length(di) != 0 && error("Fields $(keys(di)) not in type $T") -end - -function Base.isequal(p::DiagramPara{W}, q::DiagramPara{W}) where {W} - for field in fieldnames(typeof(p)) #fieldnames doesn't include user-defined entries in Base.getproperty - if field == :filter - if Set(p.filter) != Set(q.filter) - return false - end - elseif field == :transferLoop - if (isempty(p.transferLoop) && isempty(q.transferLoop) == false) || (isempty(p.transferLoop) == false && isempty(q.transferLoop)) - return false - elseif isempty(p.transferLoop) == false && isempty(q.transferLoop) == false - if (p.transferLoop ≈ q.transferLoop) == false - return false - end - end - elseif field == :interaction - if (p.interaction ⊆ q.interaction) == false || (q.interaction ⊆ p.interaction) == false - return false - end - else - if Base.getproperty(p, field) != Base.getproperty(q, field) - return false - end - end - end - return true -end - -Base.:(==)(a::DiagramPara{W}, b::DiagramPara{W}) where {W} = Base.isequal(a, b) - -""" - function innerTauNum(type, innerLoopNum, interactionTauNum) - - internal imaginary-time degrees of freedom for a given diagram type and internal loop number. - For the vertex functions (self-energy, polarization, vertex3, and vertex4), innerTauNum is equivalent to tauNum. - For the Green function, tauNum = innerTauNum + external tauNum -""" -function innerTauNum(type, innerLoopNum, interactionTauNum, extN) - if type == VertexDiag && extN == 4 - return (innerLoopNum + 1) * interactionTauNum - elseif type == FermiSelfEnergy - return innerLoopNum * interactionTauNum - elseif type == FermiPropagator - return innerLoopNum * interactionTauNum - elseif type == BoseSelfEnergy - return 1 + innerTauNum(VertexDiag, innerLoopNum - 1, interactionTauNum, extN) - elseif type == VertexDiag && extN == 3 - return 1 + innerTauNum(VertexDiag, innerLoopNum - 1, interactionTauNum, extN) - else - error("not implemented!") - end -end - -# function interactionTauNum(hasTau::Bool, interactionSet) -# if hasTau == false -# return 0 -# end -# for interaction in interactionSet -# if Dynamic in interaction.type || D_Dynamic in interaction.type -# return 2 -# end -# end -# return 1 -# end - -function firstTauIdx(type, extN::Int, offset::Int=0) - if type == FermiPropagator - return 3 + offset - elseif type == VertexDiag && extN == 3 - return 1 + offset - elseif type == BosePropagator - return 1 + offset - else - return 1 + offset - end -end - -function firstLoopIdx(type, extN::Int, offset::Int=0) - if type == VertexDiag && extN == 4 #three extK - return 4 + offset - elseif type == FermiSelfEnergy #one extK - return 2 + offset - elseif type == FermiPropagator #one extK - return 2 + offset - elseif type == BosePropagator #one extK - return 2 + offset - elseif type == VertexDiag && extN == 3 #two extK - return 3 + offset - else - error("not implemented!") - end -end - -function totalTauNum(type, innerLoopNum, interactionTauNum, extNum::Int, offset::Int=0) - return firstTauIdx(type, extNum, offset) + innerTauNum(type, innerLoopNum, interactionTauNum, extNum) - 1 -end - -function totalLoopNum(type, innerLoopNum, extNum::Int, offset::Int=0) - return firstLoopIdx(type, extNum, offset) + innerLoopNum - 1 -end - -# function totalTauNum(para, type::Symbol=:none) -# return para.totalTauNum -# # if type == :Ver4 -# # return (para.internalLoopNum + 1) * para.interactionTauNum -# # else -# # error("not implemented!") -# # end -# end - -# function totalLoopNum(para, type::Symbol=:none) -# return para.totalLoopNum -# end - diff --git a/src/computational_graph/ComputationalGraph.jl b/src/computational_graph/ComputationalGraph.jl index 2ea9d50e..94d59dbd 100644 --- a/src/computational_graph/ComputationalGraph.jl +++ b/src/computational_graph/ComputationalGraph.jl @@ -38,7 +38,7 @@ export multi_product, linear_combination, feynman_diagram, propagator, interacti include("tree_properties.jl") -export haschildren, onechild, isleaf, isbranch, ischain, isfactorless, has_zero_subfactors, eldest, count_operation +export haschildren, onechild, isleaf, isbranch, ischain, has_zero_subfactors, eldest, count_operation include("operation.jl") include("io.jl") diff --git a/src/computational_graph/abstractgraph.jl b/src/computational_graph/abstractgraph.jl index b03530e1..5891a8d1 100644 --- a/src/computational_graph/abstractgraph.jl +++ b/src/computational_graph/abstractgraph.jl @@ -3,7 +3,7 @@ abstract type AbstractGraph end abstract type AbstractOperator end struct Sum <: AbstractOperator end struct Prod <: AbstractOperator end -struct Constant <: AbstractOperator end +struct Unitary <: AbstractOperator end struct Power{N} <: AbstractOperator function Power(N::Int) @assert N ∉ [0, 1] "Power{$N} makes no sense." @@ -19,7 +19,7 @@ apply(o::AbstractOperator, diags) = error("not implemented!") Base.show(io::IO, o::AbstractOperator) = print(io, typeof(o)) Base.show(io::IO, ::Type{Sum}) = print(io, "⨁") Base.show(io::IO, ::Type{Prod}) = print(io, "Ⓧ") -Base.show(io::IO, ::Type{Constant}) = print(io, "C") +Base.show(io::IO, ::Type{Unitary}) = print(io, "𝟙") Base.show(io::IO, ::Type{Power{N}}) where {N} = print(io, "^$N") # Is the unary form of operator 𝓞 trivial: 𝓞(G) ≡ G? @@ -82,13 +82,6 @@ function operator(g::AbstractGraph) """ function operator(g::AbstractGraph) end -""" -function factor(g::AbstractGraph) - - Returns the fixed scalar-multiplicative factor of the computational graph `g`. -""" -function factor(g::AbstractGraph) end - """ function weight(g::AbstractGraph) @@ -184,13 +177,6 @@ function set_operator!(g::AbstractGraph, operator::Type{<:AbstractOperator}) """ function set_operator!(g::AbstractGraph, operator::Type{<:AbstractOperator}) end -""" -function set_factor!(g::AbstractGraph, factor) - - Update the factor of graph `g` to `factor`. -""" -function set_factor!(g::AbstractGraph, factor) end - """ function set_weight!(g::AbstractGraph, weight) @@ -340,7 +326,11 @@ function isequiv(a::AbstractGraph, b::AbstractGraph, args...) # elseif field == :subgraph_factors && getproperty(a, :subgraph_factors) == subgraph_factors(a) && getproperty(b, :subgraph_factors) == subgraph_factors(b) # continue # skip subgraph_factors if already accounted for else - getproperty(a, field) != getproperty(b, field) && return false + # getproperty(a, field) != getproperty(b, field) && return false + if getproperty(a, field) != getproperty(b, field) + # println(field) + return false + end end end return true diff --git a/src/computational_graph/conversions.jl b/src/computational_graph/conversions.jl index d1133291..bb07c3cf 100644 --- a/src/computational_graph/conversions.jl +++ b/src/computational_graph/conversions.jl @@ -9,7 +9,7 @@ - `g` computational graph """ function Base.convert(::Type{G}, g::FeynmanGraph{F,W}) where {F,W,G<:Graph} - return Graph(g.subgraphs; subgraph_factors=g.subgraph_factors, name=g.name, operator=g.operator(), orders=g.orders, ftype=F, wtype=W, factor=g.factor, weight=g.weight) + return Graph(g.subgraphs; subgraph_factors=g.subgraph_factors, name=g.name, operator=g.operator(), orders=g.orders, ftype=F, wtype=W, weight=g.weight) end function Base.convert(::Type{FeynmanGraph}, g::Graph{F,W}) where {F,W} diff --git a/src/computational_graph/eval.jl b/src/computational_graph/eval.jl index 04ca3c97..c6cba91c 100644 --- a/src/computational_graph/eval.jl +++ b/src/computational_graph/eval.jl @@ -1,13 +1,13 @@ -@inline apply(::Type{Sum}, diags::Vector{Graph{F,W}}, factors::Vector{F}) where {F<:Number,W<:Number} = sum(d.weight * d.factor * f for (d, f) in zip(diags, factors)) -@inline apply(::Type{Prod}, diags::Vector{Graph{F,W}}, factors::Vector{F}) where {F<:Number,W<:Number} = prod(d.weight * d.factor * f for (d, f) in zip(diags, factors)) -@inline apply(::Type{Power{N}}, diags::Vector{Graph{F,W}}, factors::Vector{F}) where {N,F<:Number,W<:Number} = (diags[1].weight * diags[1].factor)^N * factors[1] +@inline apply(::Type{Sum}, diags::Vector{Graph{F,W}}, factors::Vector{F}) where {F<:Number,W<:Number} = sum(d.weight * f for (d, f) in zip(diags, factors)) +@inline apply(::Type{Prod}, diags::Vector{Graph{F,W}}, factors::Vector{F}) where {F<:Number,W<:Number} = prod(d.weight * f for (d, f) in zip(diags, factors)) +@inline apply(::Type{Power{N}}, diags::Vector{Graph{F,W}}, factors::Vector{F}) where {N,F<:Number,W<:Number} = (diags[1].weight)^N * factors[1] @inline apply(o::Sum, diag::Graph{F,W}) where {F<:Number,W<:Number} = diag.weight @inline apply(o::Prod, diag::Graph{F,W}) where {F<:Number,W<:Number} = diag.weight @inline apply(o::Power{N}, diag::Graph{F,W}) where {N,F<:Number,W<:Number} = diag.weight -@inline apply(::Type{Sum}, diags::Vector{FeynmanGraph{F,W}}, factors::Vector{F}) where {F<:Number,W<:Number} = sum(d.weight * d.factor * f for (d, f) in zip(diags, factors)) -@inline apply(::Type{Prod}, diags::Vector{FeynmanGraph{F,W}}, factors::Vector{F}) where {F<:Number,W<:Number} = prod(d.weight * d.factor * f for (d, f) in zip(diags, factors)) -@inline apply(::Type{Power{N}}, diags::Vector{FeynmanGraph{F,W}}, factors::Vector{F}) where {N,F<:Number,W<:Number} = (diags[1].weight * diags[1].factor)^N * factors[1] +@inline apply(::Type{Sum}, diags::Vector{FeynmanGraph{F,W}}, factors::Vector{F}) where {F<:Number,W<:Number} = sum(d.weight * f for (d, f) in zip(diags, factors)) +@inline apply(::Type{Prod}, diags::Vector{FeynmanGraph{F,W}}, factors::Vector{F}) where {F<:Number,W<:Number} = prod(d.weight * f for (d, f) in zip(diags, factors)) +@inline apply(::Type{Power{N}}, diags::Vector{FeynmanGraph{F,W}}, factors::Vector{F}) where {N,F<:Number,W<:Number} = (diags[1].weight)^N * factors[1] @inline apply(o::Sum, diag::FeynmanGraph{F,W}) where {F<:Number,W<:Number} = diag.weight @inline apply(o::Prod, diag::FeynmanGraph{F,W}) where {F<:Number,W<:Number} = diag.weight @inline apply(o::Power{N}, diag::FeynmanGraph{F,W}) where {N,F<:Number,W<:Number} = diag.weight @@ -33,26 +33,34 @@ function eval!(g::Graph{F,W}, leafmap::Dict{Int,Int}=Dict{Int,Int}(), leaf::Vect else node.weight = apply(node.operator, node.subgraphs, node.subgraph_factors) end - result = node.weight * node.factor + result = node.weight end return result end -function eval!(g::FeynmanGraph{F,W}, leafmap::Dict{Int,Int}=Dict{Int,Int}(), leaf::Vector{W}=Vector{W}()) where {F,W} +function eval!(g::FeynmanGraph{F,W}, leafmap::Dict{Int,Int}=Dict{Int,Int}(), leaf::Vector{W}=Vector{W}(); inherit=false, randseed::Int=-1) where {F,W} result = nothing - + if randseed > 0 + Random.seed!(randseed) + end for node in PostOrderDFS(g) if isleaf(node) - if isempty(leafmap) - node.weight = 1.0 - else - node.weight = leaf[leafmap[node.id]] + if !inherit + if isempty(leafmap) + if randseed < 0 + node.weight = 1.0 + else + node.weight = rand() + end + else + node.weight = leaf[leafmap[node.id]] + end end else node.weight = apply(node.operator, node.subgraphs, node.subgraph_factors) end - result = node.weight * node.factor + result = node.weight end return result end diff --git a/src/computational_graph/feynmangraph.jl b/src/computational_graph/feynmangraph.jl index a276a823..d3a38206 100644 --- a/src/computational_graph/feynmangraph.jl +++ b/src/computational_graph/feynmangraph.jl @@ -42,7 +42,6 @@ Base.:(==)(a::FeynmanProperties, b::FeynmanProperties) = Base.isequal(a, b) Returns a copy of the given FeynmanProperties `p` modified to have no topology. """ drop_topology(p::FeynmanProperties) = FeynmanProperties(p.diagtype, p.vertices, [], p.external_indices, p.external_legs) - """ mutable struct FeynmanGraph{F<:Number,W} @@ -56,7 +55,6 @@ drop_topology(p::FeynmanProperties) = FeynmanProperties(p.diagtype, p.vertices, - `subgraphs::Vector{FeynmanGraph{F,W}}` vector of sub-diagrams - `subgraph_factors::Vector{F}` scalar multiplicative factors associated with each subdiagram - `operator::DataType` node operation (Sum, Prod, etc.) -- `factor::F` a number representing the total scalar multiplicative factor for the diagram. - `weight::W` weight of the diagram # Example: @@ -81,7 +79,6 @@ mutable struct FeynmanGraph{F<:Number,W} <: AbstractGraph # FeynmanGraph subgraph_factors::Vector{F} operator::DataType - factor::F weight::W """ @@ -120,7 +117,13 @@ mutable struct FeynmanGraph{F<:Number,W} <: AbstractGraph # FeynmanGraph vertices = [external_operators(g) for g in subgraphs if diagram_type(g) != Propagator] end properties = FeynmanProperties(typeof(diagtype), vertices, topology, external_indices, external_legs) - return new{ftype,wtype}(uid(), name, orders, properties, subgraphs, subgraph_factors, typeof(operator), factor, weight) + + g = new{ftype,wtype}(uid(), String(name), orders, properties, subgraphs, subgraph_factors, typeof(operator), weight) + if factor ≈ one(ftype) + return g + else + return new{ftype,wtype}(uid(), String(name), orders, properties, [g,], [factor,], Prod, weight * factor) + end end """ @@ -150,7 +153,12 @@ mutable struct FeynmanGraph{F<:Number,W} <: AbstractGraph # FeynmanGraph @assert length(subgraphs) == 1 "FeynmanGraph with Power operator must have one and only one subgraph." end # @assert allunique(subgraphs) "all subgraphs must be distinct." - return new{ftype,wtype}(uid(), name, orders, properties, subgraphs, subgraph_factors, typeof(operator), factor, weight) + g = new{ftype,wtype}(uid(), String(name), orders, properties, subgraphs, subgraph_factors, typeof(operator), weight) + if factor ≈ one(ftype) + return g + else + return new{ftype,wtype}(uid(), String(name), orders, properties, [g,], [factor,], Prod, weight * factor) + end end """ @@ -165,7 +173,8 @@ mutable struct FeynmanGraph{F<:Number,W} <: AbstractGraph # FeynmanGraph function FeynmanGraph(g::Graph{F,W}, properties::FeynmanProperties) where {F,W} @assert length(properties.external_indices) == length(properties.external_legs) # @assert allunique(subgraphs) "all subgraphs must be distinct." - return new{F,W}(uid(), g.name, g.orders, properties, g.subgraphs, g.subgraph_factors, g.operator, g.factor, g.weight) + # return new{F,W}(uid(), g.name, g.orders, properties, g.subgraphs, g.subgraph_factors, g.operator, g.weight) + return new{F,W}(uid(), g.name, g.orders, properties, [FeynmanGraph(subg, subg.properties) for subg in g.subgraphs], g.subgraph_factors, g.operator, g.weight) end end @@ -176,7 +185,6 @@ id(g::FeynmanGraph) = g.id name(g::FeynmanGraph) = g.name orders(g::FeynmanGraph) = g.orders operator(g::FeynmanGraph) = g.operator -factor(g::FeynmanGraph) = g.factor weight(g::FeynmanGraph) = g.weight subgraph(g::FeynmanGraph, i=1) = g.subgraphs[i] subgraphs(g::FeynmanGraph) = g.subgraphs @@ -191,7 +199,6 @@ set_name!(g::FeynmanGraph, name::String) = (g.name = name) set_orders!(g::FeynmanGraph, orders::Vector{Int}) = (g.orders = orders) set_operator!(g::FeynmanGraph, operator::Type{<:AbstractOperator}) = (g.operator = operator) set_operator!(g::FeynmanGraph, operator::AbstractOperator) = (g.operator = typeof(operator)) -set_factor!(g::FeynmanGraph{F,W}, factor) where {F,W} = (g.factor = F(factor)) set_weight!(g::FeynmanGraph{F,W}, weight) where {F,W} = (g.weight = W(weight)) set_subgraph!(g::FeynmanGraph{F,W}, subgraph::FeynmanGraph{F,W}, i=1) where {F,W} = (g.subgraphs[i] = subgraph) set_subgraphs!(g::FeynmanGraph{F,W}, subgraphs::Vector{FeynmanGraph{F,W}}) where {F,W} = (g.subgraphs = subgraphs) @@ -299,7 +306,6 @@ function Base.:*(g1::FeynmanGraph{F,W}, c2) where {F,W} # Convert trivial unary link to in-place form if unary_istrivial(g1) && onechild(g1) g.subgraph_factors[1] *= g1.subgraph_factors[1] - # g.subgraph_factors[1] *= g1.subgraph_factors[1] * g1.factor g.subgraphs = g1.subgraphs end return g @@ -319,7 +325,6 @@ function Base.:*(c1, g2::FeynmanGraph{F,W}) where {F,W} # Convert trivial unary link to in-place form if unary_istrivial(g2) && onechild(g2) g.subgraph_factors[1] *= g2.subgraph_factors[1] - # g.subgraph_factors[1] *= g2.subgraph_factors[1] * g2.factor g.subgraphs = g2.subgraphs end return g @@ -352,16 +357,15 @@ function linear_combination(g1::FeynmanGraph{F,W}, g2::FeynmanGraph{F,W}, c1=F(1 # Convert trivial unary links to in-place form if unary_istrivial(g1) && onechild(g1) subgraph_factors[1] *= g1.subgraph_factors[1] - # subgraph_factors[1] *= g1.subgraph_factors[1] * g1.factor subgraphs[1] = g1.subgraphs[1] end if unary_istrivial(g2) && onechild(g2) subgraph_factors[2] *= g2.subgraph_factors[1] - # subgraph_factors[2] *= g2.subgraph_factors[1] * g2.factor subgraphs[2] = g2.subgraphs[1] end - if subgraphs[1] == subgraphs[2] + if subgraphs[1].id == subgraphs[2].id + # if isequiv(subgraphs[1], subgraphs[2], :id) g = FeynmanGraph([subgraphs[1]], properties; subgraph_factors=[sum(subgraph_factors)], operator=Sum(), orders=orders(g1), ftype=F, wtype=W) else g = FeynmanGraph(subgraphs, properties; subgraph_factors=subgraph_factors, operator=Sum(), orders=orders(g1), ftype=F, wtype=W) @@ -403,14 +407,13 @@ function linear_combination(graphs::Vector{FeynmanGraph{F,W}}, constants::Abstra for (i, sub_g) in enumerate(graphs) if unary_istrivial(sub_g) && onechild(sub_g) subgraph_factors[i] *= sub_g.subgraph_factors[1] - # subgraph_factors[i] *= sub_g.subgraph_factors[1] * sub_g.factor subgraphs[i] = sub_g.subgraphs[1] end end unique_graphs = FeynmanGraph{F,W}[] unique_factors = F[] for (idx, g) in enumerate(subgraphs) - i = findfirst(isequal(g), unique_graphs) + i = findfirst(isequal(g.id), id.(unique_graphs)) if isnothing(i) push!(unique_graphs, g) push!(unique_factors, subgraph_factors[idx]) diff --git a/src/computational_graph/graph.jl b/src/computational_graph/graph.jl index b5b14660..ce0e61d3 100644 --- a/src/computational_graph/graph.jl +++ b/src/computational_graph/graph.jl @@ -10,7 +10,6 @@ - `subgraphs::Vector{Graph{F,W}}` vector of sub-diagrams - `subgraph_factors::Vector{F}` scalar multiplicative factors associated with each subgraph. Note that the subgraph factors may be manipulated algebraically. To associate a fixed multiplicative factor with this graph which carries some semantic meaning, use the `factor` argument instead. - `operator::DataType` node operation. Addition and multiplication are natively supported via operators Sum and Prod, respectively. Should be a concrete subtype of `AbstractOperator`. -- `factor::F` a number representing the total scalar multiplicative factor for the diagram. - `weight::W` the weight of this node - `properties::Any` extra information of Green's functions. @@ -35,7 +34,6 @@ mutable struct Graph{F<:Number,W} <: AbstractGraph # Graph subgraph_factors::Vector{F} operator::DataType - factor::F weight::W properties::Any @@ -56,14 +54,20 @@ mutable struct Graph{F<:Number,W} <: AbstractGraph # Graph - `factor` fixed scalar multiplicative factor for this diagram (e.g., a permutation sign) - `weight` the weight of this node """ - function Graph(subgraphs::AbstractVector; subgraph_factors=one.(eachindex(subgraphs)), name="", operator::AbstractOperator=Sum(), - orders=zeros(Int, 16), ftype=_dtype.factor, wtype=_dtype.weight, factor=one(ftype), weight=zero(wtype), properties=nothing + function Graph(subgraphs::AbstractVector; factor=one(_dtype.factor), subgraph_factors=one.(eachindex(subgraphs)), name="", operator::AbstractOperator=Sum(), + orders=zeros(Int, 16), ftype=_dtype.factor, wtype=_dtype.weight, weight=zero(wtype), properties=nothing ) if typeof(operator) <: Power @assert length(subgraphs) == 1 "Graph with Power operator must have one and only one subgraph." end # @assert allunique(subgraphs) "all subgraphs must be distinct." - return new{ftype,wtype}(uid(), name, orders, subgraphs, subgraph_factors, typeof(operator), factor, weight, properties) + g = new{ftype,wtype}(uid(), String(name), orders, subgraphs, subgraph_factors, typeof(operator), weight, properties) + + if factor ≈ one(ftype) + return g + else + return new{ftype,wtype}(uid(), String(name), orders, [g,], [factor,], Prod, weight * factor, properties) + end end end @@ -74,7 +78,6 @@ id(g::Graph) = g.id name(g::Graph) = g.name orders(g::Graph) = g.orders operator(g::Graph) = g.operator -factor(g::Graph) = g.factor weight(g::Graph) = g.weight properties(g::Graph) = g.properties subgraph(g::Graph, i=1) = g.subgraphs[i] @@ -90,7 +93,6 @@ set_name!(g::Graph, name::String) = (g.name = name) set_orders!(g::Graph, orders::Vector{Int}) = (g.orders = orders) set_operator!(g::Graph, operator::Type{<:AbstractOperator}) = (g.operator = operator) set_operator!(g::Graph, operator::AbstractOperator) = (g.operator = typeof(operator)) -set_factor!(g::Graph{F,W}, factor) where {F,W} = (g.factor = F(factor)) set_weight!(g::Graph{F,W}, weight) where {F,W} = (g.weight = W(weight)) set_properties!(g::Graph, properties) = (g.properties = properties) set_subgraph!(g::Graph{F,W}, subgraph::Graph{F,W}, i=1) where {F,W} = (g.subgraphs[i] = subgraph) @@ -111,7 +113,12 @@ set_subgraph_factors!(g::Graph{F,W}, subgraph_factors::AbstractVector, indices:: - `f`: constant factor """ function constant_graph(factor=one(_dtype.factor)) - return Graph([]; operator=Constant(), factor=factor, ftype=_dtype.factor, wtype=_dtype.weight, weight=one(_dtype.weight)) + g = Graph([]; operator=Unitary(), ftype=_dtype.factor, wtype=_dtype.weight, weight=one(_dtype.weight)) + if factor ≈ one(_dtype.factor) + return g + else + return g * factor + end end """ @@ -128,7 +135,6 @@ function Base.:*(g1::Graph{F,W}, c2) where {F,W} # Convert trivial unary link to in-place form if unary_istrivial(g1) && onechild(g1) g.subgraph_factors[1] *= g1.subgraph_factors[1] - # g.subgraph_factors[1] *= g1.subgraph_factors[1] * g1.factor g.subgraphs = g1.subgraphs end return g @@ -148,7 +154,6 @@ function Base.:*(c1, g2::Graph{F,W}) where {F,W} # Convert trivial unary link to in-place form if unary_istrivial(g2) && onechild(g2) g.subgraph_factors[1] *= g2.subgraph_factors[1] - # g.subgraph_factors[1] *= g2.subgraph_factors[1] * g2.factor g.subgraphs = g2.subgraphs end return g @@ -182,16 +187,14 @@ function linear_combination(g1::Graph{F,W}, g2::Graph{F,W}, c1=F(1), c2=F(1)) wh # Convert trivial unary links to in-place form if unary_istrivial(g1) && onechild(g1) subgraph_factors[1] *= g1.subgraph_factors[1] - # subgraph_factors[1] *= g1.subgraph_factors[1] * g1.factor subgraphs[1] = g1.subgraphs[1] end if unary_istrivial(g2) && onechild(g2) subgraph_factors[2] *= g2.subgraph_factors[1] - # subgraph_factors[2] *= g2.subgraph_factors[1] * g2.factor subgraphs[2] = g2.subgraphs[1] end - if subgraphs[1] == subgraphs[2] + if subgraphs[1].id == subgraphs[2].id g = Graph([subgraphs[1]]; subgraph_factors=[sum(subgraph_factors)], operator=Sum(), orders=orders(g1), ftype=F, wtype=W) else g = Graph(subgraphs; subgraph_factors=subgraph_factors, operator=Sum(), orders=orders(g1), ftype=F, wtype=W) @@ -232,7 +235,6 @@ function linear_combination(graphs::Vector{Graph{F,W}}, constants::AbstractVecto for (i, sub_g) in enumerate(graphs) if unary_istrivial(sub_g) && onechild(sub_g) subgraph_factors[i] *= sub_g.subgraph_factors[1] - # subgraph_factors[i] *= sub_g.subgraph_factors[1] * sub_g.factor subgraphs[i] = sub_g.subgraphs[1] end end @@ -240,7 +242,7 @@ function linear_combination(graphs::Vector{Graph{F,W}}, constants::AbstractVecto unique_graphs = Graph{F,W}[] unique_factors = F[] for (idx, g) in enumerate(subgraphs) - i = findfirst(isequal(g), unique_graphs) + i = findfirst(isequal(g.id), id.(unique_graphs)) if isnothing(i) push!(unique_graphs, g) push!(unique_factors, subgraph_factors[idx]) @@ -305,16 +307,14 @@ function multi_product(g1::Graph{F,W}, g2::Graph{F,W}, c1=F(1), c2=F(1)) where { # Convert trivial unary links to in-place form if unary_istrivial(g1) && onechild(g1) subgraph_factors[1] *= g1.subgraph_factors[1] - # subgraph_factors[1] *= g1.subgraph_factors[1] * g1.factor subgraphs[1] = g1.subgraphs[1] end if unary_istrivial(g2) && onechild(g2) subgraph_factors[2] *= g2.subgraph_factors[1] - # subgraph_factors[2] *= g2.subgraph_factors[1] * g2.factor subgraphs[2] = g2.subgraphs[1] end - if subgraphs[1] == subgraphs[2] + if subgraphs[1].id == subgraphs[2].id g = Graph([subgraphs[1]]; subgraph_factors=[prod(subgraph_factors)], operator=Power(2), orders=2 * orders(g1), ftype=F, wtype=W) else if length(g1.orders) > length(g2.orders) @@ -356,7 +356,6 @@ function multi_product(graphs::Vector{Graph{F,W}}, constants::AbstractVector=one for (i, sub_g) in enumerate(graphs) if unary_istrivial(sub_g) && onechild(sub_g) subgraph_factors[i] *= sub_g.subgraph_factors[1] - # subgraph_factors[i] *= sub_g.subgraph_factors[1] * sub_g.factor subgraphs[i] = sub_g.subgraphs[1] end sub_g.orders = [orders(sub_g); zeros(Int, maxlen_orders - length(orders(sub_g)))] @@ -367,7 +366,7 @@ function multi_product(graphs::Vector{Graph{F,W}}, constants::AbstractVector=one unique_factors = F[] repeated_counts = Int[] for (idx, g) in enumerate(subgraphs) - loc = findfirst(isequal(g), unique_graphs) + loc = findfirst(isequal(g.id), id.(unique_graphs)) if isnothing(loc) push!(unique_graphs, g) push!(unique_factors, subgraph_factors[idx]) diff --git a/src/computational_graph/io.jl b/src/computational_graph/io.jl index 7d321d02..112105f1 100644 --- a/src/computational_graph/io.jl +++ b/src/computational_graph/io.jl @@ -34,21 +34,22 @@ function _idstring(graph::AbstractGraph) return string(id(graph), _namestr(graph)) end -function _idstring(graph::FeynmanGraph) +function _idstring(graph::FeynmanGraph) return string(id(graph), _namestr(graph), ":", _ops_to_str(vertices(graph))) end function _stringrep(graph::AbstractGraph, color=true) idstr = _idstring(graph) - fstr = short(factor(graph), one(factor(graph))) + # fstr = short(factor(graph), one(factor(graph))) wstr = short(weight(graph)) ostr = short_orders(orders(graph)) # =$(node.weight*(2π)^(3*node.id.para.innerLoopNum)) if length(subgraphs(graph)) == 0 - return isempty(fstr) ? "$(idstr)$(ostr)=$wstr" : "$(idstr)⋅$(fstr)=$wstr" + # return isempty(fstr) ? "$(idstr)$(ostr)=$wstr" : "$(idstr)⋅$(fstr)=$wstr" + return "$(idstr)$(ostr)=$wstr" else - return "$(idstr)$(ostr)=$wstr=$(fstr)$(operator(graph)) " + return "$(idstr)$(ostr)=$wstr=$(operator(graph)) " end end diff --git a/src/computational_graph/operation.jl b/src/computational_graph/operation.jl index a7b8f85a..4cc1907f 100644 --- a/src/computational_graph/operation.jl +++ b/src/computational_graph/operation.jl @@ -35,9 +35,8 @@ function linear_combination_number_with_graph(g::Vector{Union{F,Graph{F,W}}}, co push!(subcoeff, 1.0) end result = linear_combination(subgraphs, subcoeff) - #result.factor *= d.factor elseif !isnothing(subnumber) #if only numbers appear in derivative, return a number - result = subnumber #* d.factor + result = subnumber end return result #return subgraphs, subnumber, subcoeff @@ -257,7 +256,7 @@ function backAD(diag::Graph{F,W}, debug::Bool=false) where {F,W} result = Dict{Tuple{Int,Int},Graph{F,W}}() parents = all_parent(diag) for d in Leaves(diag)#PreOrderDFS(diag) # preorder traversal will visit all parents first - if d.operator == Constant || haskey(dual, d.id) + if d.operator == Unitary || haskey(dual, d.id) continue end recursive_backAD!(d, parents, dual, result, diag.id) @@ -391,7 +390,7 @@ function forwardAD_root!(graphs::AbstractVector{G}, idx::Int=1, dual[key_node].subgraph_factors = node.subgraph_factors dual[key_node].name = node.name else - dual[key_node] = Graph(nodes_deriv; subgraph_factors=node.subgraph_factors, factor=node.factor) + dual[key_node] = Graph(nodes_deriv; subgraph_factors=node.subgraph_factors) end elseif node.operator == Prod nodes_deriv = G[] @@ -416,7 +415,7 @@ function forwardAD_root!(graphs::AbstractVector{G}, idx::Int=1, dual[key_node].subgraph_factors = one.(eachindex(nodes_deriv)) dual[key_node].name = node.name else - dual[key_node] = Graph(nodes_deriv; factor=node.factor) + dual[key_node] = Graph(nodes_deriv) end elseif node.operator <: Power # node with Power operator has only one subgraph! nodes_deriv = G[] @@ -437,7 +436,7 @@ function forwardAD_root!(graphs::AbstractVector{G}, idx::Int=1, dual[key_node].name = node.name dual.operator = Prod else - dual[key_node] = Graph(nodes_deriv; subgraph_factors=[1, node.subgraph_factors[1]], operator=Prod(), factor=node.factor) + dual[key_node] = Graph(nodes_deriv; subgraph_factors=[1, node.subgraph_factors[1]], operator=Prod()) end end end diff --git a/src/computational_graph/optimize.jl b/src/computational_graph/optimize.jl index 78fe6584..67ccfa26 100644 --- a/src/computational_graph/optimize.jl +++ b/src/computational_graph/optimize.jl @@ -403,7 +403,7 @@ function burn_from_targetleaves!(graphs::AbstractVector{G}, targetleaves_id::Abs verbose > 0 && println("remove all nodes connected to the target leaves via Prod operators.") graphs_sum = linear_combination(graphs, one.(eachindex(graphs))) - ftype = typeof(factor(graphs[1])) + ftype = eltype(subgraph_factors(graphs[1])) for leaf in Leaves(graphs_sum) if !isdisjoint(id(leaf), targetleaves_id) @@ -435,16 +435,19 @@ function burn_from_targetleaves!(graphs::AbstractVector{G}, targetleaves_id::Abs end end - g_c0 = constant_graph(ftype(0)) + # g_c0 = constant_graph(ftype(0)) + g_c1 = constant_graph(ftype(1)) has_c0 = false for g in graphs if name(g) == "BURNING" has_c0 = true - set_id!(g, id(g_c0)) - set_operator!(g, Constant) - set_factor!(g, ftype(0)) + set_id!(g, id(g_c1)) + set_operator!(g, Unitary) + # set_subgraphs!(g, subgraphs(g_c0)) + # set_subgraph_factors!(g, subgraph_factors(g_c0)) + set_weight!(g, 0.0) end end - has_c0 ? (return id(g_c0)) : (return nothing) + has_c0 ? (return id(g_c1)) : (return nothing) end \ No newline at end of file diff --git a/src/computational_graph/transform.jl b/src/computational_graph/transform.jl index a59df941..a763167b 100644 --- a/src/computational_graph/transform.jl +++ b/src/computational_graph/transform.jl @@ -498,10 +498,11 @@ function merge_multi_product!(g::Graph{F,W}) where {F,W} end end - if length(unique_factors) == 1 + if length(unique_factors) == 1 && repeated_counts[1] > 1 g.subgraphs = unique_graphs g.subgraph_factors = unique_factors g.operator = typeof(Power(repeated_counts[1])) + # g.operator = repeated_counts[1] == 1 ? Prod : typeof(Power(repeated_counts[1])) else _subgraphs = Vector{Graph{F,W}}() for (idx, g) in enumerate(unique_graphs) diff --git a/src/computational_graph/tree_properties.jl b/src/computational_graph/tree_properties.jl index 4ab3c0eb..9112840d 100644 --- a/src/computational_graph/tree_properties.jl +++ b/src/computational_graph/tree_properties.jl @@ -80,23 +80,23 @@ function ischain(g::AbstractGraph) return false end -""" - function isfactorless(g) - - Returns whether the graph g is factorless, i.e., has unity factor and, if applicable, - 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`. - -# Arguments: -- `g::AbstractGraph`: graph to be analyzed -""" -function isfactorless(g::AbstractGraph) - if isleaf(g) - return isapprox_one(factor(g)) - else - return all(isapprox_one.([factor(g); subgraph_factors(g)])) - end -end +# """ +# function isfactorless(g) + +# Returns whether the graph g is factorless, i.e., has unity factor and, if applicable, +# 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`. + +# # Arguments: +# - `g::AbstractGraph`: graph to be analyzed +# """ +# function isfactorless(g::AbstractGraph) +# if isleaf(g) +# return isapprox_one(factor(g)) +# else +# return all(isapprox_one.([factor(g); subgraph_factors(g)])) +# end +# end """ function has_zero_subfactors(g) diff --git a/src/diagram_tree/DiagTree.jl b/src/diagram_tree/DiagTree.jl deleted file mode 100644 index d1f0070b..00000000 --- a/src/diagram_tree/DiagTree.jl +++ /dev/null @@ -1,46 +0,0 @@ -module DiagTree - -# if isdefined(Base, :Experimental) && isdefined(Base.Experimental, Symbol("@optlevel")) -# @eval Base.Experimental.@optlevel 1 -# end - -using AbstractTrees -using Printf, PyCall, DataFrames - -@enum TwoBodyChannel Alli = 1 PHr PHEr PPr AnyChan -@enum Permutation Di = 1 Ex DiEx - -export TwoBodyChannel, Alli, PHr, PHEr, PPr, AnyChan -export Permutation, Di, Ex, DiEx - -Base.length(r::TwoBodyChannel) = 1 -Base.iterate(r::TwoBodyChannel) = (r, nothing) -function Base.iterate(r::TwoBodyChannel, ::Nothing) end - -Base.length(r::Permutation) = 1 -Base.iterate(r::Permutation) = (r, nothing) -function Base.iterate(r::Permutation, ::Permutation) end - -include("common.jl") -include("traits.jl") -include("tree.jl") -include("operation.jl") -include("io.jl") -include("eval.jl") -include("optimize.jl") - -const INL, OUTL, INR, OUTR = 1, 2, 3, 4 - -export Diagram -export addSubDiagram! -export toDataFrame -export evalDiagTree! -export evalDiagTreeKT! -export Operator, Sum, Prod -export DiagramId, GenericId, Ver4Id, Ver3Id, GreenId, SigmaId, PolarId -export PropagatorId, BareGreenId, BareInteractionId -export BareGreenNId, BareHoppingId, GreenNId, ConnectedGreenNId -export uidreset, toDataFrame, mergeby, plot_tree -export isleaf - -end \ No newline at end of file diff --git a/src/diagram_tree/common.jl b/src/diagram_tree/common.jl deleted file mode 100644 index 11836f9b..00000000 --- a/src/diagram_tree/common.jl +++ /dev/null @@ -1,64 +0,0 @@ -import ..Filter -import ..Wirreducible #remove all polarization subdiagrams -import ..Girreducible #remove all self-energy inseration -import ..NoHartree -import ..NoFock -import ..NoBubble # true to remove all bubble subdiagram -import ..Proper #ver4, ver3, and polarization diagrams may require to be irreducible along the transfer momentum/frequency - -import ..DiagramType -import ..GreenDiag -import ..SigmaDiag -import ..PolarDiag -import ..Ver3Diag -import ..Ver4Diag -import ..GnDiag -import ..GcDiag - -import ..Composite -import ..ChargeCharge -import ..SpinSpin -import ..UpUp -import ..UpDown -import ..Response - -import ..Instant -import ..Dynamic -import ..D_Instant -import ..D_Dynamic -import ..AnalyticProperty - -import ..symbol -import ..short - -import ..Interaction - -import ..DiagPara - -import ..innerTauNum - -# unique id -# uid() = abs(rand(Int)) % 10000 - -# let z = 0 -# global function uid() -# z += 1 -# return z -# end -# end -const _counter = [0,] - -function uid() - _counter[1] += 1 - return _counter[1] -end - -function uidreset() - _counter[1] = 0 -end - -function getK(loopNum::Int, loopIdx::Int) - k = zeros(loopNum) - k[loopIdx] = 1.0 - return k -end diff --git a/src/diagram_tree/eval.jl b/src/diagram_tree/eval.jl deleted file mode 100644 index 4e8d9bb0..00000000 --- a/src/diagram_tree/eval.jl +++ /dev/null @@ -1,95 +0,0 @@ -@inline apply(o::Sum, diags::Vector{Diagram{W}}) where {W<:Number} = sum(d.weight for d in diags) -@inline apply(o::Prod, diags::Vector{Diagram{W}}) where {W<:Number} = prod(d.weight for d in diags) -@inline apply(o::Sum, diag::Diagram{W}) where {W<:Number} = diag.weight -@inline apply(o::Prod, diag::Diagram{W}) where {W<:Number} = diag.weight - -@inline eval(d::DiagramId) = error("eval for $d has not yet implemented!") - -######################### evaluator for KT representation ######################### -function evalDiagNodeKT!(diag::Diagram, varK, varT, additional=nothing; eval=DiagTree.eval) - if length(diag.subdiagram) == 0 - # if hasproperty(diag.id, :extK) - if (isnothing(varK) == false) && (isnothing(varT) == false) - K = varK * diag.id.extK - if isnothing(additional) - diag.weight = eval(diag.id, K, diag.id.extT, varT) * diag.factor - else - diag.weight = eval(diag.id, K, diag.id.extT, varT, additional) * diag.factor - end - elseif isnothing(varK) - if isnothing(additional) - diag.weight = eval(diag.id, diag.id.extT, varT) * diag.factor - else - diag.weight = eval(diag.id, diag.id.extT, varT, additional) * diag.factor - end - elseif isnothing(varT) - K = varK * diag.id.extK - if isnothing(additional) - diag.weight = eval(diag.id, K) * diag.factor - else - diag.weight = eval(diag.id, K, additional) * diag.factor - end - else - if isnothing(additional) - diag.weight = eval(diag.id) * diag.factor - else - diag.weight = eval(diag.id, additional) * diag.factor - end - end - else - diag.weight = apply(diag.operator, diag.subdiagram) * diag.factor - end - return diag.weight -end - -function evalKT!(diag::Diagram, varK, varT; eval=DiagTree.eval) - for d in PostOrderDFS(diag) - evalDiagNodeKT!(d, varK, varT; eval=eval) - end - return diag.weight -end - -function evalKT!(diags::Vector{Diagram{W}}, varK, varT; eval=DiagTree.eval) where {W} - for d in diags - evalKT!(d, varK, varT; eval=eval) - end - # return W[d.weight for d in diags] -end - -function evalKT!(df::DataFrame, varK, varT; eval=DiagTree.eval) - for d in df[!, :diagram] - evalKT!(d, varK, varT; eval=eval) - end - # return W[d.weight for d in df[!, :Diagram]] -end - -######################### generic evaluator ######################### -function evalDiagNode!(diag::Diagram, vargs...; eval=DiagTree.eval) - if length(diag.subdiagram) == 0 - diag.weight = eval(diag.id, vargs...) * diag.factor - else - diag.weight = apply(diag.operator, diag.subdiagram) * diag.factor - end - return diag.weight -end - -function eval!(diag::Diagram, vargs...; eval=DiagTree.eval) - for d in PostOrderDFS(diag) - evalDiagNode!(d, vargs...; eval=eval) - end - return diag.weight -end - -function eval!(diags::Vector{Diagram{W}}, vargs...; eval=DiagTree.eval) where {W} - for d in diags - eval!(d, vargs...; eval=eval) - end - # return W[d.weight for d in diags] -end - -function eval!(df::DataFrame, vargs...; eval=DiagTree.eval) - for d in df[!, :diagram] - eval!(d, vargs...; eval=eval) - end - # return W[d.weight for d in df[!, :Diagram]] -end \ No newline at end of file diff --git a/src/diagram_tree/io.jl b/src/diagram_tree/io.jl deleted file mode 100644 index 0ea1f4f6..00000000 --- a/src/diagram_tree/io.jl +++ /dev/null @@ -1,227 +0,0 @@ -# function toDict(diag::Diagram; maxdepth::Int) -# @assert maxdepth == 1 "deep convert has not yet been implemented!" - -# d = Dict{Symbol,Any}() -# d[:hash] = diag.hash -# d[:id] = diag.id -# d[:name] = diag.name -# d[:diagram] = diag -# d[:subdiagram] = Tuple(d.hash for d in diag.subdiagram) -# d[:operator] = diag.operator -# d[:factor] = diag.factor -# d[:weight] = diag.weight - -# return d -# end - -function _addkey!(dict, key, val) - @assert haskey(dict, key) == false "key already exists!" - dict[key] = val -end - -function _DiagtoDict!(dict::Dict{Symbol,Any}, diagVec::Vector{Diagram{W}}; maxdepth::Int) where {W} - @assert maxdepth == 1 "deep convert has not yet been implemented!" - _addkey!(dict, :hash, [diag.hash for diag in diagVec]) - _addkey!(dict, :id, [diag.id for diag in diagVec]) - _addkey!(dict, :name, [diag.name for diag in diagVec]) - _addkey!(dict, :diagram, diagVec) - _addkey!(dict, :subdiagram, [Tuple(d.hash for d in diag.subdiagram) for diag in diagVec]) - _addkey!(dict, :operator, [diag.operator for diag in diagVec]) - _addkey!(dict, :factor, [diag.factor for diag in diagVec]) - _addkey!(dict, :weight, [diag.weight for diag in diagVec]) - return dict -end - -# function toDict(v::DiagramId) -# d = Dict{Symbol,Any}() -# for field in fieldnames(typeof(v)) -# data = getproperty(v, field) -# #DataFrame will expand a vector into multiple rows. To prevent it, we transform all vectors into tuples -# d[field] = data isa AbstractVector ? Tuple(data) : data -# end -# return d -# end - -function _vec2tup(data) - return data isa AbstractVector ? Tuple(data) : data -end - -function _IdstoDict!(dict::Dict{Symbol,Any}, diagVec::Vector{Diagram{W}}, idkey::Symbol) where {W} - sameId = all(x -> (typeof(x.id) == typeof(diagVec[1].id)), diagVec) - if sameId - data = [_vec2tup(getproperty(diagVec[1].id, idkey)),] - for idx in 2:length(diagVec) - push!(data, _vec2tup(getproperty(diagVec[idx].id, idkey))) - end - else - data = Vector{Any}() - for diag in diagVec - if hasproperty(diag.id, idkey) - tup = _vec2tup(getproperty(diag.id, idkey)) - # println(tup) - push!(data, tup) - else - push!(data, missing) - end - end - end - _addkey!(dict, idkey, data) - return dict -end - -function toDataFrame(diagVec::AbstractVector, idkey::Symbol; maxdepth::Int=1) - if idkey == :all || idkey == :All - names = Set{Symbol}() - for diag in diagVec - for field in fieldnames(typeof(diag.id)) - push!(names, field) - end - end - return toDataFrame(diagVec, collect(names); maxdepth=maxdepth) - else - return toDataFrame(diagVec, [idkey,]; maxdepth=maxdepth) - end -end - -function toDataFrame(diagVec::AbstractVector, idkey=Vector{Symbol}(); maxdepth::Int=1) - if isempty(diagVec) - return DataFrame() - end - d = Dict{Symbol,Any}() - _DiagtoDict!(d, diagVec, maxdepth=maxdepth) - - idkey = isnothing(idkey) ? Vector{Symbol}() : collect(idkey) - if isempty(idkey) == false - for _key in idkey - _IdstoDict!(d, diagVec, _key) - end - end - df = DataFrame(d, copycols=false) - # df = DataFrame(d) - return df -end - -# function toDataFrame(diagVec::AbstractVector; expand::Bool=false, maxdepth::Int=1) -# vec_of_diag_dict = [toDict(d, maxdepth=maxdepth) for d in diagVec] -# names = Set(reduce(union, keys(d) for d in vec_of_diag_dict)) -# if expand -# vec_of_id_dict = [toDict(d.id) for d in diagVec] -# idnames = Set(reduce(union, keys(d) for d in vec_of_id_dict)) -# @assert isempty(intersect(names, idnames)) "collision of diagram names $names and id names $idnames" -# names = union(names, idnames) - -# for (di, d) in enumerate(vec_of_diag_dict) -# merge!(d, vec_of_id_dict[di]) #add id dict into the diagram dict -# end -# end -# # println(names) -# df = DataFrame([name => [] for name in names]) - -# for dict in vec_of_diag_dict -# append!(df, dict, cols=:union) -# end -# return df -# end - -function _summary(diag::Diagram{W}, color=true) where {W} - - function short(factor, ignore=nothing) - if isnothing(ignore) == false && applicable(isapprox, factor, ignore) && factor ≈ ignore - return "" - end - str = "$(factor)" - if factor isa Float64 - return length(str) <= 4 ? str : @sprintf("%6.3e", factor) - elseif factor isa Vector{Float64} - return length(str) <= 4 ? str : reduce(*, [@sprintf("%6.3e", f) for f in factor]) - else - return str - end - end - - namestr = diag.name == :none ? "" : "$(diag.name) " - idstr = "$namestr$(diag.id)" - fstr = short(diag.factor, one(diag.factor)) - wstr = short(diag.weight) - # =$(node.weight*(2π)^(3*node.id.para.innerLoopNum)) - - if length(diag.subdiagram) == 0 - return isempty(fstr) ? "$idstr=$wstr" : "$(idstr)⋅$(fstr)=$wstr" - else - return "$idstr=$wstr=$fstr$(diag.operator) " - end -end - -function Base.show(io::IO, diag::Diagram) - if length(diag.subdiagram) == 0 - typestr = "" - else - subdiag = prod(["$(d.hash), " for d in diag.subdiagram[1:end-1]]) - subdiag *= "$(diag.subdiagram[end].hash)" - typestr = "($subdiag)" - end - print(io, "$(diag.hash):$(_summary(diag, true))$typestr") -end - -""" - function plot_tree(diag::Diagram; verbose = 0, maxdepth = 6) - - Visualize the diagram tree using ete3 python package - -#Arguments -- `diag` : the Diagram struct to visualize -- `verbose=0` : the amount of information to show -- `maxdepth=6` : deepest level of the diagram tree to show -""" -function plot_tree(diag::Diagram; verbose=0, maxdepth=20) - - # pushfirst!(PyVector(pyimport("sys")."path"), @__DIR__) #comment this line if no need to load local python module - ete = PyCall.pyimport("ete3") - - function treeview(node, level, t=ete.Tree(name=" ")) - if level > maxdepth - return - end - nt = t.add_child(name="$(node.hash): $(_summary(node, false))") - - if length(node.subdiagram) > 0 - name_face = ete.TextFace(nt.name, fgcolor="black", fsize=10) - nt.add_face(name_face, column=0, position="branch-top") - for child in node.subdiagram - treeview(child, level + 1, nt) - end - end - - return t - end - - t = treeview(diag, 1) - - # NOTE: t.set_style does not update the original PyObject as expected, i.e., - # `t.set_style(ete.NodeStyle(bgcolor="Khaki"))` does not modify t. - # - # The low-level approach circumvents this by directly updating the original PyObject `t."img_style"` - PyCall.set!(t."img_style", "bgcolor", "Khaki") - - ts = ete.TreeStyle() - ts.show_leaf_name = true - # ts.show_leaf_name = True - # ts.layout_fn = my_layout - ####### show tree vertically ############ - # ts.rotation = 90 #show tree vertically - - ####### show tree in an arc ############# - # ts.mode = "c" - # ts.arc_start = -180 - # ts.arc_span = 180 - # t.write(outfile="/home/kun/test.txt", format=8) - t.show(tree_style=ts) -end -function plot_tree(diags::Vector{Diagram{W}}; kwargs...) where {W} - for diag in diags - plot_tree(diag; kwargs...) - end -end -function plot_tree(df::DataFrame; kwargs...) - plot_tree(df.diagram; kwargs...) -end \ No newline at end of file diff --git a/src/diagram_tree/operation.jl b/src/diagram_tree/operation.jl deleted file mode 100644 index eeeb863a..00000000 --- a/src/diagram_tree/operation.jl +++ /dev/null @@ -1,147 +0,0 @@ -function oneOrderHigher(diag::Diagram{W}, ::Type{Id}, subdiagram=[]; - index::Int=index(Id), #which index to increase the order - operator::Operator=diag.operator, - name::Symbol=diag.name, factor::W=diag.factor) where {W,Id} - # if diag.id isa PropagatorId && (diag.id isa Id) == false - # #for bare propagator, a derivative of different id vanishes - # return nothing - # end - id = deepcopy(diag.id) - @assert index <= length(id.order) "$(id) only supports derivatives up to the index $(length(id.order))!" - id.order[index] += 1 - d = Diagram{W}(id, operator, subdiagram; name=name, factor=factor) - return d -end - -function hasOrderHigher(diag::Diagram{W}, ::Type{ID}) where {W,ID<:PropagatorId} - if diag.id isa ID - #for bare propagator, a derivative of different id vanishes - return true - else - return false - end -end - -""" - function derivative(diags::Union{Tuple,AbstractVector}, ::Type{ID}; index::Int=index(ID)) where {W,ID<:PropagatorId} - function derivative(diags::Vector{Diagram{W}}, ::Type{ID}; index::Int=index(ID)) where {W,ID<:PropagatorId} - - Automatic differentiation derivative on the diagrams - -# Arguments -- diags : diagrams to take derivative -- ID : DiagramId to apply the differentiation -- index : index of the id.order array element to increase the order -""" -function derivative(diags::Union{Tuple,AbstractVector}, ::Type{ID}; index::Int=index(ID)) where {ID<:PropagatorId} - if isempty(diags) - return diags - else - diags = collect(diags) - diags = derivative(diags, ID; index=index) - return diags - end -end - -function derivative(diags::Vector{Diagram{W}}, ::Type{ID}; index::Int=index(ID)) where {W,ID<:PropagatorId} - # use a dictionary to host the dual diagram of a diagram for a given hash number - # a dual diagram is defined as the derivative of the original diagram - - dual = Dict{Int,Diagram{W}}() - for diag in diags - for d::Diagram{W} in PostOrderDFS(diag) # postorder traversal will visit all subdiagrams of a diagram first - if haskey(dual, d.hash) - continue - end - if d.id isa PropagatorId - # for propagators like bare Green's function and interaction, derivative simply means increase an order by one - if hasOrderHigher(d, ID) - dual[d.hash] = oneOrderHigher(d, ID; index=index) - end - else # composite diagram - if d.operator isa Sum - # for a diagram which is a sum of subdiagrams, derivative means a sub of derivative subdiagrams - children = [dual[sub.hash] for sub in d.subdiagram if haskey(dual, sub.hash)] - if isempty(children) == false - dual[d.hash] = oneOrderHigher(d, ID, children; index=index) - end - elseif d.operator isa Prod - # d = s1xs2x... = s1'xs2x... + s1xs2'x... + ... - terms = Vector{Diagram{W}}() - for (si, sub) in enumerate(d.subdiagram) - if haskey(dual, sub.hash) == false - continue - end - children = [si == sj ? dual[sub.hash] : sub for (sj, sub) in enumerate(d.subdiagram)] - if isempty(children) == false - push!(terms, oneOrderHigher(d, ID, children; index=index)) - end - end - - if isempty(terms) == false - # !the summed dual diagram must have factor = 1.0 - dual[d.hash] = oneOrderHigher(d, ID, terms; index=index, name=Symbol("$(d.name)'"), factor=W(1), operator=Sum()) - end - else - error("not implemented!") - end - end - end - end - return [dual[diag.hash] for diag in diags if haskey(dual, diag.hash)] -end - -""" - function derivative(diags::Union{Diagram,Tuple,AbstractVector}, ::Type{ID}, order::Int) where {ID<:PropagatorId} - - Automatic differentiation derivative on the diagrams - -# Arguments -- diags : diagrams to take derivative -- ID : DiagramId to apply the differentiation -- order::Int : derivative order -""" -function derivative(diags::Union{Tuple,AbstractVector}, ::Type{ID}, order::Int; index::Int=index(ID)) where {ID<:PropagatorId} - @assert order >= 0 - if order == 0 - return diags - end - result = diags - for o in 1:order - result = derivative(result, ID; index=index) - end - return result -end - -""" - function removeHartreeFock!(diag::Diagram{W}) where {W} - function removeHartreeFock!(diags::Union{Tuple,AbstractVector}) - - Remove the Hartree-Fock insertions that without any derivatives on the propagator and the interaction. - -# Arguments -- diags : diagrams to remove the Fock insertion - -# Remarks -- The operations removeHartreeFock! and taking derivatives doesn't commute with each other! -- If the input diagram is a Hartree-Fock diagram, then the overall weight will become zero! -- The return value is always nothing -""" -function removeHartreeFock!(diag::Diagram{W}) where {W} - for d in PreOrderDFS(diag) - # for subdiag in d.subdiagram - if d.id isa SigmaId - # println(d, " with ", d.id.para.innerLoopNum) - if isempty(d.id.order) || all(x -> x == 0, d.id.order) #eithr order is empty or a vector of zeros - if d.id.para.innerLoopNum == 1 - d.factor = 0.0 - end - end - end - end -end -function removeHartreeFock!(diags::Union{Tuple,AbstractVector}) - for diag in diags - removeHartreeFock!(diag) - end -end \ No newline at end of file diff --git a/src/diagram_tree/optimize.jl b/src/diagram_tree/optimize.jl deleted file mode 100644 index 2b0d6bbf..00000000 --- a/src/diagram_tree/optimize.jl +++ /dev/null @@ -1,126 +0,0 @@ -function optimize!(diag::Union{Tuple,AbstractVector}, optlevel=1; verbose=0, normalize=nothing) - if isempty(diag) - return diag - else - diag = collect(diag) - removeOneChildParent!(diag, verbose=verbose) - removeDuplicatedLeaves!(diag, verbose=verbose, normalize=normalize) - return diag - end -end - -""" - removeOneChildParent!(diags::AbstractVector; verbose = 0) - - remove duplicated nodes such as: ---> ver4 ---> InteractionId. Leaf will not be touched! -""" -function removeOneChildParent!(diags::Vector{Diagram{W}}; verbose=0) where {W} - verbose > 0 && println("remove nodes with only one child.") - for diag in diags - #deep first search, remove one-child parent from the leaf level first - removeOneChildParent!(diag.subdiagram) - #then remove the one-child subdiagram of the current diagram - for (si, subdiag) in enumerate(diag.subdiagram) - if length(subdiag.subdiagram) == 1 - subdiag.subdiagram[1].factor *= subdiag.factor - diag.subdiagram[si] = subdiag.subdiagram[1] - end - end - end - return diags -end - -""" - removeDuplicatedLeaves!(diags::AbstractVector; verbose = 0) - - remove duplicated nodes such as: ---> ver4 ---> InteractionId. Leaf will not be touched! -""" -function removeDuplicatedLeaves!(diags::Vector{Diagram{W}}; verbose=0, normalize=nothing, kwargs...) where {W} - verbose > 0 && println("remove duplicated leaves.") - leaves = Vector{Diagram{W}}() - for diag in diags - #leaves must be the propagators - append!(leaves, collect(Leaves(diag))) - end - # println([d.hash for d in leaves]) - if isnothing(normalize) == false - @assert normalize isa Function "a function call is expected for normalize" - for leaf in leaves - normalize(leaf.id) - end - end - sort!(leaves, by=x -> x.hash) #sort the hash of the leaves in an asscend order - unique!(x -> x.hash, leaves) #filter out the leaves with the same hash number - - for l in leaves - #make sure all leaves are either Green's functions or interactions - @assert l.id isa PropagatorId - end - - function uniqueLeaves(_diags::Vector{Diagram{W}}) where {W} - ############### find the unique Leaves ##################### - uniqueDiag = [] - mapping = Dict{Int,Any}() - for diag in _diags - flag = true - for (ei, e) in enumerate(uniqueDiag) - if e.factor ≈ diag.factor && e.id == diag.id - mapping[diag.hash] = e - flag = false - break - end - end - if flag - push!(uniqueDiag, diag) - # push!(mapping, length(uniqueDiag)) - mapping[diag.hash] = diag - end - end - return uniqueDiag, mapping - end - - # println(leaves) - green = [l for l in leaves if l.id isa BareGreenId] - interaction = [l for l in leaves if l.id isa BareInteractionId] - greenN = [l for l in leaves if l.id isa BareGreenNId] - hopping = [l for l in leaves if l.id isa BareHoppingId] - # println(green) - # println(interaction) - - uniqueGreen, greenMap = uniqueLeaves(green) - uniqueGreenN, greenNMap = uniqueLeaves(greenN) - uniqueInteraction, interactionMap = uniqueLeaves(interaction) - uniqueHopping, hoppingMap = uniqueLeaves(hopping) - # println(uniqueInteraction) - # display(greenMap) - - verbose > 0 && length(green) > 0 && println("Number of independent Greens $(length(green)) → $(length(uniqueGreen))") - verbose > 0 && length(greenN) > 0 && println("Number of independent GreenNs $(length(greenN)) → $(length(uniqueGreenN))") - verbose > 0 && length(interaction) > 0 && println("Number of independent Interactions $(length(interaction)) → $(length(uniqueInteraction))") - verbose > 0 && length(hopping) > 0 && println("Number of independent Hopping $(length(hopping)) → $(length(uniqueHopping))") - - for diag in diags - for n in PreOrderDFS(diag) - for (si, subdiag) in enumerate(n.subdiagram) - @assert (n.id isa PropagatorId) == false "the diagram $n with subdiagrams cannot be a proapgator!" - - if subdiag.id isa PropagatorId - if subdiag.id isa BareGreenId - n.subdiagram[si] = greenMap[subdiag.hash] - elseif subdiag.id isa BareInteractionId - n.subdiagram[si] = interactionMap[subdiag.hash] - elseif subdiag.id isa BareGreenNId - n.subdiagram[si] = greenNMap[subdiag.hash] - elseif subdiag.id isa BareHoppingId - n.subdiagram[si] = hoppingMap[subdiag.hash] - else - error("not implemented!") - end - end - end - end - end - - return uniqueGreen, uniqueInteraction - # return diags -end \ No newline at end of file diff --git a/src/diagram_tree/traits.jl b/src/diagram_tree/traits.jl deleted file mode 100644 index 1cf382af..00000000 --- a/src/diagram_tree/traits.jl +++ /dev/null @@ -1,255 +0,0 @@ -abstract type Operator end -struct Sum <: Operator end -struct Prod <: Operator end -Base.isequal(a::Operator, b::Operator) = (typeof(a) == typeof(b)) -Base.:(==)(a::Operator, b::Operator) = Base.isequal(a, b) -apply(o::Operator, diags) = error("not implemented!") - -Base.show(io::IO, o::Operator) = print(io, typeof(o)) -Base.show(io::IO, o::Sum) = print(io, "⨁") -Base.show(io::IO, o::Prod) = print(io, "Ⓧ") - -""" - abstract type DiagramId end - - The abstract type of all diagrams/subdiagrams/bare propagators -""" -abstract type DiagramId end - -""" - abstract type PropagatorId <: DiagramId end - - The abstract type of all bare propagators -""" -abstract type PropagatorId <: DiagramId end - -# Base.Dict(x::DiagramId) = Dict{Symbol,Any}([fn => getfield(x, fn) for fn ∈ fieldnames(typeof(x))]) -# Base.show(io::IO, d::DiagramId) = error("Base.show not implemented!") -# Base.isequal(a::DiagramId, b::DiagramId) = error("Base.isequal not implemented!") -Base.:(==)(a::DiagramId, b::DiagramId) = Base.isequal(a, b) - -struct BareGreenId <: PropagatorId - para::DiagPara - type::AnalyticProperty #Instant, Dynamic, D_Instant, D_Dynamic - extK::Vector{Float64} - extT::Tuple{Int,Int} #all possible extT from different interactionType - order::Vector{Int} - function BareGreenId(para::DiagPara, type::AnalyticProperty=Dynamic, order=[0, 0, 0, 0]; k, t) - return new(para, type, k, Tuple(t), order) - end -end -Base.show(io::IO, v::BareGreenId) = print(io, "$(short(v.type))#$(v.order), k$(v.extK), t$(v.extT)") - -struct BareInteractionId <: PropagatorId - para::DiagPara - response::Response #UpUp, UpDown, ... - type::AnalyticProperty #Instant, Dynamic, D_Instant, D_Dynamic - permutation::Permutation - extK::Vector{Float64} - extT::Tuple{Int,Int} #all possible extT from different interactionType - order::Vector{Int} - function BareInteractionId(para::DiagPara, response::Response, type::AnalyticProperty=Instant, order=[0, 0, 0, 0]; k, t=(0, 0), permu::Permutation=DiEx) - return new(para, response, type, permu, k, Tuple(t), order) - end -end -Base.show(io::IO, v::BareInteractionId) = print(io, "$(short(v.response))$(short(v.type))$(v.permutation)#$(v.order), k$(v.extK), t$(v.extT)") - -struct GenericId <: DiagramId - para::DiagPara - extra::Any - order::Vector{Int} - GenericId(para::DiagPara, extra=Nothing, order=[0, 0, 0, 0]) = new(para, extra, order) -end -Base.show(io::IO, v::GenericId) = print(io, v.extra == Nothing ? "#$(v.order)" : "$(v.extra)#$(v.order)") - -struct GreenId <: DiagramId - para::DiagPara - type::AnalyticProperty #Instant, Dynamic, D_Instant, D_Dynamic - extK::Vector{Float64} - extT::Tuple{Int,Int} #all possible extT from different interactionType - order::Vector{Int} - function GreenId(para::DiagPara, type::AnalyticProperty=Dynamic, order=[0, 0, 0, 0]; k, t) - return new(para, type, k, Tuple(t), order) - end -end -Base.show(io::IO, v::GreenId) = print(io, "$(short(v.type))#$(v.order), k$(v.extK), t$(v.extT)") - -struct SigmaId <: DiagramId - para::DiagPara - type::AnalyticProperty #Instant, Dynamic, D_Instant, D_Dynamic - extK::Vector{Float64} - extT::Tuple{Int,Int} #all possible extT from different interactionType - order::Vector{Int} - function SigmaId(para::DiagPara, type::AnalyticProperty, order=[0, 0, 0, 0]; k, t=(0, 0)) - return new(para, type, k, t, order) - end -end -Base.show(io::IO, v::SigmaId) = print(io, "$(short(v.type))#$(v.order), t$(v.extT)") - -struct PolarId <: DiagramId - para::DiagPara - response::Response #UpUp, UpDown, ... - extK::Vector{Float64} - extT::Tuple{Int,Int} #all possible extT from different interactionType - order::Vector{Int} - function PolarId(para::DiagPara, response::Response, order=[0, 0, 0, 0]; k, t=(0, 0)) - return new(para, response, k, t, order) - end -end -Base.show(io::IO, v::PolarId) = print(io, "$(short(v.response))#$(v.order), k$(v.extK), t$(v.extT)") - -struct Ver3Id <: DiagramId - para::DiagPara - response::Response #UpUp, UpDown, ... - extK::Vector{Vector{Float64}} - extT::Tuple{Int,Int,Int} #all possible extT from different interactionType - order::Vector{Int} - function Ver3Id(para::DiagPara, response::Response, order=[0, 0, 0, 0]; k, t=(0, 0, 0)) - return new(para, response, k, Tuple(t), order) - end -end -Base.show(io::IO, v::Ver3Id) = print(io, "$(short(v.response))#$(v.order),t$(v.extT)") - -struct Ver4Id <: DiagramId - para::DiagPara - response::Response #UpUp, UpDown, ... - type::AnalyticProperty #Instant, Dynamic, D_Instant, D_Dynamic - channel::TwoBodyChannel # particle-hole, particle-hole exchange, particle-particle, irreducible - extK::Vector{Vector{Float64}} - extT::Tuple{Int,Int,Int,Int} #all possible extT from different interactionType - order::Vector{Int} - function Ver4Id(para::DiagPara, response::Response, type::AnalyticProperty=Dynamic, order=[0, 0, 0, 0]; k, t=(0, 0, 0, 0), chan::TwoBodyChannel=AnyChan) - return new(para, response, type, chan, k, Tuple(t), order) - end -end -Base.show(io::IO, v::Ver4Id) = print(io, (v.channel == AnyChan ? "" : "$(v.channel) ") * "$(short(v.response))$(short(v.type))#$(v.order),t$(v.extT)") - -function vstr(r, c) - N = length(r) - # cstr(x) = x ? "⁺" : "⁻" - s = "" - for i = 1:N-1 - s *= "$(r[i])$c" - end - s *= "$(r[end])$c" - return s -end - -function vcstr(r, creation) - N = length(r) - # cstr(x) = x ? "⁺" : "⁻" - s = "" - for i = 1:N-1 - if creation[i] - s *= "$(r[i])⁺" - else - s *= "$(r[i])⁻" - end - end - if creation[end] - s *= "$(r[end])⁺" - else - s *= "$(r[end])⁻" - end - return s -end - -""" -hopping function c⁺c⁻ -""" -struct BareHoppingId <: PropagatorId - para::DiagPara - site::Tuple{Int,Int} - orbital::Tuple{Int,Int} - extT::Tuple{Int,Int} - function BareHoppingId(para::DiagPara, orbital, t, r) - return new(para, r, orbital, t) - end -end -Base.show(io::IO, v::BareHoppingId) = print(io, "($(vstr(v.site, "ᵣ"))|$(vstr(v.orbital, "ₒ"))|$(vcstr(v.extT, [true, false])))") - -""" -time-ordered N-point Bare Green's function -""" -struct BareGreenNId <: PropagatorId - para::DiagPara - site::Int - creation::Vector{Bool} - orbital::Vector{Int} - extT::Vector{Int} - N::Int - function BareGreenNId(para::DiagPara; orbital=[], t=[], creation=[], r=0) - @assert length(orbital) == length(t) == length(creation) - return new(para, r, creation, orbital, t, length(orbital)) - end -end -Base.show(io::IO, v::BareGreenNId) = print(io, "($(v.site)ᵣ|$(vstr(v.orbital, "ₒ"))|$(vcstr(v.extT, v.creation)))") - -""" -time-ordered N-point Composite Green's function -""" -struct GreenNId <: DiagramId - para::DiagPara - site::Vector{Int} - creation::Vector{Bool} - orbital::Vector{Int} - extT::Vector{Int} - N::Int - function GreenNId(para::DiagPara; orbital=[], t=[], creation=[], r=[]) - @assert length(orbital) == length(t) == length(r) == length(creation) - return new(para, r, creation, orbital, t, length(orbital)) - end -end -Base.show(io::IO, v::GreenNId) = print(io, "($(vstr(v.site, "ᵣ"))|$(vstr(v.orbital, "ₒ"))|$(vcstr(v.extT, v.creation)))") - -""" -time-ordered N-point Composite Green's function -""" -struct ConnectedGreenNId <: DiagramId - para::DiagPara - site::Vector{Int} - creation::Vector{Bool} - orbital::Vector{Int} - extT::Vector{Int} - N::Int - function ConnectedGreenNId(para::DiagPara; orbital=[], t=[], creation=[], r=[]) - @assert length(orbital) == length(t) == length(r) == length(creation) - return new(para, r, creation, orbital, t, length(orbital)) - end -end -Base.show(io::IO, v::ConnectedGreenNId) = print(io, "($(vstr(v.site, "ᵣ"))|$(vstr(v.orbital, "ₒ"))|$(vcstr(v.extT, v.creation)))") - -function Base.isequal(a::DiagramId, b::DiagramId) - if typeof(a) != typeof(b) - return false - end - for field in fieldnames(typeof(a)) - field in [:para, :permutation] && continue - if field == :extK - if !(getproperty(a, :extK) ≈ getproperty(b, :extK)) && !(getproperty(a, :extK) ≈ -getproperty(b, :extK)) - return false - end - continue - end - if getproperty(a, field) != getproperty(b, field) - return false - end - end - return true -end - -function index(type) - if type == BareGreenId - return 1 - elseif type == BareInteractionId - return 2 - elseif type == BareGreenNId - return 3 - elseif type == BareHoppingId - return 4 - else - error("Not Implemented!") - end -end - - diff --git a/src/diagram_tree/tree.jl b/src/diagram_tree/tree.jl deleted file mode 100644 index fc30a5c1..00000000 --- a/src/diagram_tree/tree.jl +++ /dev/null @@ -1,275 +0,0 @@ -# Base.hash(d::DiagramId) = hash(d) % 1000000 -""" - mutable struct Diagram{W} - - struct of a diagram. A diagram of a sum or produce of various subdiagrams. - -# Members -- hash::Int : the unique hash number to identify the diagram -- name::Symbol : name of the diagram -- id::DiagramId : diagram id -- operator::Operator : operation, support Sum() and Prod() -- factor::W : additional factor of the diagram -- subdiagram::Vector{Diagram{W}} : vector of sub-diagrams -- weight::W : weight of the diagram -""" -mutable struct Diagram{W} - hash::Int - name::Symbol - id::DiagramId - operator::Operator - factor::W - subdiagram::Vector{Diagram{W}} - - weight::W - # parent::Diagram - - """ - function Diagram{W}(id::DiagramId, operator::Operator = Sum(), subdiagram = []; name = :none, factor = W(1), weight = W(0)) where {W} - - construct Diagram struct. - - # Arguments - - id : DiagramId of the diagram - - operator : Sum() or Prod() - - subdiagram : subdiagrams of the diagram, it should be a vector of Diagram struct - - name : name of the diaram - - factor : the additional factor of the diagram - - weight : the initial weight - """ - function Diagram{W}(id::DiagramId, operator::Operator=Sum(), subdiagram=[]; - name=:none, factor=W(1), weight=W(0)) where {W} - # return new{W}(uid(), name, id, operator, factor, deepcopy(subdiagram), weight) - return new{W}(uid(), name, id, operator, factor, subdiagram, weight) - end - # function Diagram(id::DiagramId, operator::Operator=Sum(), subdiagram=[]; type::DataType=id.para.weightType, - # name=:none, factor=one(type), weight=zero(type)) - # # return new{type}(uid(), name, id, operator, factor, deepcopy(subdiagram), weight) - # return new{type}(uid(), name, id, operator, factor, subdiagram, weight) - # end -end - -isbare(diag::Diagram) = isempty(diag.subdiagram) - -# function addSubDiagram!(parent::Diagram, child::Diagram) -# for c in parent.subdiagram -# if c.id == child.id -# return false -# end -# end -# push!(parent.subdiagram, deepcopy(child)) -# end - -# function addSubDiagram!(parent::Diagram, child::Vector{Diagram{W}}) where {W} -# for d in child -# addSubDiagram!(parent, d) -# end -# end - -# _diagram(df, index) = df[index, :Diagram] - -function _combinegroups(groups, getid, factor, operator, name) - # combine diagrams in a group into one composite diagram - gdf = combine(groups) do group # for each group in groups - # check the documentation of ``combine" for details https://dataframes.juliadata.org/stable/man/split_apply_combine/ - # id = isnothing(getid) ? GenericId(group.diagram[1].id.para, Tuple(group[1, fields])) : getid(group) - id = getid(group) - - if nrow(group) == 1 - # if there is only one diagram in df, and the new id is either GenericId or the id of the existing diagram, - # then simply return the current df without creating a new diagram - # ! the new factor will be multiplied to the factor of the exisiting diagram! - if id isa GenericId || typeof(id) == typeof(group.diagram[1].id) - # diag = deepcopy(group[1, :diagram]) - diag = group.diagram[1] - diag.factor *= factor - return (diagram=diag, hash=diag.hash) - end - end - W = typeof(group.diagram[1].weight) - diag = Diagram{W}(id, operator, group.diagram, name=name, factor=factor) - return (diagram=diag, hash=diag.hash) - end - return gdf -end - -function _mergediag(::Type{W}, group, factor, id, operator, name) where {W} - if nrow(group) == 1 - # if there is only one diagram in df, and the new id is either GenericId or the id of the existing diagram, - # then simply return the current df without creating a new diagram - # ! the new factor will be multiplied to the factor of the exisiting diagram! - if id isa GenericId || typeof(id) == typeof(group.diagram[1].id) - # diag = deepcopy(group[1, :diagram]) - diag::Diagram{W} = group.diagram[1] - diag.factor *= factor - return diag - end - end - return Diagram{W}(id, operator, group.diagram, name=name, factor=factor) -end - -function _combine(::Type{W}, groups, factor, getid, operator, name) where {W} - """ - # if fields = [:response, :extT], then - - # 1. groups.cols is like: Vector{Symbol}[:response, :extT] - - # 2. groups.keymap is like: - - # Dict{Any, Int64} with 2 entries: - # (UpDown, (1, 1, 1, 1)) => 2 - # (UpUp, (1, 1, 1, 1)) => 1 - # """ - d = Dict{Symbol,Any}() - _keys = keys(groups) - for col in groupcols(groups) - d[col] = [key[col] for key in _keys] - end - d[:diagram] = [_mergediag(W, groups[key], factor, getid(groups[key]), operator, name) for key in _keys] - d[:hash] = [diag.hash for diag in d[:diagram]] - return DataFrame(d, copycols=false) -end - -function mergeby(df::DataFrame, fields=Vector{Symbol}(); - operator=Sum(), name::Symbol=:none, factor=1.0, - getid::Function=g -> GenericId(g[1, :diagram].id.para, Tuple(g[1, fields])) -) - if isempty(df) - return df - else - W = typeof(df.diagram[1].weight) - return mergeby(W, df, fields; operator=operator, name=name, factor=factor, getid=getid) - end -end - -function mergeby(::Type{W}, df::DataFrame, fields=Vector{Symbol}(); - operator=Sum(), name::Symbol=:none, factor=1.0, - getid::Function=g -> GenericId(g[1, :diagram].id.para, Tuple(g[1, fields])) -) where {W} - if isempty(df) - return df - else - if all(x -> typeof(x.id) == typeof(df.diagram[1].id), df[!, :diagram]) == false - @warn "Not all DiagramIds in $df are the same!" - end - groups = DataFrames.groupby(df, fields, sort=true) - ######## less memory usage but can not pass the test right now ############## - d = _combine(W, groups, factor, getid, operator, name) - ######## alternative approach (more memory) ################## - # d = _combinegroups(groups, getid, factor, operator, name) - # println("old\n$d \n new\n$cd") - return d - end -end - -function mergeby(diags::Union{Diagram,Tuple,AbstractVector}, fields=nothing; idkey=nothing, kwargs...) - if diags isa Diagram - return diags - else - if isempty(diags) - return diags - else - W = typeof(diags[1].weight) - @assert all(x -> (x.weight isa W), diags) "all diagrams should be of the same type. \n$diags" - diags = collect(diags) - if isnothing(fields) && isnothing(idkey) - return mergeby(diags; kwargs...) - else - return mergeby(diags, fields; idkey=idkey, kwargs...) - end - end - end -end - -# function mergeby(diags::AbstractVector, fields=[]; idkey::Vector{Symbol}=[], kwargs...) -function mergeby(diags::Vector{Diagram{W}}, fields; idkey=Vector{Symbol}(), kwargs...) where {W} - if isempty(diags) - return diags - else - df = toDataFrame(diags, idkey) - mergedf = mergeby(df, fields; kwargs...) - return Vector{Diagram{W}}(mergedf.diagram) - end -end - -function mergeby(diags::Vector{Diagram{W}}; - operator=Sum(), name::Symbol=:none, factor=1.0, - getid::Function=d -> GenericId(d[1].id.para::DiagPara{W}) -) where {W} - if isempty(diags) - return diags - else - id = getid(diags) - if length(diags) == 1 && (id isa GenericId || typeof(id) == typeof(diags[1].id)) - # if there is only one diagram, and the new id is either GenericId or the id of the existing diagram, - # then simply return the current diagram without creating a new diagram - # ! the new factor will be multiplied to the factor of the exisiting diagram! - diags[1].factor *= factor - return diags - end - diag = Diagram{W}(id, operator, diags, name=name, factor=factor) - return [diag,] - end -end -# mergeby(df::DataFrame; kwargs...) = mergeby(df, []; kwargs...) -# mergeby(diags::Vector{Diagram{W}}; kwargs...) where {W} = mergeby(diags, []; kwargs...) - - - -##################### interface to AbstractTrees ########################### -function AbstractTrees.children(diag::Diagram) - return diag.subdiagram -end - -## Things that make printing prettier -AbstractTrees.printnode(io::IO, diag::Diagram) = print(io, "\u001b[32m$(diag.hash)\u001b[0m : $diag") -# AbstractTrees.printnode(io::IO, diag::Diagram) = print(io, "$(diag)") - -######### define the following for the type stability ######################### -# AbstractTrees.childrentype(diag::Diagram{W}) where {W} = Vector{Diagram{W}} - -# AbstractTrees.NodeType(::Diagram{W}) where {W} = HasNodeType() -AbstractTrees.nodetype(::Diagram{W}) where {W} = Diagram{W} - -## Optional enhancements -# These next two definitions allow inference of the item type in iteration. -# (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/expression_tree/ExpressionTree.jl b/src/expression_tree/ExpressionTree.jl deleted file mode 100644 index f669ce2e..00000000 --- a/src/expression_tree/ExpressionTree.jl +++ /dev/null @@ -1,29 +0,0 @@ -module ExprTree -using AbstractTrees, LinearAlgebra, StaticArrays -import LinearAlgebra: BlasInt -using ..DiagTree -# using Unrolled -# using InteractiveUtils - -using Printf, PyCall - -const ADD, MUL = 1, 2 -export ADD, MUL - -include("common.jl") - -# struct Cache and struct Pool -include("pool.jl") - -include("tree.jl") -export ExpressionTree - -# IO operations -include("io.jl") - -# diagram evaluation -include("eval.jl") - -include("build.jl") - -end \ No newline at end of file diff --git a/src/expression_tree/build.jl b/src/expression_tree/build.jl deleted file mode 100644 index 49a43ac7..00000000 --- a/src/expression_tree/build.jl +++ /dev/null @@ -1,65 +0,0 @@ -function build(diags::Union{Diagram,Tuple,AbstractVector}, loopDim::Int, hasLoop=true; verbose::Int=0, normalize=nothing) - if isempty(diags) - return nothing - else - diags = collect(diags) - @assert eltype(diags) <: Diagram "Diagram struct expected for $diags" - return _build(diags, loopDim, hasLoop; verbose=verbose, normalize=normalize) - end -end - -function _build(diags::Vector{Diagram{W}}, loopDim::Int, hasLoop=true; verbose::Int=0, normalize=nothing) where {W} - # println(diags) - @assert all(d -> (d.id.para == diags[1].id.para), diags) "Parameters of all diagrams shoud be the same!" - - DiagTree.optimize!(diags, verbose=verbose, normalize=normalize) - - tree = newExprTree(diags[1].id.para::DiagPara{W}, loopDim, :none, hasLoop) - - # nodepool = CachedPool(:node, Node{DiagramId,W}, W) - - verbose > 0 && println("Constructing expression tree...") - nodes = Dict{Int,Any}() - for diag in diags - for d::Diagram{W} in PostOrderDFS(diag) - if haskey(nodes, d.hash) == false - id = d.id - if isempty(d.subdiagram) - K = hasLoop ? id.extK : nothing - nodes[d.hash] = addpropagator!(tree, d.name, d.factor; site=collect(id.extT), loop=K, para=id) - else - children = [nodes[sub.hash] for sub in d.subdiagram] - nodes[d.hash] = addnode!(tree, operator(d.operator), d.name, children, d.factor, para=id) - end - end - end - end - - setroot!(tree, collect([nodes[d.hash] for d in diags])) - initialize!(tree.node) - return tree -end -# function build(diag::Diagram{W}; verbose::Int=0) where {W} -# diag = build([diag,], verbose=verbose) -# return diag -# end - -function operator(op::Operator) - if op isa Sum - return ADD - elseif op isa Prod - return MUL - else - error("$op not implemented!") - end -end - -function newExprTree(para::DiagPara{W}, loopDim::Int, name::Symbol=:none, hasLoop=true) where {W} - if hasLoop - Kpool = LoopPool(:K, loopDim, para.totalLoopNum, Float64) - else - Kpool = LoopPool(:K, 0, para.totalLoopNum, Float64) - end - return ExpressionTree{W,DiagramId}(loopBasis=Kpool, name=name) - # return ExpressionTree{W,Any}(loopBasis=Kpool, name=name) -end \ No newline at end of file diff --git a/src/expression_tree/common.jl b/src/expression_tree/common.jl deleted file mode 100644 index cca0e00f..00000000 --- a/src/expression_tree/common.jl +++ /dev/null @@ -1,61 +0,0 @@ -import ..Filter -import ..Wirreducible #remove all polarization subdiagrams -import ..Girreducible #remove all self-energy inseration -import ..NoHartree -import ..NoFock -import ..NoBubble # true to remove all bubble subdiagram -import ..Proper #ver4, ver3, and polarization diagrams may require to be irreducible along the transfer momentum/frequency - -import ..DiagramType -import ..GreenDiag -import ..SigmaDiag -import ..PolarDiag -import ..Ver3Diag -import ..Ver4Diag - -import ..Composite -import ..ChargeCharge -import ..SpinSpin -import ..UpUp -import ..UpDown -import ..Response - -import ..Instant -import ..Dynamic -import ..D_Instant -import ..D_Dynamic -import ..AnalyticProperty - -import ..symbol -import ..short - -import ..Interaction -import ..DiagPara -import ..innerTauNum - -import ..Diagram - -import ..DiagramId -import ..Ver4Id -import ..Ver3Id -import ..GreenId -import ..SigmaId -import ..PolarId -import ..BareInteractionId -import ..BareGreenId - -import ..TwoBodyChannel -import ..Alli -import ..PHr -import ..PHEr -import ..PPr -import ..AnyChan - -import ..Permutation -import ..Di -import ..Ex -import ..DiEx - -import ..uidreset -import ..toDataFrame -import ..mergeby \ No newline at end of file diff --git a/src/expression_tree/eval.jl b/src/expression_tree/eval.jl deleted file mode 100644 index f69caa58..00000000 --- a/src/expression_tree/eval.jl +++ /dev/null @@ -1,103 +0,0 @@ -# function warn_type(diag::Diagrams, loopVar, siteVar, evalPropagator, evalNodeFactor = nothing, root = diag.root) -# @code_warntype evalNaive!(diag, loopVar, siteVar, evalPropagator, evalNodeFactor, root) -# end - -function evalKT!(diag::ExpressionTree, additional=nothing; K=nothing, T=nothing, eval=DiagTree.eval) - evalKT!(diag, K, T, additional; eval=eval) -end - -function evalNaive!(diag::ExpressionTree, loopVar, siteVar, additional=nothing; eval=DiagTree.eval) - evalKT!(diag, loopVar, siteVar, additional; eval=eval) -end - -@inbounds function evalKT!(diag::ExpressionTree, loopVar, siteVar, additional=nothing; eval=DiagTree.eval) - loopPool = diag.loopBasis - tree = diag.node - tweight = tree.current - - # calculate new loop - if hasloop(loopPool) && (isnothing(loopVar) == false) - update(loopPool, loopVar) - end - - #calculate diagram tree - @inbounds for (ni, node) in enumerate(tree.object) - # for (ni, node) in enumerate(tree.object) - children = node.children - idpara = node.para - # println(node.children, " , ", node.para) - # if isempty(children) - if node.isleaf - # if node.para isa PropagatorId - if hasloop(loopPool) && (isnothing(siteVar) == false) - if isnothing(additional) - @inbounds tweight[ni] = eval(idpara, current(loopPool, node.loopidx), node.siteidx, siteVar) - # if idpara isa BareGreenId - # @inbounds tweight[ni] = eval(idpara::BareGreenId, current(loopPool, node.loopidx), node.siteidx, siteVar) - # elseif idpara isa BareInteractionId - # @inbounds tweight[ni] = eval(idpara::BareInteractionId, current(loopPool, node.loopidx), node.siteidx, siteVar) - # else - # error("not implemented") - # end - else - @inbounds tweight[ni] = eval(idpara, current(loopPool, node.loopidx), node.siteidx, siteVar, additional) - end - elseif hasloop(loopPool) - if isnothing(additional) - @inbounds tweight[ni] = eval(idpara, node.siteidx, siteVar) - else - @inbounds tweight[ni] = eval(idpara, node.siteidx, siteVar, additional) - end - elseif isnothing(siteVar) == false - if isnothing(additional) - @inbounds tweight[ni] = eval(idpara, current(loopPool, node.loopidx)) - else - @inbounds tweight[ni] = eval(idpara, current(loopPool, node.loopidx), additional) - end - else - if isnothing(additional) - @inbounds tweight[ni] = eval(idpara) - else - @inbounds tweight[ni] = eval(idpara, additional) - end - end - @inbounds tweight[ni] *= node.factor - else - if node.operation == MUL - # @inbounds tweight[ni] = node.factor - # @inbounds for nidx in children - # @inbounds tweight[ni] *= tweight[nidx] - # end - - # f = node.factor - # @inbounds for nidx in children - # @inbounds f *= tweight[nidx] - # end - # tweight[ni] = f - - @inbounds tweight[ni] = reduce(*, tweight[nidx] for nidx in children) * node.factor - - elseif node.operation == ADD - # @inbounds tweight[ni] = 0.0 - # for nidx in children - # @inbounds tweight[ni] += tweight[nidx] - # end - # @inbounds tweight[ni] *= node.factor - - # f = 0.0 - # @inbounds for nidx in children - # @inbounds f += tweight[nidx] - # end - # @inbounds tweight[ni] = f * node.factor - - # @inbounds tweight[ni] = reduce(+, tweight[ni] for ni in children) * node.factor - @inbounds tweight[ni] = sum(tweight[nidx] for nidx in children) * node.factor - else - error("not implemented!") - end - end - end -end - -# @inline function _eval(idpara, loop, siteIdx, siteVar, additional; eval) -# tweight[ni] = eval(idpara, current(loopPool, node.loopidx), node.siteidx, siteVar) \ No newline at end of file diff --git a/src/expression_tree/io.jl b/src/expression_tree/io.jl deleted file mode 100644 index a18d6361..00000000 --- a/src/expression_tree/io.jl +++ /dev/null @@ -1,141 +0,0 @@ -function printBasisPool(diag, io=Base.stdout) - printstyled(io, "Loop Basis ($(length(diag.loopBasis)) in total)\n", color=:blue) - title = @sprintf("%5s%40s\n", "index", "loopBasis") - printstyled(io, title, color=:green) - for i = 1:length(diag.loopBasis) - b = diag.loopBasis.basis[:, i] - @printf(io, "%5i%40s\n", i, "$b") - end - println(io) -end - -function printNodes(diag, io=Base.stdout) - printstyled(io, "Node ($(length(diag.node)) in total)\n", color=:blue) - title = @sprintf("%5s%5s%40s%40s\n", "index", "name", "para", "child") - printstyled(io, title, color=:green) - for (idx, n) in enumerate(diag.node.object) - # site = isempty(p.siteBasis) ? "" : "$(p.siteBasis)" - # loop = p.loopIdx <= 0 ? "" : "$(diag.basisPool[p.loopIdx])" - # loop = p.loopIdx <= 0 ? "" : "$(p.loopIdx)" - if n isa Propagator - site = isempty(n.siteBasis) ? "" : "$(n.siteBasis)" - loop = n.loopIdx <= 0 ? "" : "$(diag.loopBasis[n.loopIdx])" - @printf(io, "%5i%5s%40s%40s%40s\n", idx, "$(n.name)", "$(n.para)", loop, site) - else - @printf(io, "%5i%5s%40s%40s\n", idx, "$(n.name)", "$(n.para)", "$(n.childNodes)") - end - end - println(io) -end - -function Base.show(io::IO, tree::ExpressionTree) - print(io, "ExprTree: $(tree.name) with root $(tree.root)") - # print(io, "$(short(v.response))#$(v.order), k$(v.extK), t$(v.extT)") -end - - -""" - showTree(diag::Diagrams, _root = diag.root[end]; verbose = 0, depth = 999) - - Visualize the diagram tree using ete3 python package - -#Arguments -- `diag`: the Diagrams struct to visualize -- `_root`: the index of the root node to visualize -- `verbose=0`: the amount of information to show -- `depth=999`: deepest level of the diagram tree to show -""" -function showTree(tree::ExpressionTree, _root::Int; verbose=0, depth=999) - - # pushfirst!(PyVector(pyimport("sys")."path"), @__DIR__) #comment this line if no need to load local python module - ete = PyCall.pyimport("ete3") - - function name_para(p) - name = (p.name == :none) ? "" : " $(p.name)" - para = isnothing(p.para) ? "" : " $(p.para)" - return name * para - end - - function factor(f) - if f ≈ 1 - return "" - end - s = "$f" - if length(s) <= 4 - return s - else - return @sprintf("%6.3e", f) - end - end - - function info(node, idx) - s = "N$(idx)$(name_para(node)) = $(tree.node.current[idx])" - # s *= sprint(show, node.para) - # s *= ": " - - if node.operation == MUL - s *= " = $(factor(node.factor))x" - elseif node.operation == ADD - s *= " = $(factor(node.factor))+" - else - error("not implemented!") - end - return s - end - - - function treeview(idx::Int, level, t=nothing) - if isnothing(t) - t = ete.Tree(name=" ") - end - - if tree.node.object[idx] isa PropagatorId - p = tree.node.object[idx] #Propagator - site = isempty(p.siteBasis) ? "" : " t$(p.siteBasis)," - loop = p.loopIdx <= 0 ? "" : "k$(tree.loopBasis[p.loopIdx])" - # loop = p.loopIdx <= 0 ? "" : "$(p.loopIdx)" - nnt = t.add_child(name="P$(idx)$(name_para(p)): $loop,$site $(factor(p.factor))") - else # composite node - nt = t.add_child(name=info(tree.node.object[idx], idx)) - name_face = ete.TextFace(nt.name, fgcolor="black", fsize=10) - nt.add_face(name_face, column=0, position="branch-top") - - for child in tree.node.object[idx].children - if child != -1 - treeview(child, level + 1, nt) - else - nnt = nt.add_child(name="0") - end - end - end - - return t - end - - t = treeview(_root, 1) - - # NOTE: t.set_style does not update the original PyObject as expected, i.e., - # `t.set_style(ete.NodeStyle(bgcolor="Khaki"))` does not modify t. - # - # The low-level approach circumvents this by directly updating the original PyObject `t."img_style"` - PyCall.set!(t."img_style", "bgcolor", "Khaki") - - - ts = ete.TreeStyle() - ts.show_leaf_name = true - # ts.show_leaf_name = True - # ts.layout_fn = my_layout - ####### show tree vertically ############ - # ts.rotation = 90 #show tree vertically - - ####### show tree in an arc ############# - # ts.mode = "c" - # ts.arc_start = -180 - # ts.arc_span = 180 - # t.write(outfile="/home/kun/test.txt", format=8) - t.show(tree_style=ts) -end -# function showTree(diag::ExpressionTree, _root::Component; kwargs...) -# @assert _root.isNode "Can not visualize $_root, because it is not a Node!" -# return showTree(diag, _root.index; kwargs...) -# end \ No newline at end of file diff --git a/src/expression_tree/pool.jl b/src/expression_tree/pool.jl deleted file mode 100644 index c7ac55f6..00000000 --- a/src/expression_tree/pool.jl +++ /dev/null @@ -1,232 +0,0 @@ -""" - struct CachedPool{O,T} - - Use this pool to host the objects that are heavy to evaluate so that one wants to cache their status. - The user should defines a compare - -# Members -- name::Symbol : name of the pool -- object::O : object -- current::T : current status -- new::T : the new status wants to assign later -- version::Int128 : the current version -- excited::Bool : if set to excited, then the current status needs to be replaced with the new status -""" -# mutable struct CachedPool{O,T} -struct CachedPool{O,T} - name::Symbol - object::Vector{O} - current::Vector{T} - new::Vector{T} - version::Vector{Int128} - excited::Vector{Bool} - - function CachedPool(name::Symbol, objType::DataType, weightType::DataType) - object = Vector{objType}(undef, 0) - current = Vector{weightType}(undef, 0) - _new = Vector{weightType}(undef, 0) - version = Vector{Int128}(undef, 0) - excited = Vector{Bool}(undef, 0) - return new{objType,weightType}(name, object, current, _new, version, excited) - end - # function CachedPool{T}(obj::Vector{O}) where {O,T} - # weight = zeros(5, length(obj)) - # return new{O,T}(obj, weight) - # end -end - -Base.length(pool::CachedPool) = length(pool.object) -Base.size(pool::CachedPool) = size(pool.object) -Base.show(io::IO, pool::CachedPool) = print(io, pool.object) -# Base.view(pool::Pool, inds...) = Base.view(pool.pool, inds...) - -#index interface for Pool -Base.getindex(pool::CachedPool, i) = pool.object[i] -Base.setindex!(pool::CachedPool, v, i) = setindex!(pool.object, v, i) -Base.firstindex(pool::CachedPool) = 1 -Base.lastindex(pool::CachedPool) = length(pool) - -# iterator interface -function Base.iterate(pool::CachedPool) - if length(pool) == 0 - return nothing - else - return (pool.object[1], 1) - end -end - -function Base.iterate(pool::CachedPool, state) - if state >= length(pool) || length(pool) == 0 - return nothing - else - return (pool.object[state+1], state + 1) - end -end - - -function append(pool::CachedPool, object) - #ExprTree should not take care of the optimization problem - # that's why we comment out the following lines - - # @assert para isa eltype(pool.pool) - # for (oi, o) in enumerate(pool.object) - # if o == object - # return oi #existing obj - # end - # end - - id = length(pool.object) + 1 - push!(pool.object, object) - - return id #new momentum -end - -function initialize!(pool::CachedPool{O,T}) where {O,T} - N = length(pool) - resize!(pool.current, N) - fill!(pool.current, zero(T)) - - resize!(pool.new, N) - fill!(pool.new, zero(T)) - - resize!(pool.version, N) - fill!(pool.version, one(T)) - - resize!(pool.excited, N) - fill!(pool.excited, zero(T)) -end - -function updateAll(pool::CachedPool, ignoreCache::Bool, eval::Function; kwargs...) - N = length(pool.object) - if ignoreCache - T = eltype(pool.current) - for (idx, o) in enumerate(pool.object) - pool.current[idx] = T(eval(obj; kwargs...)) - end - else - error("not implemented!") - # pool.version .= 1 - # pool.excited .= false - end -end - -""" - struct LoopPool{T} - - Pool of loop basis. Each loop basis corresponds to a loop variable. - A loop variable is a linear combination of N independent loops. The combination coefficients is what we call a loop basis. - For example, if a loop is a momentum K, then - - varibale_i = K_1*basis[1, i] + K_2*basis[2, i] + K_3*basis[3, i] + ... - -# Members -- name::Symbol : name of the pool -- dim::Int : dimension of a loop variable (for example, the dimension of a momentum-frequency loop variable is (d+1) where d is the spatial dimension) -- N::Int : number of independent loops (dimension of loop basis) -- basis::Matrix{T} : Matrix of (N x Nb) that stores the loop basis, where Nb is the number of loop basis (or number of loop variables). -- current::Matrix{T} : Matrix of (dim x Nb) that stores the loop variables, where Nb is the number of loop basis (or number of loop variables). -""" -mutable struct LoopPool{T} - name::Symbol - dim::Int #dimension - loopNum::Int #number of independent loops - # N::Int #number of basis - basis::Matrix{T} # loopNum x N - current::Matrix{T} # dim x loopNum - - function LoopPool(name::Symbol, dim::Int, loopNum::Int, type::DataType=Float64) - basis = Matrix{type}(undef, loopNum, 0) # Nx0 matrix - current = Matrix{type}(undef, dim, 0) # dimx0 matrix - return new{type}(name, dim, loopNum, basis, current) - end - function LoopPool(name::Symbol, dim::Int, basis::AbstractVector{Vector{T}}) where {T} - @assert isempty(basis) == false - loopNum = length(basis[1]) - N = length(basis) #number of basis - @assert all(x -> length(x) == loopNum, basis) - current = rands(T, (dim, N)) - return new{T}(name, dim, loopNum, basis, current) - end -end - -Base.length(pool::LoopPool) = size(pool.basis)[2] -Base.size(pool::LoopPool) = length(pool) -Base.show(io::IO, pool::LoopPool) = print(io, pool.basis) -# Base.view(pool::Pool, inds...) = Base.view(pool.pool, inds...) - -#index interface for Pool -Base.getindex(pool::LoopPool, i) = pool.basis[:, i] -Base.setindex!(pool::LoopPool, v, i) = setindex!(pool.basis, v, i) -Base.firstindex(pool::LoopPool) = 1 -Base.lastindex(pool::LoopPool) = length(pool) - -# iterator interface -function Base.iterate(pool::LoopPool) - if length(pool) == 0 - return nothing - else - return (pool.basis[:, 1], 1) - end -end - -function Base.iterate(pool::LoopPool, state) - if state >= length(pool) || length(pool) == 0 - return nothing - else - return (pool.basis[:, state+1], state + 1) - end -end - -function update(pool::LoopPool, variable=rand(eltype(pool.current), pool.dim, pool.loopNum)) - @assert size(variable)[1] == pool.dim - # loopNum = size(pool.basis)[1] - loopNum = pool.loopNum - - ############ naive implementation, one allocation for each call ################ - # pool.current = view(variable, :, 1:loopNum) * pool.basis - - ############# BLAS call, no allocation, but takes ~1.6μs ######################## - #varK : M x (1:loopNum) - #basis : loopNum x N - #pool.current : M x N - # M, N = size(variable)[1], size(pool.basis)[2] - # ccall(("dgemm"), Cvoid, - # (Ref{UInt8}, Ref{UInt8}, Ref{BlasInt}, Ref{BlasInt}, - # Ref{BlasInt}, Ref{Float64}, Ptr{Float64}, Ref{BlasInt}, - # Ptr{Float64}, Ref{BlasInt}, Ref{Float64}, Ptr{Float64}, - # Ref{BlasInt}), - # 'N', 'N', M, N, loopNum, 1.0, variable, M, pool.basis, loopNum, 0.0, pool.current, M) - - ############### higher level BLAS call, no allocation, takes ~0.8μs ################ - # BLAS.gemm!('N', 'N', 1.0, view(variable, :, 1:loopNum), pool.basis, 0.0, pool.current) - - ############### higher level LinearAlgebra call, no allocation, takes ~0.8μs ################ - mul!(pool.current, view(variable, :, 1:loopNum), pool.basis) #use view will use less memory than variable[:, 1:loopNum] - - # B = view(pool.basis, 1:loopNum, :) - # B = view(pool.basis, 1:loopNum, :) - # C = pool.current[:, 1:length(pool)] - # LinearAlgebra.mul!(pool.current, A, pool.basis) - # LinearAlgebra.BLAS.gemm!('N', 'N', false, variable[:, 1:loopNum], pool.basis[1:loopNum, 1:length(pool)], false, pool.current[:, 1:length(pool)]) -end - -# current(pool::LoopPool, idx) = pool.current[:, idx] -current(pool::LoopPool, idx) = view(pool.current, :, idx) - -hasloop(pool::LoopPool) = (pool.dim > 0) && (pool.loopNum > 0) - -function append(pool::LoopPool, basis::AbstractVector) - for bi in 1:length(pool) - if pool.basis[:, bi] ≈ basis - # if (pool.basis[:, bi] ≈ basis) || (pool.basis[:, bi] ≈ -basis) - return bi - end - end - - pool.basis = hcat(pool.basis, basis) - pool.current = hcat(pool.current, rand(eltype(pool.current), pool.dim)) - # pool.size += 1 - # @assert pool.size <= size(pool.basis)[2] "Too many loop basis!. Increase maxSize when creates the LoopPool!" - # pool.basis[:, pool.size] = basis - return length(pool) -end diff --git a/src/expression_tree/tree.jl b/src/expression_tree/tree.jl deleted file mode 100644 index 00561561..00000000 --- a/src/expression_tree/tree.jl +++ /dev/null @@ -1,197 +0,0 @@ -""" - mutable struct Node{PARA,F} - - Node Object, which is the building block of the diagram tree. Each node is a collection of CACHED proapgator objects and other child CACHED node objects - -# Members -- para::PARA : user-defined parameters, which will be used to evaluate the factor and the weight of the node (e.g., if the node represents a vertex function, then the parameter may be the momentum basis of the external legs) -- operation::Int : #1: multiply, 2: add, ... -- factor::F : additional factor of the node -- components::Vector{Vector{Int}} : Index to the cached propagators stored in certain pools. Each Vector{Int} is for one kind of propagator. -- childNodes::Vector{Int} : Indices to the cached nodes stored in certain pool. They are the child of the current node in the diagram tree. -- parent::Int : Index to the cached nodes which is the parent of the current node. -""" -struct Node{PARA,F} - name::Symbol - para::PARA - operation::Int #1: multiply, 2: add, ... - factor::F - loopidx::Int - siteidx::Vector{Int} - children::Vector{Int} - isleaf::Bool - function Node{P,F}(name::Symbol, para; loopidx=0, siteidx=[], operator=ADD, children=[], factor=1.0) where {F,P} - # @assert typeof(para) == P - return new{P,F}(name, para, operator, F(factor), loopidx, siteidx, children, isempty(children)) - end -end - -# function Base.show(io::IO, node::Node) -# print(io, "Node#$(node.name):$(node.para)") -# end - -function Base.isequal(a::Node{P}, b::Node{P}) where {P} - # only parent is allowed to be different - if (isequal(a.para, b.para) == false) || (a.operation != b.operation) || (Set(a.children) != Set(b.children)) || (a.factor ≈ b.factor) == false || a.loopidx != b.loopidx || a.siteidx != b.siteidx - return false - else - return true - end -end -Base.:(==)(a::Node{P}, b::Node{P}) where {P} = Base.isequal(a, b) - -""" - mutable struct ExpressionTree{V,PARA,F,W} - - Diagram Object represents a set of Feynman diagrams in an experssion tree (forest) structure - -# Members -- name::Symbol : Name of the tree -- loopBasis::V : Tuple of pools of cached basis in a format of (BasisPool1, BasisPool2, ...) -- node::CachedPool{Node{PARA,F},W} : Pool of the nodes in the diagram tree -- root::Vector{Int} : indices of the cached nodes that are the root(s) of the diagram tree. Each element corresponds to one root. -""" -# mutable struct ExpressionTree{V,PARA,F,W} -struct ExpressionTree{V,PARA,F,W} - name::Symbol - loopBasis::V - node::CachedPool{Node{PARA,F},W} - root::Vector{Int} - function ExpressionTree{W,PARA}(; loopBasis::V, name=:none) where {V,W,PARA} - nodePool = CachedPool(:node, Node{PARA,W}, W) - return new{V,PARA,W,W}(name, loopBasis, nodePool, []) - end - function ExpressionTree(; loopBasis::V, weight::DataType, factor::DataType=weight, nodePara::DataType=Nothing, name=:none) where {V} - nodePool = CachedPool(:node, Node{nodePara,factor}, weight) - return new{V,nodePara,factor,weight}(name, loopBasis, nodePool, []) - end -end - -function setroot!(tree::ExpressionTree, root::AbstractVector) - resize!(tree.root, length(root)) - for (ri, r) in enumerate(root) - tree.root[ri] = r - end -end - -weight(tree::ExpressionTree) = tree.node.current - -Base.getindex(diag::ExpressionTree, i) = diag.node.current[diag.root[i]] -Base.firstindex(diag::ExpressionTree) = 1 -Base.lastindex(diag::ExpressionTree) = length(diag.root) - -""" - function addPropagator!(diag::ExpressionTree, name, factor = 1.0; site = [], loop = nothing, para = nothing, order::Int = 0) - - Add a propagator into the diagram tree. - -# Arguments -- diag : diagrammatic experssion tree. -- order::Int = 0 : Order of the propagator. -- name = :none : name of the propagator. -- factor = 1 : Factor of the propagator. -- site = [] : site basis (e.g, time and space coordinate) of the propagator. -- loop = nothing : loop basis (e.g, momentum and frequency) of the propagator. -- para = nothing : Additional paramenter required to evaluate the propagator. -""" -function addpropagator!(diag::ExpressionTree{V,PARA,F,W}, name, factor=1.0; site=[], loop=nothing, para=nothing, order::Int=0) where {V,PARA,F,W} - loopPool = diag.loopBasis - loopidx = 0 - if isnothing(loop) == false - @assert typeof(loop) <: AbstractVector "LoopBasis should be a Vector!" - loopidx = append(loopPool, loop) - end - # prop = Propagator{pPARA,F}(name, order, para, factor, loopidx, collect(site)) - prop = Node{PARA,F}(name, para; factor=factor, loopidx=loopidx, siteidx=collect(site)) - # pidx = append(diag.propagator, prop) - pidx = append(diag.node, prop) - # return component(pidx, false, propagatorPool[index].name) - return pidx -end - -""" - function addnode!(diag::ExpressionTree{V,PARA,F,W}, operator, name, children::Union{Tuple, AbstractVector}, factor = 1.0; para = nothing) where {V,PARA,F,W} - - Add a node into the expression tree. - -# Arguments -- diag::ExpressionTree : diagrammatic experssion tree. -- operator::Int : #1: multiply, 2: add, ... -- name : name of the node -- children : Indices to the cached nodes stored in certain pool. They are the child of the current node in the diagram tree. It should be in the format of Vector{Int}. -- factor = 1.0 : Factor of the node -- para = nothing : Additional paramenter required to evaluate the node. Set to nothing by default. -""" -function addnode!(diag::ExpressionTree{V,PARA,F,W}, operator, name, children::Union{Tuple,AbstractVector}, factor=1.0; para=nothing) where {V,PARA,F,W} - nodePool = diag.node - - for nidx in children - @assert nidx <= length(diag.node) "Failed to add node with propagator = $propagator, and child =$children. $nidx is not in nodePool." - end - - node = Node{PARA,F}(name, para; operator=operator, children=children, factor=factor) - - nidx = append(nodePool, node) - return nidx - # return component(nidx, true, :none) -end - -""" - function getNode(diag::Diagrams, nidx::Int) - - get Node in the diag with the index nidx. -""" -function getNode(diag, nidx::Int) - return diag.node.object[nidx] -end - -# function getPropagator(diag::Diagrams, pidx::Int) -# for p in diag.propagatorPool -# if p.name == poolName -# return p.object[pidx] -# end -# end -# error("$poolName propagator pool doesn't exist!") -# end - -""" - function getNodeWeight(tree, nidx::Int) - - get Node weight in the diagram experssion tree with the index nidx. -""" -function getNodeWeight(tree, nidx::Int) - return tree.node.current[nidx] -end - - -# function addpropagator!(diag, name, factor = 1.0; site = [], loop = nothing, para = nothing, order::Int = 0) -# pidx = addPropagator!(diag, name, factor; site = site, loop = loop, para = para, order = order) -# @assert pidx > 0 -# return Component(pidx, false, :propagator, diag.node.object[pidx]) -# end - -# function addnode!(diag, operator, name, components, factor = 1.0; para = nothing) -# _components = [c for c in components if c.index > 0] -# if operator == MUL -# if length(_components) < length(components) -# return zero(Component) #if some of the components doesn't exist, then product of the components doens't exist -# end -# elseif operator == ADD -# if length(_components) == 0 -# return zero(Component) #if all of the components doesn't exist, then sum of the components doens't exist -# end -# end - -# child = [] -# propagator = [] -# for c in collect(_components) -# @assert c isa Component "$c is not a DiagTree.Component" -# if c.isNode -# push!(child, c.index) -# else -# push!(propagator, c.index) -# end -# end -# nidx = addNode!(diag, operator, name, factor; propagator = propagator, child = child, para = para) -# return Component(nidx, true, diag.node.name, getNode(diag, nidx)) -# end \ No newline at end of file diff --git a/src/frontend/GV.jl b/src/frontend/GV.jl index c03aaafa..cd16f951 100644 --- a/src/frontend/GV.jl +++ b/src/frontend/GV.jl @@ -6,46 +6,22 @@ import ..ComputationalGraphs: FeynmanGraph import ..ComputationalGraphs: Graph import ..ComputationalGraphs: _dtype import ..Parquet +import ..Parquet: Filter, NoBubble, NoHartree, NoFock, DirectOnly +import ..Parquet: Wirreducible #remove all polarization subdiagrams +import ..Parquet: Girreducible #remove all self-energy inseration +import ..Parquet: NoBubble # true to remove all bubble subdiagram +import ..Parquet: Proper #ver4, ver3, and polarization diagrams may require to be irreducible along the transfer momentum/frequency +import ..Parquet: Response, Composite, ChargeCharge, SpinSpin, UpUp, UpDown +import ..Parquet: AnalyticProperty, Instant, Dynamic, D_Instant, D_Dynamic +import ..Parquet: DiagramType, VacuumDiag, SigmaDiag, GreenDiag, PolarDiag, Ver3Diag, Ver4Diag import ..Taylor -using ..DiagTree using ..FrontEnds using AbstractTrees import ..Utility: taylorexpansion! -import ..Filter -import ..Wirreducible #remove all polarization subdiagrams -import ..Girreducible #remove all self-energy inseration -import ..NoHartree -import ..NoFock -import ..NoBubble # true to remove all bubble subdiagram -import ..Proper #ver4, ver3, and polarization diagrams may require to be irreducible along the transfer momentum/frequency -import ..DirectOnly - -import ..DiagramType -import ..VacuumDiag -import ..GreenDiag -import ..SigmaDiag -import ..PolarDiag -import ..Ver3Diag -import ..Ver4Diag - -import ..Composite -import ..ChargeCharge -import ..SpinSpin -import ..UpUp -import ..UpDown -import ..Response - -import ..Instant -import ..Dynamic -import ..D_Instant -import ..D_Dynamic -import ..AnalyticProperty - import ..Interaction import ..DiagPara -import ..DiagParaF64 import ..DiagramId import ..Ver4Id @@ -274,9 +250,7 @@ function diagdict_parquet(type::Symbol, MaxOrder::Int, has_counterterm::Bool=tru for order in MinOrder:MaxOrder Taylor.set_variables("x y"; orders=[MaxOrder - order, MaxOrder - order]) para = diagPara(diagtype, isDynamic, spin, order, filter, transferLoop) - # legK = [DiagTree.getK(para.totalLoopNum + 3, 1), DiagTree.getK(para.totalLoopNum + 3, 2), DiagTree.getK(para.totalLoopNum + 3, 3)] - # d::Vector{Diagram{Float64}} = Parquet.vertex4(para, legK, channel).diagram - # diags::Vector{Diagram{Float64}} = Parquet.build(para).diagram + # legK = [Parquet.getK(para.totalLoopNum + 3, 1), Parquet.getK(para.totalLoopNum + 3, 2), Parquet.getK(para.totalLoopNum + 3, 3)] parquet_builder = Parquet.build(para) diags, extT = parquet_builder.diagram, parquet_builder.extT @@ -443,7 +417,7 @@ function diagPara(type, isDynamic::Bool, spin, order, filter, transferLoop=nothi end if isnothing(transferLoop) - return DiagParaF64( + return DiagPara( type=type, innerLoopNum=innerLoopNum, hasTau=true, @@ -452,7 +426,7 @@ function diagPara(type, isDynamic::Bool, spin, order, filter, transferLoop=nothi filter=filter, ) else - return DiagParaF64( + return DiagPara( type=type, innerLoopNum=innerLoopNum, hasTau=true, @@ -608,7 +582,7 @@ function leafstates_diagtree(leaf_maps::Vector{Dict{Int,Graph}}, maxloopNum::Int push!(leafOutTau[ikey], diagId.extT[2]) push!(leafOrders[ikey], leaf_orders) - push!(leafType[ikey], DiagTree.index(typeof(diagId))) + push!(leafType[ikey], Parquet.index(typeof(diagId))) end end diff --git a/src/frontend/GV_diagrams/groups_vertex4/4Vertex2_0_0.diag b/src/frontend/GV_diagrams/groups_vertex4/4Vertex2_0_0.diag new file mode 100644 index 00000000..a6ef92f3 --- /dev/null +++ b/src/frontend/GV_diagrams/groups_vertex4/4Vertex2_0_0.diag @@ -0,0 +1,32 @@ +#Type: SelfEnergy +#DiagNum: 1 +#Order: 2 +#GNum: 4 +#Ver4Num: 2 +#LoopNum: 3 +#ExtLoopIndex: 0 +#DummyLoopIndex: +#TauNum: 2 +#ExtTauIndex: 0 2 +#DummyTauIndex: + +# Permutation + 3 2 1 0 +# SymFactor +-1.0 +# GType +-2 -2 0 -2 +# VertexBasis + 0 0 1 1 + 1 1 0 0 +# LoopBasis + 1 0 1 0 + 0 1 1 0 + 1 0 0 1 +# Ver4Legs(InL,OutL,InR,OutR) + 3 0 2 1 | 1 2 0 3 | +# WType(Direct,Exchange) + 0 0 | 0 0 | +# SpinFactor +-2 1 + diff --git a/src/frontend/GV_diagrams/groups_vertex4/4Vertex2_0_1.diag b/src/frontend/GV_diagrams/groups_vertex4/4Vertex2_0_1.diag new file mode 100644 index 00000000..f3877e19 --- /dev/null +++ b/src/frontend/GV_diagrams/groups_vertex4/4Vertex2_0_1.diag @@ -0,0 +1,72 @@ +#Type: SelfEnergy +#DiagNum: 3 +#Order: 2 +#GNum: 4 +#Ver4Num: 2 +#LoopNum: 3 +#ExtLoopIndex: 0 +#DummyLoopIndex: +#TauNum: 2 +#ExtTauIndex: 0 2 +#DummyTauIndex: + +# Permutation + 3 2 1 0 +# SymFactor +-1.0 +# GType +-2 -2 1 -2 +# VertexBasis + 0 0 1 1 + 1 1 0 0 +# LoopBasis + 1 0 1 0 + 0 1 1 0 + 1 0 0 1 +# Ver4Legs(InL,OutL,InR,OutR) + 3 0 2 1 | 1 2 0 3 | +# WType(Direct,Exchange) + 0 0 | 0 0 | +# SpinFactor +-2 1 + +# Permutation + 3 2 1 0 +# SymFactor +-1.0 +# GType +-2 -2 0 -2 +# VertexBasis + 0 0 1 1 + 1 1 0 0 +# LoopBasis + 1 0 1 0 + 0 1 1 0 + 1 0 0 1 +# Ver4Legs(InL,OutL,InR,OutR) + 3 0 2 1 | 1 2 0 3 | +# WType(Direct,Exchange) + 0 0 | 0 0 | +# SpinFactor +-2 1 + +# Permutation + 3 2 1 0 +# SymFactor +-1.0 +# GType +-2 -2 0 -2 +# VertexBasis + 0 0 1 1 + 1 1 0 0 +# LoopBasis + 1 0 1 0 + 0 1 1 0 + 1 0 0 1 +# Ver4Legs(InL,OutL,InR,OutR) + 3 0 2 1 | 1 2 0 3 | +# WType(Direct,Exchange) + 0 0 | 0 0 | +# SpinFactor +-2 1 + diff --git a/src/frontend/GV_diagrams/groups_vertex4/4Vertex2_0_2.diag b/src/frontend/GV_diagrams/groups_vertex4/4Vertex2_0_2.diag new file mode 100644 index 00000000..13a29262 --- /dev/null +++ b/src/frontend/GV_diagrams/groups_vertex4/4Vertex2_0_2.diag @@ -0,0 +1,132 @@ +#Type: SelfEnergy +#DiagNum: 6 +#Order: 2 +#GNum: 4 +#Ver4Num: 2 +#LoopNum: 3 +#ExtLoopIndex: 0 +#DummyLoopIndex: +#TauNum: 2 +#ExtTauIndex: 0 2 +#DummyTauIndex: + +# Permutation + 3 2 1 0 +# SymFactor +-1.0 +# GType +-2 -2 2 -2 +# VertexBasis + 0 0 1 1 + 1 1 0 0 +# LoopBasis + 1 0 1 0 + 0 1 1 0 + 1 0 0 1 +# Ver4Legs(InL,OutL,InR,OutR) + 3 0 2 1 | 1 2 0 3 | +# WType(Direct,Exchange) + 0 0 | 0 0 | +# SpinFactor +-2 1 + +# Permutation + 3 2 1 0 +# SymFactor +-1.0 +# GType +-2 -2 1 -2 +# VertexBasis + 0 0 1 1 + 1 1 0 0 +# LoopBasis + 1 0 1 0 + 0 1 1 0 + 1 0 0 1 +# Ver4Legs(InL,OutL,InR,OutR) + 3 0 2 1 | 1 2 0 3 | +# WType(Direct,Exchange) + 0 0 | 0 0 | +# SpinFactor +-2 1 + +# Permutation + 3 2 1 0 +# SymFactor +-1.0 +# GType +-2 -2 0 -2 +# VertexBasis + 0 0 1 1 + 1 1 0 0 +# LoopBasis + 1 0 1 0 + 0 1 1 0 + 1 0 0 1 +# Ver4Legs(InL,OutL,InR,OutR) + 3 0 2 1 | 1 2 0 3 | +# WType(Direct,Exchange) + 0 0 | 0 0 | +# SpinFactor +-2 1 + +# Permutation + 3 2 1 0 +# SymFactor +-1.0 +# GType +-2 -2 1 -2 +# VertexBasis + 0 0 1 1 + 1 1 0 0 +# LoopBasis + 1 0 1 0 + 0 1 1 0 + 1 0 0 1 +# Ver4Legs(InL,OutL,InR,OutR) + 3 0 2 1 | 1 2 0 3 | +# WType(Direct,Exchange) + 0 0 | 0 0 | +# SpinFactor +-2 1 + +# Permutation + 3 2 1 0 +# SymFactor +-1.0 +# GType +-2 -2 0 -2 +# VertexBasis + 0 0 1 1 + 1 1 0 0 +# LoopBasis + 1 0 1 0 + 0 1 1 0 + 1 0 0 1 +# Ver4Legs(InL,OutL,InR,OutR) + 3 0 2 1 | 1 2 0 3 | +# WType(Direct,Exchange) + 0 0 | 0 0 | +# SpinFactor +-2 1 + +# Permutation + 3 2 1 0 +# SymFactor +-1.0 +# GType +-2 -2 0 -2 +# VertexBasis + 0 0 1 1 + 1 1 0 0 +# LoopBasis + 1 0 1 0 + 0 1 1 0 + 1 0 0 1 +# Ver4Legs(InL,OutL,InR,OutR) + 3 0 2 1 | 1 2 0 3 | +# WType(Direct,Exchange) + 0 0 | 0 0 | +# SpinFactor +-2 1 + diff --git a/src/frontend/GV_diagrams/groups_vertex4/4Vertex2_1_0.diag b/src/frontend/GV_diagrams/groups_vertex4/4Vertex2_1_0.diag new file mode 100644 index 00000000..8518b8e9 --- /dev/null +++ b/src/frontend/GV_diagrams/groups_vertex4/4Vertex2_1_0.diag @@ -0,0 +1,52 @@ +#Type: SelfEnergy +#DiagNum: 2 +#Order: 2 +#GNum: 4 +#Ver4Num: 2 +#LoopNum: 3 +#ExtLoopIndex: 0 +#DummyLoopIndex: +#TauNum: 2 +#ExtTauIndex: 0 2 +#DummyTauIndex: + +# Permutation + 3 2 1 0 +# SymFactor +-1.0 +# GType +-2 -2 0 -2 +# VertexBasis + 0 0 1 1 + 1 1 0 0 +# LoopBasis + 1 0 1 0 + 0 1 1 0 + 1 0 0 1 +# Ver4Legs(InL,OutL,InR,OutR) + 3 0 2 1 | 1 2 0 3 | +# WType(Direct,Exchange) + 0 0 | 1 1 | +# SpinFactor +-2 1 + +# Permutation + 3 2 1 0 +# SymFactor +-1.0 +# GType +-2 -2 0 -2 +# VertexBasis + 0 0 1 1 + 1 1 0 0 +# LoopBasis + 1 0 1 0 + 0 1 1 0 + 1 0 0 1 +# Ver4Legs(InL,OutL,InR,OutR) + 3 0 2 1 | 1 2 0 3 | +# WType(Direct,Exchange) + 1 1 | 0 0 | +# SpinFactor +-2 1 + diff --git a/src/frontend/GV_diagrams/groups_vertex4/4Vertex2_1_1.diag b/src/frontend/GV_diagrams/groups_vertex4/4Vertex2_1_1.diag new file mode 100644 index 00000000..f4459f16 --- /dev/null +++ b/src/frontend/GV_diagrams/groups_vertex4/4Vertex2_1_1.diag @@ -0,0 +1,132 @@ +#Type: SelfEnergy +#DiagNum: 6 +#Order: 2 +#GNum: 4 +#Ver4Num: 2 +#LoopNum: 3 +#ExtLoopIndex: 0 +#DummyLoopIndex: +#TauNum: 2 +#ExtTauIndex: 0 2 +#DummyTauIndex: + +# Permutation + 3 2 1 0 +# SymFactor +-1.0 +# GType +-2 -2 1 -2 +# VertexBasis + 0 0 1 1 + 1 1 0 0 +# LoopBasis + 1 0 1 0 + 0 1 1 0 + 1 0 0 1 +# Ver4Legs(InL,OutL,InR,OutR) + 3 0 2 1 | 1 2 0 3 | +# WType(Direct,Exchange) + 0 0 | 1 1 | +# SpinFactor +-2 1 + +# Permutation + 3 2 1 0 +# SymFactor +-1.0 +# GType +-2 -2 0 -2 +# VertexBasis + 0 0 1 1 + 1 1 0 0 +# LoopBasis + 1 0 1 0 + 0 1 1 0 + 1 0 0 1 +# Ver4Legs(InL,OutL,InR,OutR) + 3 0 2 1 | 1 2 0 3 | +# WType(Direct,Exchange) + 0 0 | 1 1 | +# SpinFactor +-2 1 + +# Permutation + 3 2 1 0 +# SymFactor +-1.0 +# GType +-2 -2 0 -2 +# VertexBasis + 0 0 1 1 + 1 1 0 0 +# LoopBasis + 1 0 1 0 + 0 1 1 0 + 1 0 0 1 +# Ver4Legs(InL,OutL,InR,OutR) + 3 0 2 1 | 1 2 0 3 | +# WType(Direct,Exchange) + 0 0 | 1 1 | +# SpinFactor +-2 1 + +# Permutation + 3 2 1 0 +# SymFactor +-1.0 +# GType +-2 -2 1 -2 +# VertexBasis + 0 0 1 1 + 1 1 0 0 +# LoopBasis + 1 0 1 0 + 0 1 1 0 + 1 0 0 1 +# Ver4Legs(InL,OutL,InR,OutR) + 3 0 2 1 | 1 2 0 3 | +# WType(Direct,Exchange) + 1 1 | 0 0 | +# SpinFactor +-2 1 + +# Permutation + 3 2 1 0 +# SymFactor +-1.0 +# GType +-2 -2 0 -2 +# VertexBasis + 0 0 1 1 + 1 1 0 0 +# LoopBasis + 1 0 1 0 + 0 1 1 0 + 1 0 0 1 +# Ver4Legs(InL,OutL,InR,OutR) + 3 0 2 1 | 1 2 0 3 | +# WType(Direct,Exchange) + 1 1 | 0 0 | +# SpinFactor +-2 1 + +# Permutation + 3 2 1 0 +# SymFactor +-1.0 +# GType +-2 -2 0 -2 +# VertexBasis + 0 0 1 1 + 1 1 0 0 +# LoopBasis + 1 0 1 0 + 0 1 1 0 + 1 0 0 1 +# Ver4Legs(InL,OutL,InR,OutR) + 3 0 2 1 | 1 2 0 3 | +# WType(Direct,Exchange) + 1 1 | 0 0 | +# SpinFactor +-2 1 + diff --git a/src/frontend/GV_diagrams/groups_vertex4/4Vertex2_2_0.diag b/src/frontend/GV_diagrams/groups_vertex4/4Vertex2_2_0.diag new file mode 100644 index 00000000..9c6dd4a3 --- /dev/null +++ b/src/frontend/GV_diagrams/groups_vertex4/4Vertex2_2_0.diag @@ -0,0 +1,72 @@ +#Type: SelfEnergy +#DiagNum: 3 +#Order: 2 +#GNum: 4 +#Ver4Num: 2 +#LoopNum: 3 +#ExtLoopIndex: 0 +#DummyLoopIndex: +#TauNum: 2 +#ExtTauIndex: 0 2 +#DummyTauIndex: + +# Permutation + 3 2 1 0 +# SymFactor +-1.0 +# GType +-2 -2 0 -2 +# VertexBasis + 0 0 1 1 + 1 1 0 0 +# LoopBasis + 1 0 1 0 + 0 1 1 0 + 1 0 0 1 +# Ver4Legs(InL,OutL,InR,OutR) + 3 0 2 1 | 1 2 0 3 | +# WType(Direct,Exchange) + 0 0 | 2 2 | +# SpinFactor +-2 1 + +# Permutation + 3 2 1 0 +# SymFactor +-1.0 +# GType +-2 -2 0 -2 +# VertexBasis + 0 0 1 1 + 1 1 0 0 +# LoopBasis + 1 0 1 0 + 0 1 1 0 + 1 0 0 1 +# Ver4Legs(InL,OutL,InR,OutR) + 3 0 2 1 | 1 2 0 3 | +# WType(Direct,Exchange) + 1 1 | 1 1 | +# SpinFactor +-2 1 + +# Permutation + 3 2 1 0 +# SymFactor +-1.0 +# GType +-2 -2 0 -2 +# VertexBasis + 0 0 1 1 + 1 1 0 0 +# LoopBasis + 1 0 1 0 + 0 1 1 0 + 1 0 0 1 +# Ver4Legs(InL,OutL,InR,OutR) + 3 0 2 1 | 1 2 0 3 | +# WType(Direct,Exchange) + 2 2 | 0 0 | +# SpinFactor +-2 1 + diff --git a/src/frontend/GV_diagrams/groups_vertex4/4Vertex3_0_0.diag b/src/frontend/GV_diagrams/groups_vertex4/4Vertex3_0_0.diag new file mode 100644 index 00000000..9dd8a407 --- /dev/null +++ b/src/frontend/GV_diagrams/groups_vertex4/4Vertex3_0_0.diag @@ -0,0 +1,138 @@ +#Type: SelfEnergy +#DiagNum: 6 +#Order: 3 +#GNum: 6 +#Ver4Num: 3 +#LoopNum: 4 +#ExtLoopIndex: 0 +#DummyLoopIndex: +#TauNum: 3 +#ExtTauIndex: 0 2 +#DummyTauIndex: + +# Permutation + 2 4 0 1 3 5 +# SymFactor +-1.0 +# GType +-2 -2 -2 0 0 0 +# VertexBasis + 0 0 1 1 2 2 + 1 2 0 0 1 2 +# LoopBasis + 1 0 0 1 1 0 + 0 0 1 0 0 0 + 0 1 0 1 1 0 + 1 0 0 0 0 1 +# Ver4Legs(InL,OutL,InR,OutR) + 2 0 3 1 | 0 2 4 3 | 1 4 5 5 | +# WType(Direct,Exchange) + 0 0 | 0 0 | 0 0 | +# SpinFactor +-4 2 2 -1 + +# Permutation + 3 5 4 0 2 1 +# SymFactor +-1.0 +# GType +-2 -2 0 -2 0 0 +# VertexBasis + 0 0 1 1 2 2 + 1 2 2 0 1 0 +# LoopBasis + 1 0 1 0 1 0 + 0 1 1 0 0 0 + 0 0 0 1 1 0 + 1 0 0 0 0 1 +# Ver4Legs(InL,OutL,InR,OutR) + 3 0 5 1 | 4 2 0 3 | 2 4 1 5 | +# WType(Direct,Exchange) + 0 0 | 0 0 | 0 0 | +# SpinFactor +-4 2 2 -1 + +# Permutation + 2 4 0 1 3 5 +# SymFactor +-1.0 +# GType +-2 -2 -2 0 0 0 +# VertexBasis + 0 0 1 1 2 2 + 1 2 0 0 1 2 +# LoopBasis + 1 0 0 1 0 0 + 1 0 1 0 0 0 + 0 1 0 1 1 0 + 0 0 0 0 0 1 +# Ver4Legs(InL,OutL,InR,OutR) + 2 0 3 1 | 0 2 4 3 | 1 4 5 5 | +# WType(Direct,Exchange) + 0 0 | 0 0 | 0 0 | +# SpinFactor + 0 2 0 -1 + +# Permutation + 5 3 0 1 4 2 +# SymFactor +-1.0 +# GType +-2 -2 -2 0 0 0 +# VertexBasis + 0 0 1 1 2 2 + 2 1 0 0 2 1 +# LoopBasis + 1 0 0 1 0 1 + 0 0 1 0 0 0 + 1 0 0 1 1 0 + 0 1 0 0 0 1 +# Ver4Legs(InL,OutL,InR,OutR) + 2 0 3 1 | 5 2 1 3 | 4 4 0 5 | +# WType(Direct,Exchange) + 0 0 | 0 0 | 0 0 | +# SpinFactor + 0 2 0 -1 + +# Permutation + 3 2 0 1 5 4 +# SymFactor +1.0 +# GType +-2 -2 -2 0 0 0 +# VertexBasis + 0 0 1 1 2 2 + 1 1 0 0 2 2 +# LoopBasis + 1 0 0 0 0 1 + 0 1 0 0 -1 1 + 0 0 0 1 1 0 + 1 0 1 0 1 0 +# Ver4Legs(InL,OutL,InR,OutR) + 2 0 3 1 | 1 2 0 3 | 5 4 4 5 | +# WType(Direct,Exchange) + 0 0 | 0 0 | 0 0 | +# SpinFactor +-2 0 4 0 + +# Permutation + 5 4 0 1 3 2 +# SymFactor +0.5 +# GType +-2 -2 -2 0 0 0 +# VertexBasis + 0 0 1 1 2 2 + 2 2 0 0 1 1 +# LoopBasis + 1 0 0 1 1 0 + 0 0 0 0 -1 1 + 0 1 0 1 1 0 + 1 0 1 0 1 0 +# Ver4Legs(InL,OutL,InR,OutR) + 2 0 3 1 | 5 2 4 3 | 1 4 0 5 | +# WType(Direct,Exchange) + 0 0 | 0 0 | 0 0 | +# SpinFactor +-2 1 1 -2 + diff --git a/src/frontend/GV_diagrams/groups_vertex4/4Vertex3_0_1.diag b/src/frontend/GV_diagrams/groups_vertex4/4Vertex3_0_1.diag new file mode 100644 index 00000000..d1cf5a3f --- /dev/null +++ b/src/frontend/GV_diagrams/groups_vertex4/4Vertex3_0_1.diag @@ -0,0 +1,642 @@ +#Type: SelfEnergy +#DiagNum: 30 +#Order: 3 +#GNum: 6 +#Ver4Num: 3 +#LoopNum: 4 +#ExtLoopIndex: 0 +#DummyLoopIndex: +#TauNum: 3 +#ExtTauIndex: 0 2 +#DummyTauIndex: + +# Permutation + 2 4 0 1 3 5 +# SymFactor +-1.0 +# GType +-2 -2 -2 0 0 1 +# VertexBasis + 0 0 1 1 2 2 + 1 2 0 0 1 2 +# LoopBasis + 1 0 0 1 0 0 + 1 0 1 0 0 0 + 0 1 0 1 1 0 + 0 0 0 0 0 1 +# Ver4Legs(InL,OutL,InR,OutR) + 2 0 3 1 | 0 2 4 3 | 1 4 5 5 | +# WType(Direct,Exchange) + 0 0 | 0 0 | 0 0 | +# SpinFactor + 0 2 0 -1 + +# Permutation + 5 3 0 1 4 2 +# SymFactor +-1.0 +# GType +-2 -2 -2 0 0 1 +# VertexBasis + 0 0 1 1 2 2 + 2 1 0 0 2 1 +# LoopBasis + 1 0 0 1 0 1 + 0 0 1 0 0 0 + 1 0 0 1 1 0 + 0 1 0 0 0 1 +# Ver4Legs(InL,OutL,InR,OutR) + 2 0 3 1 | 5 2 1 3 | 4 4 0 5 | +# WType(Direct,Exchange) + 0 0 | 0 0 | 0 0 | +# SpinFactor + 0 2 0 -1 + +# Permutation + 3 2 0 1 5 4 +# SymFactor +1.0 +# GType +-2 -2 -2 0 0 1 +# VertexBasis + 0 0 1 1 2 2 + 1 1 0 0 2 2 +# LoopBasis + 1 0 0 0 0 1 + 0 1 0 0 -1 1 + 0 0 0 1 1 0 + 1 0 1 0 1 0 +# Ver4Legs(InL,OutL,InR,OutR) + 2 0 3 1 | 1 2 0 3 | 5 4 4 5 | +# WType(Direct,Exchange) + 0 0 | 0 0 | 0 0 | +# SpinFactor +-2 0 4 0 + +# Permutation + 5 4 0 1 3 2 +# SymFactor +0.5 +# GType +-2 -2 -2 0 0 1 +# VertexBasis + 0 0 1 1 2 2 + 2 2 0 0 1 1 +# LoopBasis + 1 0 0 1 1 0 + 0 0 0 0 -1 1 + 0 1 0 1 1 0 + 1 0 1 0 1 0 +# Ver4Legs(InL,OutL,InR,OutR) + 2 0 3 1 | 5 2 4 3 | 1 4 0 5 | +# WType(Direct,Exchange) + 0 0 | 0 0 | 0 0 | +# SpinFactor +-2 1 1 -2 + +# Permutation + 2 4 0 1 3 5 +# SymFactor +-1.0 +# GType +-2 -2 -2 0 1 0 +# VertexBasis + 0 0 1 1 2 2 + 1 2 0 0 1 2 +# LoopBasis + 1 0 0 1 1 0 + 0 0 1 0 0 0 + 0 1 0 1 1 0 + 1 0 0 0 0 1 +# Ver4Legs(InL,OutL,InR,OutR) + 2 0 3 1 | 0 2 4 3 | 1 4 5 5 | +# WType(Direct,Exchange) + 0 0 | 0 0 | 0 0 | +# SpinFactor +-4 2 2 -1 + +# Permutation + 3 5 4 0 2 1 +# SymFactor +-1.0 +# GType +-2 -2 0 -2 1 0 +# VertexBasis + 0 0 1 1 2 2 + 1 2 2 0 1 0 +# LoopBasis + 1 0 1 0 1 0 + 0 1 1 0 0 0 + 0 0 0 1 1 0 + 1 0 0 0 0 1 +# Ver4Legs(InL,OutL,InR,OutR) + 3 0 5 1 | 4 2 0 3 | 2 4 1 5 | +# WType(Direct,Exchange) + 0 0 | 0 0 | 0 0 | +# SpinFactor +-4 2 2 -1 + +# Permutation + 2 4 0 1 3 5 +# SymFactor +-1.0 +# GType +-2 -2 -2 0 1 0 +# VertexBasis + 0 0 1 1 2 2 + 1 2 0 0 1 2 +# LoopBasis + 1 0 0 1 0 0 + 1 0 1 0 0 0 + 0 1 0 1 1 0 + 0 0 0 0 0 1 +# Ver4Legs(InL,OutL,InR,OutR) + 2 0 3 1 | 0 2 4 3 | 1 4 5 5 | +# WType(Direct,Exchange) + 0 0 | 0 0 | 0 0 | +# SpinFactor + 0 2 0 -1 + +# Permutation + 3 2 0 1 5 4 +# SymFactor +1.0 +# GType +-2 -2 -2 0 1 0 +# VertexBasis + 0 0 1 1 2 2 + 1 1 0 0 2 2 +# LoopBasis + 1 0 0 0 0 1 + 0 1 0 0 -1 1 + 0 0 0 1 1 0 + 1 0 1 0 1 0 +# Ver4Legs(InL,OutL,InR,OutR) + 2 0 3 1 | 1 2 0 3 | 5 4 4 5 | +# WType(Direct,Exchange) + 0 0 | 0 0 | 0 0 | +# SpinFactor +-2 0 4 0 + +# Permutation + 5 4 0 1 3 2 +# SymFactor +0.5 +# GType +-2 -2 -2 0 1 0 +# VertexBasis + 0 0 1 1 2 2 + 2 2 0 0 1 1 +# LoopBasis + 1 0 0 1 1 0 + 0 0 0 0 -1 1 + 0 1 0 1 1 0 + 1 0 1 0 1 0 +# Ver4Legs(InL,OutL,InR,OutR) + 2 0 3 1 | 5 2 4 3 | 1 4 0 5 | +# WType(Direct,Exchange) + 0 0 | 0 0 | 0 0 | +# SpinFactor +-2 1 1 -2 + +# Permutation + 2 4 0 1 3 5 +# SymFactor +-1.0 +# GType +-2 -2 -2 1 0 0 +# VertexBasis + 0 0 1 1 2 2 + 1 2 0 0 1 2 +# LoopBasis + 1 0 0 1 1 0 + 0 0 1 0 0 0 + 0 1 0 1 1 0 + 1 0 0 0 0 1 +# Ver4Legs(InL,OutL,InR,OutR) + 2 0 3 1 | 0 2 4 3 | 1 4 5 5 | +# WType(Direct,Exchange) + 0 0 | 0 0 | 0 0 | +# SpinFactor +-4 2 2 -1 + +# Permutation + 3 5 4 0 2 1 +# SymFactor +-1.0 +# GType +-2 -2 0 -2 0 0 +# VertexBasis + 0 0 1 1 2 2 + 1 2 2 0 1 0 +# LoopBasis + 1 0 1 0 1 0 + 0 1 1 0 0 0 + 0 0 0 1 1 0 + 1 0 0 0 0 1 +# Ver4Legs(InL,OutL,InR,OutR) + 3 0 5 1 | 4 2 0 3 | 2 4 1 5 | +# WType(Direct,Exchange) + 0 0 | 0 0 | 0 0 | +# SpinFactor +-4 2 2 -1 + +# Permutation + 2 4 0 1 3 5 +# SymFactor +-1.0 +# GType +-2 -2 -2 1 0 0 +# VertexBasis + 0 0 1 1 2 2 + 1 2 0 0 1 2 +# LoopBasis + 1 0 0 1 0 0 + 1 0 1 0 0 0 + 0 1 0 1 1 0 + 0 0 0 0 0 1 +# Ver4Legs(InL,OutL,InR,OutR) + 2 0 3 1 | 0 2 4 3 | 1 4 5 5 | +# WType(Direct,Exchange) + 0 0 | 0 0 | 0 0 | +# SpinFactor + 0 2 0 -1 + +# Permutation + 5 3 0 1 4 2 +# SymFactor +-1.0 +# GType +-2 -2 -2 1 0 0 +# VertexBasis + 0 0 1 1 2 2 + 2 1 0 0 2 1 +# LoopBasis + 1 0 0 1 0 1 + 0 0 1 0 0 0 + 1 0 0 1 1 0 + 0 1 0 0 0 1 +# Ver4Legs(InL,OutL,InR,OutR) + 2 0 3 1 | 5 2 1 3 | 4 4 0 5 | +# WType(Direct,Exchange) + 0 0 | 0 0 | 0 0 | +# SpinFactor + 0 2 0 -1 + +# Permutation + 3 2 0 1 5 4 +# SymFactor +1.0 +# GType +-2 -2 -2 1 0 0 +# VertexBasis + 0 0 1 1 2 2 + 1 1 0 0 2 2 +# LoopBasis + 1 0 0 0 0 1 + 0 1 0 0 -1 1 + 0 0 0 1 1 0 + 1 0 1 0 1 0 +# Ver4Legs(InL,OutL,InR,OutR) + 2 0 3 1 | 1 2 0 3 | 5 4 4 5 | +# WType(Direct,Exchange) + 0 0 | 0 0 | 0 0 | +# SpinFactor +-2 0 4 0 + +# Permutation + 5 4 0 1 3 2 +# SymFactor +0.5 +# GType +-2 -2 -2 1 0 0 +# VertexBasis + 0 0 1 1 2 2 + 2 2 0 0 1 1 +# LoopBasis + 1 0 0 1 1 0 + 0 0 0 0 -1 1 + 0 1 0 1 1 0 + 1 0 1 0 1 0 +# Ver4Legs(InL,OutL,InR,OutR) + 2 0 3 1 | 5 2 4 3 | 1 4 0 5 | +# WType(Direct,Exchange) + 0 0 | 0 0 | 0 0 | +# SpinFactor +-2 1 1 -2 + +# Permutation + 2 4 0 1 3 5 +# SymFactor +-1.0 +# GType +-2 -2 -2 0 0 0 +# VertexBasis + 0 0 1 1 2 2 + 1 2 0 0 1 2 +# LoopBasis + 1 0 0 1 1 0 + 0 0 1 0 0 0 + 0 1 0 1 1 0 + 1 0 0 0 0 1 +# Ver4Legs(InL,OutL,InR,OutR) + 2 0 3 1 | 0 2 4 3 | 1 4 5 5 | +# WType(Direct,Exchange) + 0 0 | 0 0 | 0 0 | +# SpinFactor +-4 2 2 -1 + +# Permutation + 3 5 4 0 2 1 +# SymFactor +-1.0 +# GType +-2 -2 1 -2 0 0 +# VertexBasis + 0 0 1 1 2 2 + 1 2 2 0 1 0 +# LoopBasis + 1 0 1 0 1 0 + 0 1 1 0 0 0 + 0 0 0 1 1 0 + 1 0 0 0 0 1 +# Ver4Legs(InL,OutL,InR,OutR) + 3 0 5 1 | 4 2 0 3 | 2 4 1 5 | +# WType(Direct,Exchange) + 0 0 | 0 0 | 0 0 | +# SpinFactor +-4 2 2 -1 + +# Permutation + 5 3 0 1 4 2 +# SymFactor +-1.0 +# GType +-2 -2 -2 0 0 0 +# VertexBasis + 0 0 1 1 2 2 + 2 1 0 0 2 1 +# LoopBasis + 1 0 0 1 0 1 + 0 0 1 0 0 0 + 1 0 0 1 1 0 + 0 1 0 0 0 1 +# Ver4Legs(InL,OutL,InR,OutR) + 2 0 3 1 | 5 2 1 3 | 4 4 0 5 | +# WType(Direct,Exchange) + 0 0 | 0 0 | 0 0 | +# SpinFactor + 0 2 0 -1 + +# Permutation + 2 4 0 1 3 5 +# SymFactor +-1.0 +# GType +-2 -2 -2 0 0 0 +# VertexBasis + 0 0 1 1 2 2 + 1 2 0 0 1 2 +# LoopBasis + 1 0 0 1 1 0 + 0 0 1 0 0 0 + 0 1 0 1 1 0 + 1 0 0 0 0 1 +# Ver4Legs(InL,OutL,InR,OutR) + 2 0 3 1 | 0 2 4 3 | 1 4 5 5 | +# WType(Direct,Exchange) + 0 0 | 0 0 | 0 0 | +# SpinFactor +-4 2 2 -1 + +# Permutation + 3 5 4 0 2 1 +# SymFactor +-1.0 +# GType +-2 -2 0 -2 0 0 +# VertexBasis + 0 0 1 1 2 2 + 1 2 2 0 1 0 +# LoopBasis + 1 0 1 0 1 0 + 0 1 1 0 0 0 + 0 0 0 1 1 0 + 1 0 0 0 0 1 +# Ver4Legs(InL,OutL,InR,OutR) + 3 0 5 1 | 4 2 0 3 | 2 4 1 5 | +# WType(Direct,Exchange) + 0 0 | 0 0 | 0 0 | +# SpinFactor +-4 2 2 -1 + +# Permutation + 2 4 0 1 3 5 +# SymFactor +-1.0 +# GType +-2 -2 -2 0 0 0 +# VertexBasis + 0 0 1 1 2 2 + 1 2 0 0 1 2 +# LoopBasis + 1 0 0 1 0 0 + 1 0 1 0 0 0 + 0 1 0 1 1 0 + 0 0 0 0 0 1 +# Ver4Legs(InL,OutL,InR,OutR) + 2 0 3 1 | 0 2 4 3 | 1 4 5 5 | +# WType(Direct,Exchange) + 0 0 | 0 0 | 0 0 | +# SpinFactor + 0 2 0 -1 + +# Permutation + 5 3 0 1 4 2 +# SymFactor +-1.0 +# GType +-2 -2 -2 0 0 0 +# VertexBasis + 0 0 1 1 2 2 + 2 1 0 0 2 1 +# LoopBasis + 1 0 0 1 0 1 + 0 0 1 0 0 0 + 1 0 0 1 1 0 + 0 1 0 0 0 1 +# Ver4Legs(InL,OutL,InR,OutR) + 2 0 3 1 | 5 2 1 3 | 4 4 0 5 | +# WType(Direct,Exchange) + 0 0 | 0 0 | 0 0 | +# SpinFactor + 0 2 0 -1 + +# Permutation + 3 2 0 1 5 4 +# SymFactor +1.0 +# GType +-2 -2 -2 0 0 0 +# VertexBasis + 0 0 1 1 2 2 + 1 1 0 0 2 2 +# LoopBasis + 1 0 0 0 0 1 + 0 1 0 0 -1 1 + 0 0 0 1 1 0 + 1 0 1 0 1 0 +# Ver4Legs(InL,OutL,InR,OutR) + 2 0 3 1 | 1 2 0 3 | 5 4 4 5 | +# WType(Direct,Exchange) + 0 0 | 0 0 | 0 0 | +# SpinFactor +-2 0 4 0 + +# Permutation + 5 4 0 1 3 2 +# SymFactor +0.5 +# GType +-2 -2 -2 0 0 0 +# VertexBasis + 0 0 1 1 2 2 + 2 2 0 0 1 1 +# LoopBasis + 1 0 0 1 1 0 + 0 0 0 0 -1 1 + 0 1 0 1 1 0 + 1 0 1 0 1 0 +# Ver4Legs(InL,OutL,InR,OutR) + 2 0 3 1 | 5 2 4 3 | 1 4 0 5 | +# WType(Direct,Exchange) + 0 0 | 0 0 | 0 0 | +# SpinFactor +-2 1 1 -2 + +# Permutation + 2 4 0 1 3 5 +# SymFactor +-1.0 +# GType +-2 -2 -2 0 0 0 +# VertexBasis + 0 0 1 1 2 2 + 1 2 0 0 1 2 +# LoopBasis + 1 0 0 1 1 0 + 0 0 1 0 0 0 + 0 1 0 1 1 0 + 1 0 0 0 0 1 +# Ver4Legs(InL,OutL,InR,OutR) + 2 0 3 1 | 0 2 4 3 | 1 4 5 5 | +# WType(Direct,Exchange) + 0 0 | 0 0 | 0 0 | +# SpinFactor +-4 2 2 -1 + +# Permutation + 3 5 4 0 2 1 +# SymFactor +-1.0 +# GType +-2 -2 0 -2 0 0 +# VertexBasis + 0 0 1 1 2 2 + 1 2 2 0 1 0 +# LoopBasis + 1 0 1 0 1 0 + 0 1 1 0 0 0 + 0 0 0 1 1 0 + 1 0 0 0 0 1 +# Ver4Legs(InL,OutL,InR,OutR) + 3 0 5 1 | 4 2 0 3 | 2 4 1 5 | +# WType(Direct,Exchange) + 0 0 | 0 0 | 0 0 | +# SpinFactor +-4 2 2 -1 + +# Permutation + 2 4 0 1 3 5 +# SymFactor +-1.0 +# GType +-2 -2 -2 0 0 0 +# VertexBasis + 0 0 1 1 2 2 + 1 2 0 0 1 2 +# LoopBasis + 1 0 0 1 0 0 + 1 0 1 0 0 0 + 0 1 0 1 1 0 + 0 0 0 0 0 1 +# Ver4Legs(InL,OutL,InR,OutR) + 2 0 3 1 | 0 2 4 3 | 1 4 5 5 | +# WType(Direct,Exchange) + 0 0 | 0 0 | 0 0 | +# SpinFactor + 0 2 0 -1 + +# Permutation + 5 3 0 1 4 2 +# SymFactor +-1.0 +# GType +-2 -2 -2 0 0 0 +# VertexBasis + 0 0 1 1 2 2 + 2 1 0 0 2 1 +# LoopBasis + 1 0 0 1 0 1 + 0 0 1 0 0 0 + 1 0 0 1 1 0 + 0 1 0 0 0 1 +# Ver4Legs(InL,OutL,InR,OutR) + 2 0 3 1 | 5 2 1 3 | 4 4 0 5 | +# WType(Direct,Exchange) + 0 0 | 0 0 | 0 0 | +# SpinFactor + 0 2 0 -1 + +# Permutation + 3 2 0 1 5 4 +# SymFactor +1.0 +# GType +-2 -2 -2 0 0 0 +# VertexBasis + 0 0 1 1 2 2 + 1 1 0 0 2 2 +# LoopBasis + 1 0 0 0 0 1 + 0 1 0 0 -1 1 + 0 0 0 1 1 0 + 1 0 1 0 1 0 +# Ver4Legs(InL,OutL,InR,OutR) + 2 0 3 1 | 1 2 0 3 | 5 4 4 5 | +# WType(Direct,Exchange) + 0 0 | 0 0 | 0 0 | +# SpinFactor +-2 0 4 0 + +# Permutation + 5 4 0 1 3 2 +# SymFactor +0.5 +# GType +-2 -2 -2 0 0 0 +# VertexBasis + 0 0 1 1 2 2 + 2 2 0 0 1 1 +# LoopBasis + 1 0 0 1 1 0 + 0 0 0 0 -1 1 + 0 1 0 1 1 0 + 1 0 1 0 1 0 +# Ver4Legs(InL,OutL,InR,OutR) + 2 0 3 1 | 5 2 4 3 | 1 4 0 5 | +# WType(Direct,Exchange) + 0 0 | 0 0 | 0 0 | +# SpinFactor +-2 1 1 -2 + diff --git a/src/frontend/GV_diagrams/groups_vertex4/4Vertex3_1_0.diag b/src/frontend/GV_diagrams/groups_vertex4/4Vertex3_1_0.diag new file mode 100644 index 00000000..c517fdf3 --- /dev/null +++ b/src/frontend/GV_diagrams/groups_vertex4/4Vertex3_1_0.diag @@ -0,0 +1,390 @@ +#Type: SelfEnergy +#DiagNum: 18 +#Order: 3 +#GNum: 6 +#Ver4Num: 3 +#LoopNum: 4 +#ExtLoopIndex: 0 +#DummyLoopIndex: +#TauNum: 3 +#ExtTauIndex: 0 2 +#DummyTauIndex: + +# Permutation + 2 4 0 1 3 5 +# SymFactor +-1.0 +# GType +-2 -2 -2 0 0 0 +# VertexBasis + 0 0 1 1 2 2 + 1 2 0 0 1 2 +# LoopBasis + 1 0 0 1 1 0 + 0 0 1 0 0 0 + 0 1 0 1 1 0 + 1 0 0 0 0 1 +# Ver4Legs(InL,OutL,InR,OutR) + 2 0 3 1 | 0 2 4 3 | 1 4 5 5 | +# WType(Direct,Exchange) + 0 0 | 0 0 | 1 1 | +# SpinFactor +-4 2 2 -1 + +# Permutation + 3 5 4 0 2 1 +# SymFactor +-1.0 +# GType +-2 -2 0 -2 0 0 +# VertexBasis + 0 0 1 1 2 2 + 1 2 2 0 1 0 +# LoopBasis + 1 0 1 0 1 0 + 0 1 1 0 0 0 + 0 0 0 1 1 0 + 1 0 0 0 0 1 +# Ver4Legs(InL,OutL,InR,OutR) + 3 0 5 1 | 4 2 0 3 | 2 4 1 5 | +# WType(Direct,Exchange) + 0 0 | 0 0 | 1 1 | +# SpinFactor +-4 2 2 -1 + +# Permutation + 2 4 0 1 3 5 +# SymFactor +-1.0 +# GType +-2 -2 -2 0 0 0 +# VertexBasis + 0 0 1 1 2 2 + 1 2 0 0 1 2 +# LoopBasis + 1 0 0 1 0 0 + 1 0 1 0 0 0 + 0 1 0 1 1 0 + 0 0 0 0 0 1 +# Ver4Legs(InL,OutL,InR,OutR) + 2 0 3 1 | 0 2 4 3 | 1 4 5 5 | +# WType(Direct,Exchange) + 0 0 | 0 0 | 1 1 | +# SpinFactor + 0 2 0 -1 + +# Permutation + 5 3 0 1 4 2 +# SymFactor +-1.0 +# GType +-2 -2 -2 0 0 0 +# VertexBasis + 0 0 1 1 2 2 + 2 1 0 0 2 1 +# LoopBasis + 1 0 0 1 0 1 + 0 0 1 0 0 0 + 1 0 0 1 1 0 + 0 1 0 0 0 1 +# Ver4Legs(InL,OutL,InR,OutR) + 2 0 3 1 | 5 2 1 3 | 4 4 0 5 | +# WType(Direct,Exchange) + 0 0 | 0 0 | 1 1 | +# SpinFactor + 0 2 0 -1 + +# Permutation + 3 2 0 1 5 4 +# SymFactor +1.0 +# GType +-2 -2 -2 0 0 0 +# VertexBasis + 0 0 1 1 2 2 + 1 1 0 0 2 2 +# LoopBasis + 1 0 0 0 0 1 + 0 1 0 0 -1 1 + 0 0 0 1 1 0 + 1 0 1 0 1 0 +# Ver4Legs(InL,OutL,InR,OutR) + 2 0 3 1 | 1 2 0 3 | 5 4 4 5 | +# WType(Direct,Exchange) + 0 0 | 0 0 | 1 1 | +# SpinFactor +-2 0 4 0 + +# Permutation + 5 4 0 1 3 2 +# SymFactor +0.5 +# GType +-2 -2 -2 0 0 0 +# VertexBasis + 0 0 1 1 2 2 + 2 2 0 0 1 1 +# LoopBasis + 1 0 0 1 1 0 + 0 0 0 0 -1 1 + 0 1 0 1 1 0 + 1 0 1 0 1 0 +# Ver4Legs(InL,OutL,InR,OutR) + 2 0 3 1 | 5 2 4 3 | 1 4 0 5 | +# WType(Direct,Exchange) + 0 0 | 0 0 | 1 1 | +# SpinFactor +-2 1 1 -2 + +# Permutation + 2 4 0 1 3 5 +# SymFactor +-1.0 +# GType +-2 -2 -2 0 0 0 +# VertexBasis + 0 0 1 1 2 2 + 1 2 0 0 1 2 +# LoopBasis + 1 0 0 1 1 0 + 0 0 1 0 0 0 + 0 1 0 1 1 0 + 1 0 0 0 0 1 +# Ver4Legs(InL,OutL,InR,OutR) + 2 0 3 1 | 0 2 4 3 | 1 4 5 5 | +# WType(Direct,Exchange) + 0 0 | 1 1 | 0 0 | +# SpinFactor +-4 2 2 -1 + +# Permutation + 3 5 4 0 2 1 +# SymFactor +-1.0 +# GType +-2 -2 0 -2 0 0 +# VertexBasis + 0 0 1 1 2 2 + 1 2 2 0 1 0 +# LoopBasis + 1 0 1 0 1 0 + 0 1 1 0 0 0 + 0 0 0 1 1 0 + 1 0 0 0 0 1 +# Ver4Legs(InL,OutL,InR,OutR) + 3 0 5 1 | 4 2 0 3 | 2 4 1 5 | +# WType(Direct,Exchange) + 0 0 | 1 1 | 0 0 | +# SpinFactor +-4 2 2 -1 + +# Permutation + 2 4 0 1 3 5 +# SymFactor +-1.0 +# GType +-2 -2 -2 0 0 0 +# VertexBasis + 0 0 1 1 2 2 + 1 2 0 0 1 2 +# LoopBasis + 1 0 0 1 0 0 + 1 0 1 0 0 0 + 0 1 0 1 1 0 + 0 0 0 0 0 1 +# Ver4Legs(InL,OutL,InR,OutR) + 2 0 3 1 | 0 2 4 3 | 1 4 5 5 | +# WType(Direct,Exchange) + 0 0 | 1 1 | 0 0 | +# SpinFactor + 0 2 0 -1 + +# Permutation + 5 3 0 1 4 2 +# SymFactor +-1.0 +# GType +-2 -2 -2 0 0 0 +# VertexBasis + 0 0 1 1 2 2 + 2 1 0 0 2 1 +# LoopBasis + 1 0 0 1 0 1 + 0 0 1 0 0 0 + 1 0 0 1 1 0 + 0 1 0 0 0 1 +# Ver4Legs(InL,OutL,InR,OutR) + 2 0 3 1 | 5 2 1 3 | 4 4 0 5 | +# WType(Direct,Exchange) + 0 0 | 1 1 | 0 0 | +# SpinFactor + 0 2 0 -1 + +# Permutation + 3 2 0 1 5 4 +# SymFactor +1.0 +# GType +-2 -2 -2 0 0 0 +# VertexBasis + 0 0 1 1 2 2 + 1 1 0 0 2 2 +# LoopBasis + 1 0 0 0 0 1 + 0 1 0 0 -1 1 + 0 0 0 1 1 0 + 1 0 1 0 1 0 +# Ver4Legs(InL,OutL,InR,OutR) + 2 0 3 1 | 1 2 0 3 | 5 4 4 5 | +# WType(Direct,Exchange) + 0 0 | 1 1 | 0 0 | +# SpinFactor +-2 0 4 0 + +# Permutation + 5 4 0 1 3 2 +# SymFactor +0.5 +# GType +-2 -2 -2 0 0 0 +# VertexBasis + 0 0 1 1 2 2 + 2 2 0 0 1 1 +# LoopBasis + 1 0 0 1 1 0 + 0 0 0 0 -1 1 + 0 1 0 1 1 0 + 1 0 1 0 1 0 +# Ver4Legs(InL,OutL,InR,OutR) + 2 0 3 1 | 5 2 4 3 | 1 4 0 5 | +# WType(Direct,Exchange) + 0 0 | 1 1 | 0 0 | +# SpinFactor +-2 1 1 -2 + +# Permutation + 2 4 0 1 3 5 +# SymFactor +-1.0 +# GType +-2 -2 -2 0 0 0 +# VertexBasis + 0 0 1 1 2 2 + 1 2 0 0 1 2 +# LoopBasis + 1 0 0 1 1 0 + 0 0 1 0 0 0 + 0 1 0 1 1 0 + 1 0 0 0 0 1 +# Ver4Legs(InL,OutL,InR,OutR) + 2 0 3 1 | 0 2 4 3 | 1 4 5 5 | +# WType(Direct,Exchange) + 1 1 | 0 0 | 0 0 | +# SpinFactor +-4 2 2 -1 + +# Permutation + 3 5 4 0 2 1 +# SymFactor +-1.0 +# GType +-2 -2 0 -2 0 0 +# VertexBasis + 0 0 1 1 2 2 + 1 2 2 0 1 0 +# LoopBasis + 1 0 1 0 1 0 + 0 1 1 0 0 0 + 0 0 0 1 1 0 + 1 0 0 0 0 1 +# Ver4Legs(InL,OutL,InR,OutR) + 3 0 5 1 | 4 2 0 3 | 2 4 1 5 | +# WType(Direct,Exchange) + 1 1 | 0 0 | 0 0 | +# SpinFactor +-4 2 2 -1 + +# Permutation + 2 4 0 1 3 5 +# SymFactor +-1.0 +# GType +-2 -2 -2 0 0 0 +# VertexBasis + 0 0 1 1 2 2 + 1 2 0 0 1 2 +# LoopBasis + 1 0 0 1 0 0 + 1 0 1 0 0 0 + 0 1 0 1 1 0 + 0 0 0 0 0 1 +# Ver4Legs(InL,OutL,InR,OutR) + 2 0 3 1 | 0 2 4 3 | 1 4 5 5 | +# WType(Direct,Exchange) + 1 1 | 0 0 | 0 0 | +# SpinFactor + 0 2 0 -1 + +# Permutation + 5 3 0 1 4 2 +# SymFactor +-1.0 +# GType +-2 -2 -2 0 0 0 +# VertexBasis + 0 0 1 1 2 2 + 2 1 0 0 2 1 +# LoopBasis + 1 0 0 1 0 1 + 0 0 1 0 0 0 + 1 0 0 1 1 0 + 0 1 0 0 0 1 +# Ver4Legs(InL,OutL,InR,OutR) + 2 0 3 1 | 5 2 1 3 | 4 4 0 5 | +# WType(Direct,Exchange) + 1 1 | 0 0 | 0 0 | +# SpinFactor + 0 2 0 -1 + +# Permutation + 3 2 0 1 5 4 +# SymFactor +1.0 +# GType +-2 -2 -2 0 0 0 +# VertexBasis + 0 0 1 1 2 2 + 1 1 0 0 2 2 +# LoopBasis + 1 0 0 0 0 1 + 0 1 0 0 -1 1 + 0 0 0 1 1 0 + 1 0 1 0 1 0 +# Ver4Legs(InL,OutL,InR,OutR) + 2 0 3 1 | 1 2 0 3 | 5 4 4 5 | +# WType(Direct,Exchange) + 1 1 | 0 0 | 0 0 | +# SpinFactor +-2 0 4 0 + +# Permutation + 5 4 0 1 3 2 +# SymFactor +0.5 +# GType +-2 -2 -2 0 0 0 +# VertexBasis + 0 0 1 1 2 2 + 2 2 0 0 1 1 +# LoopBasis + 1 0 0 1 1 0 + 0 0 0 0 -1 1 + 0 1 0 1 1 0 + 1 0 1 0 1 0 +# Ver4Legs(InL,OutL,InR,OutR) + 2 0 3 1 | 5 2 4 3 | 1 4 0 5 | +# WType(Direct,Exchange) + 1 1 | 0 0 | 0 0 | +# SpinFactor +-2 1 1 -2 + diff --git a/src/frontend/GV_diagrams/groups_vertex4/4Vertex4_0_0.diag b/src/frontend/GV_diagrams/groups_vertex4/4Vertex4_0_0.diag new file mode 100644 index 00000000..ce9af15d --- /dev/null +++ b/src/frontend/GV_diagrams/groups_vertex4/4Vertex4_0_0.diag @@ -0,0 +1,870 @@ +#Type: SelfEnergy +#DiagNum: 39 +#Order: 4 +#GNum: 8 +#Ver4Num: 4 +#LoopNum: 5 +#ExtLoopIndex: 0 +#DummyLoopIndex: +#TauNum: 4 +#ExtTauIndex: 0 2 +#DummyTauIndex: + +# Permutation + 2 3 0 1 7 6 5 4 +# SymFactor +-1.0 +# GType +-2 -2 -2 0 0 0 0 0 +# VertexBasis + 0 0 1 1 2 2 3 3 + 1 1 0 0 3 3 2 2 +# LoopBasis + 1 0 0 1 0 1 0 1 + 1 0 1 0 0 0 0 0 + 0 0 0 1 1 0 0 0 + 0 0 0 0 0 1 1 0 + 0 1 0 0 0 0 0 1 +# Ver4Legs(InL,OutL,InR,OutR) + 2 0 3 1 | 0 2 1 3 | 7 4 6 5 | 5 6 4 7 | +# WType(Direct,Exchange) + 0 0 | 0 0 | 0 0 | 0 0 | +# SpinFactor +-8 4 4 -8 4 -2 -2 4 + +# Permutation + 6 5 4 0 2 1 3 7 +# SymFactor +-1.0 +# GType +-2 -2 0 -2 0 0 0 0 +# VertexBasis + 0 0 1 1 2 2 3 3 + 3 2 2 0 1 0 1 3 +# LoopBasis + 1 0 1 0 1 0 1 0 + 0 1 1 0 0 0 0 0 + 0 0 0 1 1 0 0 0 + 1 0 0 0 0 1 1 0 + 0 0 0 0 0 0 0 1 +# Ver4Legs(InL,OutL,InR,OutR) + 3 0 5 1 | 4 2 6 3 | 2 4 1 5 | 0 6 7 7 | +# WType(Direct,Exchange) + 0 0 | 0 0 | 0 0 | 0 0 | +# SpinFactor + 0 4 0 -2 0 -2 0 1 + +# Permutation + 2 4 0 1 3 6 5 7 +# SymFactor +-1.0 +# GType +-2 -2 -2 0 0 0 0 0 +# VertexBasis + 0 0 1 1 2 2 3 3 + 1 2 0 0 1 3 2 3 +# LoopBasis + 1 0 0 1 1 0 0 0 + 1 0 1 0 0 0 0 0 + 0 1 0 1 1 0 0 0 + 0 0 0 0 0 1 1 0 + 0 0 0 0 0 0 0 1 +# Ver4Legs(InL,OutL,InR,OutR) + 2 0 3 1 | 0 2 4 3 | 1 4 6 5 | 5 6 7 7 | +# WType(Direct,Exchange) + 0 0 | 0 0 | 0 0 | 0 0 | +# SpinFactor + 0 4 0 -2 0 -2 0 1 + +# Permutation + 5 6 0 1 4 2 3 7 +# SymFactor +-1.0 +# GType +-2 -2 -2 0 0 0 0 0 +# VertexBasis + 0 0 1 1 2 2 3 3 + 2 3 0 0 2 1 1 3 +# LoopBasis + 1 0 0 1 0 1 0 0 + 0 0 1 0 0 0 0 0 + 1 0 0 1 1 0 0 0 + 0 1 0 0 0 1 1 0 + 0 0 0 0 0 0 0 1 +# Ver4Legs(InL,OutL,InR,OutR) + 2 0 3 1 | 5 2 6 3 | 4 4 0 5 | 1 6 7 7 | +# WType(Direct,Exchange) + 0 0 | 0 0 | 0 0 | 0 0 | +# SpinFactor + 0 0 0 -2 0 0 0 1 + +# Permutation + 6 5 0 1 4 3 2 7 +# SymFactor +-1.0 +# GType +-2 -2 -2 0 0 0 0 0 +# VertexBasis + 0 0 1 1 2 2 3 3 + 3 2 0 0 2 1 1 3 +# LoopBasis + 1 0 0 1 0 1 1 0 + 0 0 1 0 0 0 0 0 + 1 0 0 1 1 0 0 0 + 0 1 0 0 0 1 1 0 + 0 0 0 0 0 0 0 1 +# Ver4Legs(InL,OutL,InR,OutR) + 2 0 3 1 | 6 2 5 3 | 4 4 1 5 | 0 6 7 7 | +# WType(Direct,Exchange) + 0 0 | 0 0 | 0 0 | 0 0 | +# SpinFactor + 0 0 4 -2 0 0 -2 1 + +# Permutation + 4 2 1 0 3 6 5 7 +# SymFactor +-1.0 +# GType +-2 -2 0 -2 0 0 0 0 +# VertexBasis + 0 0 1 1 2 2 3 3 + 2 1 0 0 1 3 2 3 +# LoopBasis + 1 0 1 0 1 0 0 0 + 0 1 1 0 0 0 0 0 + 1 0 0 1 1 0 0 0 + 0 0 0 0 0 1 1 0 + 0 0 0 0 0 0 0 1 +# Ver4Legs(InL,OutL,InR,OutR) + 3 0 2 1 | 1 2 4 3 | 0 4 6 5 | 5 6 7 7 | +# WType(Direct,Exchange) + 0 0 | 0 0 | 0 0 | 0 0 | +# SpinFactor + 0 0 0 -2 0 0 0 1 + +# Permutation + 2 4 0 1 3 6 5 7 +# SymFactor +-1.0 +# GType +-2 -2 -2 0 0 0 0 0 +# VertexBasis + 0 0 1 1 2 2 3 3 + 1 2 0 0 1 3 2 3 +# LoopBasis + 1 0 0 1 1 0 1 0 + 0 0 1 0 0 0 0 0 + 0 1 0 1 1 0 0 0 + 0 0 0 0 0 1 1 0 + 1 0 0 0 0 0 0 1 +# Ver4Legs(InL,OutL,InR,OutR) + 2 0 3 1 | 0 2 4 3 | 1 4 6 5 | 5 6 7 7 | +# WType(Direct,Exchange) + 0 0 | 0 0 | 0 0 | 0 0 | +# SpinFactor +-8 4 4 -2 4 -2 -2 1 + +# Permutation + 2 6 0 1 5 4 3 7 +# SymFactor +-1.0 +# GType +-2 -2 -2 0 0 0 0 0 +# VertexBasis + 0 0 1 1 2 2 3 3 + 1 3 0 0 2 2 1 3 +# LoopBasis + 1 0 0 1 0 1 0 0 + 1 0 1 0 0 0 0 0 + 0 0 0 1 1 0 0 0 + 0 1 0 0 0 1 1 0 + 0 0 0 0 0 0 0 1 +# Ver4Legs(InL,OutL,InR,OutR) + 2 0 3 1 | 0 2 6 3 | 5 4 4 5 | 1 6 7 7 | +# WType(Direct,Exchange) + 0 0 | 0 0 | 0 0 | 0 0 | +# SpinFactor + 0 4 0 0 0 -2 0 0 + +# Permutation + 2 5 0 1 6 3 4 7 +# SymFactor +-1.0 +# GType +-2 -2 -2 0 0 0 0 0 +# VertexBasis + 0 0 1 1 2 2 3 3 + 1 2 0 0 3 1 2 3 +# LoopBasis + 1 0 0 0 0 0 1 0 + 0 0 1 0 0 0 0 0 + 0 0 0 1 1 0 0 0 + 0 1 0 0 0 1 1 0 + 1 0 0 0 0 0 0 1 +# Ver4Legs(InL,OutL,InR,OutR) + 2 0 3 1 | 0 2 5 3 | 6 4 1 5 | 4 6 7 7 | +# WType(Direct,Exchange) + 0 0 | 0 0 | 0 0 | 0 0 | +# SpinFactor +-8 4 4 -2 4 -2 -2 1 + +# Permutation + 3 2 0 1 6 4 5 7 +# SymFactor +1.0 +# GType +-2 -2 -2 0 0 0 0 0 +# VertexBasis + 0 0 1 1 2 2 3 3 + 1 1 0 0 3 2 2 3 +# LoopBasis + 1 0 0 0 1 0 0 0 + 0 -1 0 0 -1 1 0 0 + 1 1 0 1 1 0 0 0 + 0 1 1 0 1 0 1 0 + 0 0 0 0 0 0 0 1 +# Ver4Legs(InL,OutL,InR,OutR) + 2 0 3 1 | 1 2 0 3 | 5 4 6 5 | 4 6 7 7 | +# WType(Direct,Exchange) + 0 0 | 0 0 | 0 0 | 0 0 | +# SpinFactor +-4 2 8 -4 8 -4 -16 8 + +# Permutation + 4 6 1 0 3 2 5 7 +# SymFactor +0.5 +# GType +-2 -2 0 -2 0 0 0 0 +# VertexBasis + 0 0 1 1 2 2 3 3 + 2 3 0 0 1 1 2 3 +# LoopBasis + 1 0 1 0 0 1 0 0 + 0 0 0 0 -1 1 0 0 + 1 0 0 1 1 0 0 0 + 0 1 1 0 1 0 1 0 + 0 0 0 0 0 0 0 1 +# Ver4Legs(InL,OutL,InR,OutR) + 3 0 2 1 | 5 2 4 3 | 0 4 6 5 | 1 6 7 7 | +# WType(Direct,Exchange) + 0 0 | 0 0 | 0 0 | 0 0 | +# SpinFactor + 0 2 0 -1 0 -1 0 2 + +# Permutation + 4 3 0 1 2 7 5 6 +# SymFactor +0.5 +# GType +-2 -2 -2 0 0 0 0 0 +# VertexBasis + 0 0 1 1 2 2 3 3 + 2 1 0 0 1 3 2 3 +# LoopBasis + 1 0 1 0 0 1 0 1 + 0 0 0 0 -1 1 0 0 + 1 0 0 1 1 0 0 0 + 0 0 1 0 1 0 1 0 + 0 1 0 0 0 0 0 1 +# Ver4Legs(InL,OutL,InR,OutR) + 2 0 3 1 | 4 2 1 3 | 0 4 6 5 | 7 6 5 7 | +# WType(Direct,Exchange) + 0 0 | 0 0 | 0 0 | 0 0 | +# SpinFactor +-4 8 2 -4 2 -4 -1 2 + +# Permutation + 5 6 4 0 2 1 3 7 +# SymFactor +1.0 +# GType +-2 -2 0 -2 0 0 0 0 +# VertexBasis + 0 0 1 1 2 2 3 3 + 2 3 2 0 1 0 1 3 +# LoopBasis + 1 0 1 0 0 0 0 0 + 1 0 0 0 -1 1 0 0 + 0 0 0 1 1 0 0 0 + 0 1 1 0 1 0 1 0 + 0 0 0 0 0 0 0 1 +# Ver4Legs(InL,OutL,InR,OutR) + 3 0 5 1 | 4 2 6 3 | 2 4 0 5 | 1 6 7 7 | +# WType(Direct,Exchange) + 0 0 | 0 0 | 0 0 | 0 0 | +# SpinFactor + 0 2 0 -1 0 -1 0 2 + +# Permutation + 3 2 0 1 6 4 5 7 +# SymFactor +1.0 +# GType +-2 -2 -2 0 0 0 0 0 +# VertexBasis + 0 0 1 1 2 2 3 3 + 1 1 0 0 3 2 2 3 +# LoopBasis + 1 0 0 1 0 0 0 0 +-1 0 0 0 -1 1 0 0 + 1 1 0 1 1 0 0 0 + 1 0 1 0 1 0 1 0 + 0 0 0 0 0 0 0 1 +# Ver4Legs(InL,OutL,InR,OutR) + 2 0 3 1 | 1 2 0 3 | 5 4 6 5 | 4 6 7 7 | +# WType(Direct,Exchange) + 0 0 | 0 0 | 0 0 | 0 0 | +# SpinFactor +-4 2 8 -4 8 -4 -16 8 + +# Permutation + 2 7 0 1 5 4 3 6 +# SymFactor +1.0 +# GType +-2 -2 -2 0 0 0 0 0 +# VertexBasis + 0 0 1 1 2 2 3 3 + 1 3 0 0 2 2 1 3 +# LoopBasis + 1 0 0 0 0 1 1 0 + 0 1 0 0 -1 1 0 0 + 0 0 0 1 1 0 0 0 + 0 0 1 0 1 0 1 0 + 1 0 0 0 0 0 0 1 +# Ver4Legs(InL,OutL,InR,OutR) + 2 0 3 1 | 0 2 6 3 | 5 4 4 5 | 7 6 1 7 | +# WType(Direct,Exchange) + 0 0 | 0 0 | 0 0 | 0 0 | +# SpinFactor +-4 8 0 0 2 -4 0 0 + +# Permutation + 2 5 0 1 6 7 4 3 +# SymFactor +0.5 +# GType +-2 -2 -2 0 0 0 0 0 +# VertexBasis + 0 0 1 1 2 2 3 3 + 1 2 0 0 3 3 2 1 +# LoopBasis + 1 0 0 0 0 0 1 0 + 0 0 0 0 -1 1 0 0 + 0 0 0 1 1 0 0 0 + 0 1 1 0 1 0 1 0 + 1 0 0 0 0 0 0 1 +# Ver4Legs(InL,OutL,InR,OutR) + 2 0 3 1 | 0 2 7 3 | 6 4 1 5 | 4 6 5 7 | +# WType(Direct,Exchange) + 0 0 | 0 0 | 0 0 | 0 0 | +# SpinFactor +-4 2 2 -4 2 -1 -1 2 + +# Permutation + 5 4 0 1 6 2 3 7 +# SymFactor +1.0 +# GType +-2 -2 -2 0 0 0 0 0 +# VertexBasis + 0 0 1 1 2 2 3 3 + 2 2 0 0 3 1 1 3 +# LoopBasis + 1 0 1 0 0 1 1 0 +-1 1 0 0 -1 1 0 0 + 1 0 0 1 1 0 0 0 + 1 0 1 0 1 0 1 0 + 0 0 0 0 0 0 0 1 +# Ver4Legs(InL,OutL,InR,OutR) + 2 0 3 1 | 5 2 6 3 | 1 4 0 5 | 4 6 7 7 | +# WType(Direct,Exchange) + 0 0 | 0 0 | 0 0 | 0 0 | +# SpinFactor +-4 2 2 -1 0 0 0 0 + +# Permutation + 2 4 0 1 3 7 5 6 +# SymFactor +0.5 +# GType +-2 -2 -2 0 0 0 0 0 +# VertexBasis + 0 0 1 1 2 2 3 3 + 1 2 0 0 1 3 2 3 +# LoopBasis + 1 0 0 1 1 0 1 0 + 0 0 0 0 -1 1 0 0 + 0 1 0 1 1 0 0 0 + 0 0 1 0 1 0 1 0 + 1 0 0 0 0 0 0 1 +# Ver4Legs(InL,OutL,InR,OutR) + 2 0 3 1 | 0 2 4 3 | 1 4 6 5 | 7 6 5 7 | +# WType(Direct,Exchange) + 0 0 | 0 0 | 0 0 | 0 0 | +# SpinFactor +-4 8 2 -4 2 -4 -1 2 + +# Permutation + 4 5 0 1 2 6 3 7 +# SymFactor +0.5 +# GType +-2 -2 -2 0 0 0 0 0 +# VertexBasis + 0 0 1 1 2 2 3 3 + 2 2 0 0 1 3 1 3 +# LoopBasis + 1 0 1 0 0 1 1 0 + 0 0 0 0 -1 1 0 0 + 1 0 0 1 1 0 0 0 + 0 1 1 0 1 0 1 0 + 0 0 0 0 0 0 0 1 +# Ver4Legs(InL,OutL,InR,OutR) + 2 0 3 1 | 4 2 6 3 | 0 4 1 5 | 5 6 7 7 | +# WType(Direct,Exchange) + 0 0 | 0 0 | 0 0 | 0 0 | +# SpinFactor +-4 2 2 -1 0 0 0 0 + +# Permutation + 5 2 0 1 6 3 4 7 +# SymFactor +1.0 +# GType +-2 -2 -2 0 0 0 0 0 +# VertexBasis + 0 0 1 1 2 2 3 3 + 2 1 0 0 3 1 2 3 +# LoopBasis + 1 0 1 0 0 0 1 0 + 1 0 0 0 -1 1 0 0 + 0 0 0 1 1 0 0 0 + 0 1 1 0 1 0 1 0 + 0 0 0 0 0 0 0 1 +# Ver4Legs(InL,OutL,InR,OutR) + 2 0 3 1 | 1 2 5 3 | 6 4 0 5 | 4 6 7 7 | +# WType(Direct,Exchange) + 0 0 | 0 0 | 0 0 | 0 0 | +# SpinFactor +-4 2 2 -1 8 -4 -4 2 + +# Permutation + 7 3 0 1 6 4 5 2 +# SymFactor +1.0 +# GType +-2 -2 -2 0 0 0 0 0 +# VertexBasis + 0 0 1 1 2 2 3 3 + 3 1 0 0 3 2 2 1 +# LoopBasis + 1 0 1 0 0 0 0 1 +-1 0 0 0 -1 1 0 0 + 1 0 0 1 1 0 0 0 + 1 0 1 0 1 0 1 0 + 0 1 0 0 0 0 0 1 +# Ver4Legs(InL,OutL,InR,OutR) + 2 0 3 1 | 7 2 1 3 | 5 4 6 5 | 4 6 0 7 | +# WType(Direct,Exchange) + 0 0 | 0 0 | 0 0 | 0 0 | +# SpinFactor +-4 2 8 -4 2 -1 -4 2 + +# Permutation + 5 3 0 1 7 6 2 4 +# SymFactor +0.5 +# GType +-2 -2 -2 0 0 0 0 0 +# VertexBasis + 0 0 1 1 2 2 3 3 + 2 1 0 0 3 3 1 2 +# LoopBasis + 1 0 1 0 1 0 0 1 + 0 0 0 0 -1 1 0 0 + 0 0 0 1 1 0 0 0 + 1 0 1 0 1 0 1 0 + 0 1 0 0 0 0 0 1 +# Ver4Legs(InL,OutL,InR,OutR) + 2 0 3 1 | 6 2 1 3 | 7 4 0 5 | 5 6 4 7 | +# WType(Direct,Exchange) + 0 0 | 0 0 | 0 0 | 0 0 | +# SpinFactor + 0 0 0 0 0 0 0 0 + +# Permutation + 6 4 0 1 3 2 5 7 +# SymFactor +1.0 +# GType +-2 -2 -2 0 0 0 0 0 +# VertexBasis + 0 0 1 1 2 2 3 3 + 3 2 0 0 1 1 2 3 +# LoopBasis + 1 0 0 0 1 0 1 0 + 0 -1 0 0 -1 1 0 0 + 0 1 0 1 1 0 0 0 + 1 1 1 0 1 0 1 0 + 0 0 0 0 0 0 0 1 +# Ver4Legs(InL,OutL,InR,OutR) + 2 0 3 1 | 5 2 4 3 | 1 4 6 5 | 0 6 7 7 | +# WType(Direct,Exchange) + 0 0 | 0 0 | 0 0 | 0 0 | +# SpinFactor + 0 2 0 -1 0 -1 0 2 + +# Permutation + 3 6 4 0 2 7 5 1 +# SymFactor +0.5 +# GType +-2 -2 0 -2 0 0 0 0 +# VertexBasis + 0 0 1 1 2 2 3 3 + 1 3 2 0 1 3 2 0 +# LoopBasis + 1 0 1 0 1 0 1 0 + 0 0 0 0 -1 1 0 0 + 0 0 0 1 1 0 0 0 + 0 1 1 0 1 0 1 0 + 1 0 0 0 0 0 0 1 +# Ver4Legs(InL,OutL,InR,OutR) + 3 0 7 1 | 4 2 0 3 | 2 4 6 5 | 1 6 5 7 | +# WType(Direct,Exchange) + 0 0 | 0 0 | 0 0 | 0 0 | +# SpinFactor +-4 8 2 -4 2 -4 -1 2 + +# Permutation + 6 4 0 1 3 2 5 7 +# SymFactor +0.5 +# GType +-2 -2 -2 0 0 0 0 0 +# VertexBasis + 0 0 1 1 2 2 3 3 + 3 2 0 0 1 1 2 3 +# LoopBasis + 1 0 0 1 1 0 1 0 + 0 0 0 0 -1 1 0 0 + 0 1 0 1 1 0 0 0 + 1 0 1 0 1 0 1 0 + 0 0 0 0 0 0 0 1 +# Ver4Legs(InL,OutL,InR,OutR) + 2 0 3 1 | 5 2 4 3 | 1 4 6 5 | 0 6 7 7 | +# WType(Direct,Exchange) + 0 0 | 0 0 | 0 0 | 0 0 | +# SpinFactor + 0 2 0 -1 0 -1 0 2 + +# Permutation + 4 3 0 1 7 5 2 6 +# SymFactor +1.0 +# GType +-2 -2 -2 0 0 0 0 0 +# VertexBasis + 0 0 1 1 2 2 3 3 + 2 1 0 0 3 2 1 3 +# LoopBasis + 1 0 0 1 1 0 0 1 + 0 0 1 0 0 0 0 0 + 1 0 0 0 0 1 0 0 + 0 0 0 1 1 0 1 0 + 0 1 0 0 0 0 0 1 +# Ver4Legs(InL,OutL,InR,OutR) + 2 0 3 1 | 6 2 1 3 | 0 4 5 5 | 7 6 4 7 | +# WType(Direct,Exchange) + 0 0 | 0 0 | 0 0 | 0 0 | +# SpinFactor +-4 8 2 -4 2 -4 -1 2 + +# Permutation + 2 4 0 1 6 3 5 7 +# SymFactor +1.0 +# GType +-2 -2 -2 0 0 0 0 0 +# VertexBasis + 0 0 1 1 2 2 3 3 + 1 2 0 0 3 1 2 3 +# LoopBasis + 1 0 0 1 1 0 1 0 + 1 0 1 0 0 0 0 0 + 0 0 0 0 0 1 0 0 + 0 1 0 1 1 0 1 0 + 0 0 0 0 0 0 0 1 +# Ver4Legs(InL,OutL,InR,OutR) + 2 0 3 1 | 0 2 5 3 | 1 4 6 5 | 4 6 7 7 | +# WType(Direct,Exchange) + 0 0 | 0 0 | 0 0 | 0 0 | +# SpinFactor + 0 2 0 0 0 -1 0 0 + +# Permutation + 4 5 6 0 2 1 3 7 +# SymFactor +1.0 +# GType +-2 -2 0 -2 0 0 0 0 +# VertexBasis + 0 0 1 1 2 2 3 3 + 2 2 3 0 1 0 1 3 +# LoopBasis + 1 0 1 0 1 0 0 0 + 0 1 1 0 0 0 0 0 + 1 0 0 0 0 1 0 0 + 0 0 0 1 1 0 1 0 + 0 0 0 0 0 0 0 1 +# Ver4Legs(InL,OutL,InR,OutR) + 3 0 5 1 | 4 2 6 3 | 0 4 1 5 | 2 6 7 7 | +# WType(Direct,Exchange) + 0 0 | 0 0 | 0 0 | 0 0 | +# SpinFactor +-4 2 2 -1 8 -4 -4 2 + +# Permutation + 3 4 0 1 6 5 2 7 +# SymFactor +1.0 +# GType +-2 -2 -2 0 0 0 0 0 +# VertexBasis + 0 0 1 1 2 2 3 3 + 1 2 0 0 3 2 1 3 +# LoopBasis + 1 0 0 0 1 0 0 0 + 0 0 1 0 0 0 0 0 + 1 0 0 0 0 1 0 0 + 0 1 0 1 1 0 1 0 + 0 0 0 0 0 0 0 1 +# Ver4Legs(InL,OutL,InR,OutR) + 2 0 3 1 | 6 2 0 3 | 1 4 5 5 | 4 6 7 7 | +# WType(Direct,Exchange) + 0 0 | 0 0 | 0 0 | 0 0 | +# SpinFactor +-4 2 2 -1 8 -4 -4 2 + +# Permutation + 5 2 0 1 4 6 3 7 +# SymFactor +1.0 +# GType +-2 -2 -2 0 0 0 0 0 +# VertexBasis + 0 0 1 1 2 2 3 3 + 2 1 0 0 2 3 1 3 +# LoopBasis + 1 0 0 1 0 1 1 0 + 0 0 1 0 0 0 0 0 + 0 1 0 0 0 1 0 0 + 1 0 0 1 1 0 1 0 + 0 0 0 0 0 0 0 1 +# Ver4Legs(InL,OutL,InR,OutR) + 2 0 3 1 | 1 2 6 3 | 4 4 0 5 | 5 6 7 7 | +# WType(Direct,Exchange) + 0 0 | 0 0 | 0 0 | 0 0 | +# SpinFactor + 0 0 2 -1 0 0 -4 2 + +# Permutation + 2 5 0 1 6 4 3 7 +# SymFactor +1.0 +# GType +-2 -2 -2 0 0 0 0 0 +# VertexBasis + 0 0 1 1 2 2 3 3 + 1 2 0 0 3 2 1 3 +# LoopBasis + 1 0 0 1 0 0 1 0 + 1 0 1 0 0 0 0 0 + 0 0 0 0 0 1 0 0 + 0 1 0 1 1 0 1 0 + 0 0 0 0 0 0 0 1 +# Ver4Legs(InL,OutL,InR,OutR) + 2 0 3 1 | 0 2 6 3 | 5 4 1 5 | 4 6 7 7 | +# WType(Direct,Exchange) + 0 0 | 0 0 | 0 0 | 0 0 | +# SpinFactor +-4 2 0 0 2 -1 0 0 + +# Permutation + 7 2 0 1 6 4 5 3 +# SymFactor +-0.5 +# GType +-2 -2 -2 0 0 0 0 0 +# VertexBasis + 0 0 1 1 2 2 3 3 + 3 1 0 0 3 2 2 1 +# LoopBasis + 1 0 1 0 0 0 0 1 +-1 0 0 0 -1 1 0 0 + 1 1 1 0 1 0 0 1 + 1 0 1 0 1 0 1 0 + 0 0 -1 1 0 0 0 0 +# Ver4Legs(InL,OutL,InR,OutR) + 2 0 3 1 | 1 2 7 3 | 5 4 6 5 | 4 6 0 7 | +# WType(Direct,Exchange) + 0 0 | 0 0 | 0 0 | 0 0 | +# SpinFactor +-2 1 4 -2 4 -2 -8 4 + +# Permutation + 5 4 0 1 7 6 2 3 +# SymFactor +-0.25 +# GType +-2 -2 -2 0 0 0 0 0 +# VertexBasis + 0 0 1 1 2 2 3 3 + 2 2 0 0 3 3 1 1 +# LoopBasis + 1 0 1 0 1 0 0 1 + 0 0 0 0 -1 1 0 0 + 0 1 1 0 1 0 0 1 + 1 0 1 0 1 0 1 0 + 0 0 -1 1 0 0 0 0 +# Ver4Legs(InL,OutL,InR,OutR) + 2 0 3 1 | 6 2 7 3 | 1 4 0 5 | 5 6 4 7 | +# WType(Direct,Exchange) + 0 0 | 0 0 | 0 0 | 0 0 | +# SpinFactor +-2 1 1 -2 1 -2 -2 1 + +# Permutation + 3 4 0 1 2 7 5 6 +# SymFactor +-0.5 +# GType +-2 -2 -2 0 0 0 0 0 +# VertexBasis + 0 0 1 1 2 2 3 3 + 1 2 0 0 1 3 2 3 +# LoopBasis + 1 0 0 0 1 0 0 0 + 0 -1 0 0 -1 1 0 0 + 1 1 1 0 1 0 0 1 + 0 1 1 0 1 0 1 0 + 0 0 -1 1 0 0 0 0 +# Ver4Legs(InL,OutL,InR,OutR) + 2 0 3 1 | 4 2 0 3 | 1 4 6 5 | 7 6 5 7 | +# WType(Direct,Exchange) + 0 0 | 0 0 | 0 0 | 0 0 | +# SpinFactor +-2 4 1 -2 4 -8 -2 4 + +# Permutation + 3 7 0 1 6 4 5 2 +# SymFactor +-1.0 +# GType +-2 -2 -2 0 0 0 0 0 +# VertexBasis + 0 0 1 1 2 2 3 3 + 1 3 0 0 3 2 2 1 +# LoopBasis + 1 0 0 0 1 0 0 0 + 0 0 0 0 0 1 1 -1 + 1 0 0 1 0 0 -1 1 + 0 0 1 0 0 0 0 1 + 0 1 0 0 1 0 1 0 +# Ver4Legs(InL,OutL,InR,OutR) + 2 0 3 1 | 7 2 0 3 | 5 4 6 5 | 4 6 1 7 | +# WType(Direct,Exchange) + 0 0 | 0 0 | 0 0 | 0 0 | +# SpinFactor +-2 1 4 -2 4 -2 -8 4 + +# Permutation + 5 7 0 1 3 6 2 4 +# SymFactor +-1.0 +# GType +-2 -2 -2 0 0 0 0 0 +# VertexBasis + 0 0 1 1 2 2 3 3 + 2 3 0 0 1 3 1 2 +# LoopBasis + 1 0 0 0 1 0 0 1 + 1 -1 0 0 0 1 1 -1 +-1 1 0 1 0 0 -1 1 + 0 1 1 0 0 0 0 1 + 1 0 0 0 1 0 1 0 +# Ver4Legs(InL,OutL,InR,OutR) + 2 0 3 1 | 6 2 4 3 | 7 4 0 5 | 5 6 1 7 | +# WType(Direct,Exchange) + 0 0 | 0 0 | 0 0 | 0 0 | +# SpinFactor +-2 1 1 -2 1 -2 -2 4 + +# Permutation + 4 5 0 1 7 6 3 2 +# SymFactor +-1.0 +# GType +-2 -2 -2 0 0 0 0 0 +# VertexBasis + 0 0 1 1 2 2 3 3 + 2 2 0 0 3 3 1 1 +# LoopBasis + 1 0 1 0 0 1 1 0 + 0 1 0 0 0 1 1 -1 + 1 -1 0 1 0 0 -1 1 + 0 0 1 0 0 0 0 1 + 0 1 0 0 1 0 1 0 +# Ver4Legs(InL,OutL,InR,OutR) + 2 0 3 1 | 7 2 6 3 | 0 4 1 5 | 5 6 4 7 | +# WType(Direct,Exchange) + 0 0 | 0 0 | 0 0 | 0 0 | +# SpinFactor +-2 1 1 -2 1 -2 -2 1 + +# Permutation + 2 6 4 0 3 7 5 1 +# SymFactor +-1.0 +# GType +-2 -2 0 -2 0 0 0 0 +# VertexBasis + 0 0 1 1 2 2 3 3 + 1 3 2 0 1 3 2 0 +# LoopBasis + 1 0 1 0 0 0 0 0 +-1 0 0 0 0 1 1 -1 + 1 0 0 1 0 0 -1 1 + 1 1 1 0 0 0 0 1 + 0 0 0 0 1 0 1 0 +# Ver4Legs(InL,OutL,InR,OutR) + 3 0 7 1 | 0 2 4 3 | 2 4 6 5 | 1 6 5 7 | +# WType(Direct,Exchange) + 0 0 | 0 0 | 0 0 | 0 0 | +# SpinFactor +-2 4 1 -2 4 -8 -2 4 + +# Permutation + 4 2 0 1 3 7 5 6 +# SymFactor +-1.0 +# GType +-2 -2 -2 0 0 0 0 0 +# VertexBasis + 0 0 1 1 2 2 3 3 + 2 1 0 0 1 3 2 3 +# LoopBasis + 1 0 1 0 0 1 0 1 + 0 -1 0 0 0 1 1 -1 + 1 1 0 1 0 0 -1 1 + 0 1 1 0 0 0 0 1 + 0 0 0 0 1 0 1 0 +# Ver4Legs(InL,OutL,InR,OutR) + 2 0 3 1 | 1 2 4 3 | 0 4 6 5 | 7 6 5 7 | +# WType(Direct,Exchange) + 0 0 | 0 0 | 0 0 | 0 0 | +# SpinFactor +-2 4 1 -2 4 -8 -2 4 + diff --git a/src/frontend/GV_diagrams/main_vertex4.py b/src/frontend/GV_diagrams/main_vertex4.py new file mode 100644 index 00000000..cf91542a --- /dev/null +++ b/src/frontend/GV_diagrams/main_vertex4.py @@ -0,0 +1,89 @@ +from free_energy import * +from polar import * +from vertex4 import * +import copy +import sys + + +def Generate(Order, VerOrder, SigmaOrder, SPIN): + LnZOrder = Order-1 + DiagFile = "./Diagram/HugenDiag{0}.diag".format(LnZOrder) + LnZ = free_energy(LnZOrder) + # Load pre-generated lnZ diagrams + # build labeled Feynman diagram to unlabled Hugenholtz diagram mapping + print "\nLoad Order {0} LnZ diagrams ...".format(LnZOrder) + LnZ.LoadDiagrams(DiagFile) + + print red("\nThe optimimal LnZ diagrams:") + OptLnZHugenDiagList = LnZ.OptimizeLoopBasis() + + Polar = polar(Order) + + UniqueUnLabelDiagList = [] + + for d in OptLnZHugenDiagList: + print "\n=============================================================" + print blue("Processing LnZ diagram: {0} with SymFactor: {1}".format( + d.GetPermu(), d.SymFactor)) + + print "Attach two external vertexes ..." + OptPolarHugenDiagDict = Polar.AttachExtVer(d) + + # print "Check Tadpole..." + # for p in OptPolarHugenDiagDict.keys(): + # if diag.HasTadpole(p, Polar.GetReference()): + # del OptPolarHugenDiagDict[p] + + # print "Check Fock..." + # for p in OptPolarHugenDiagDict.keys(): + # if diag.HasFock(p, Polar.GetReference()): + # del OptPolarHugenDiagDict[p] + + print "Group polarization diagrams from the same LnZ diagram..." + UnLabelDiagDeformList = Polar.Group( + OptPolarHugenDiagDict, TimeRotation=True) + # each element contains a deforamtion of hugenholz polarization + # diagrams in the same LnZ group + + print red("Representative polarization Hugenholtz diagram:") + for d in UnLabelDiagDeformList: + diagram = copy.deepcopy(OptPolarHugenDiagDict[d[0]]) + diagram.SymFactor = diagram.SymFactor*len(d) + UniqueUnLabelDiagList.append(diagram) + print red("{0} with SymFactor {1}".format( + diagram.GetPermu(), diagram.SymFactor)) + + print yellow("Total Unique Polarization diagram: {0}".format( + len(UniqueUnLabelDiagList))) + + print "Save diagrams ..." + + Vertex4 = vertex4(Order) + + # fname = "./output/{0}{1}_{2}_{3}.diag".format( + fname = "./groups_vertex4/{0}{1}_{2}_{3}.diag".format( + "4Vertex", Order, VerOrder, SigmaOrder) + # with open(fname, "w") as f: + with open(fname, "w") as f: + str_polar = Vertex4.ToString(UniqueUnLabelDiagList, + VerOrder, SigmaOrder, SPIN) + if not(str_polar is None): + f.write(str_polar) + # f.write(SelfEnergy.ToString(UniqueUnLabelDiagList, + # VerOrder, SigmaOrder, SPIN)) + + +if __name__ == "__main__": + # print "Input Diagram Order: " + # Order = int(sys.argv[1]) + Order = 4 + SPIN = 2 + for o in range(2, Order+1): + for v in range(0, Order): + # for g in range(0, (Order-1)/2+1): + for g in range(0, Order): + # if o+v+2*g > Order: + if o+v+g > Order: + continue + Generate(o, v, g, SPIN) + # Generate(5, 0, 0, SPIN) diff --git a/src/frontend/GV_diagrams/vertex4.py b/src/frontend/GV_diagrams/vertex4.py new file mode 100644 index 00000000..87c89641 --- /dev/null +++ b/src/frontend/GV_diagrams/vertex4.py @@ -0,0 +1,404 @@ +import diagram as diag +import numpy as np +from logger import * + + +class vertex4(): + def __init__(self, Order): + self.Order = Order + self.GNum = 2*self.Order + self.Ver4Num = self.Order + self.VerNum = 2*self.Ver4Num + + self.ExtLegNum = 2 + # self.ExtLegNum = 0 + self.ExtLoopNum = 1 + + self.LoopNum = self.Order+self.ExtLoopNum + + def GetInteractionPairs(self, WithMeasuring=False): + if WithMeasuring: + return tuple([(2*i, 2*i+1) for i in range(0, self.Ver4Num+1)]) + else: + return tuple([(2*i, 2*i+1) for i in range(1, self.Ver4Num+1)]) + + def GetReference(self): + return tuple(range(self.GNum)) + + def BuildADiagram(self): + d = diag.diagram(self.Order) + d.Type = "SelfEnergy" + d.GNum = self.GNum + d.Ver4Num = self.Ver4Num + d.VerNum = self.VerNum + d.LoopNum = self.LoopNum + # d.ExtLeg = [0, 1] + d.ExtLeg = [0, 2] + d.ExtLegNum = 2 + d.ExtLoop = [0] + d.ExtLoopNum = 1 + return d + + def ToString(self, PolarHugenList, VerOrder, SigmaOrder, SPIN): + if len(PolarHugenList) == 0: + return + + InterCounterTerms = self.__InterCounterTerms(VerOrder) + SigmaCounterTerms = self.__SigmaCounterTerms(SigmaOrder) + print InterCounterTerms + print SigmaCounterTerms + + IrreDiagList = [] + for vertype in InterCounterTerms: + for gtype in SigmaCounterTerms: + for Diag in PolarHugenList: + Permutation = Diag.GetPermu() + Mom = Diag.LoopBasis + + FeynList = self.HugenToFeyn(Diag.GetPermu()) + FactorList = [] + + for FeynPermu in FeynList: + if (FeynPermu[0] == 1 or FeynPermu[1] == 0 or self.__IsHartree(FeynPermu, Diag.LoopBasis, vertype, gtype) or + self.__IsReducible(FeynPermu, Diag.LoopBasis, vertype, gtype) or self.__IsTwoParticleReducible(FeynPermu, Diag.LoopBasis)): + FactorList.append(0) + else: + FactorList.append(1) + + if np.all(np.array(FactorList) == 0): + print "Reducible diagram: ", Permutation + continue + + IrreDiagList.append( + [Diag, FeynList, FactorList, vertype, gtype]) + + print yellow( + "Irreducible SelfEnergy Diag Num: {0}".format(len(IrreDiagList))) + + Body = "" + DiagNum = 0 + for Diag, FeynList, FactorList, VerType, GType in IrreDiagList: + Permutation = Diag.GetPermu() + SymFactor = Diag.SymFactor + Mom = Diag.LoopBasis + # DiagNum += 1 + + inv_OldPermu = np.argsort(Permutation) + Permutation = list(Permutation) + + print "Original Polar Permu: {0}".format(Permutation) + swap_ver = () + jp_0 = Permutation.index(0) + jp_1 = Permutation.index(1) + # if jp_0 < 2 or jp_1 < 2: + Assert(jp_0 > 1 and jp_1>1, "false permutation with {0} and {1}".format(jp_0, jp_1)) + Permutation = diag.SwapTwoVertex(Permutation, jp_0, 2) + Permutation = diag.SwapTwoVertex(Permutation, jp_1, 3) + # swap_ver = (jp_0, neighbor) + # print "newPermu: {0}".format(Permutation) + + # print Diag.LoopBasis + # loopBasis = np.copy(Diag.LoopBasis) + # gtype_temp = np.copy(GType) + # if len(swap_ver) > 0: + # loopBasis[:, swap_ver[0]], loopBasis[:, 2] = Diag.LoopBasis[:,2], Diag.LoopBasis[:, swap_ver[0]] + # GType[swap_ver[0]], GType[2] = gtype_temp[2], gtype_temp[swap_ver[0]] + # if swap_ver[1] != 2: + # loopBasis[:, swap_ver[1]], loopBasis[:, 3] = Diag.LoopBasis[:,3], Diag.LoopBasis[:, swap_ver[1]] + # GType[swap_ver[1]], GType[3] = gtype_temp[3], gtype_temp[swap_ver[1]] + # if jp_0 >= 2: + # locs_extloop = np.where(abs(loopBasis[:, 0]) == 1 & (loopBasis[:, 0] == loopBasis[:,2]))[0] + # loc_extloop=locs_extloop[0] + # # loc_extloop = np.where(abs(loopBasis[:, 0]) == 1 & (loopBasis[:, 0] == loopBasis[:,2]))[0][0] + # else: + # # loc_extloop = np.where(abs(loopBasis[:, 0]) == 1 & (loopBasis[:, 0] == loopBasis[:,1]))[0][0] + # locs_extloop = np.where(abs(loopBasis[:, 0]) == 1 & (loopBasis[:, 0] == loopBasis[:,1]))[0] + # loc_extloop=locs_extloop[0] + # if len(locs_extloop)>1: + # print yellow("{0}".format(loopBasis)) + # for loc in locs_extloop[1:]: + # if loopBasis[loc, 0] == loopBasis[loc_extloop, 0]: + # loopBasis[loc, :] = loopBasis[loc, :] - loopBasis[loc_extloop, :] + # else: + # loopBasis[loc, :] = loopBasis[loc, :] + loopBasis[loc_extloop, :] + # print blue("{0}".format(loopBasis)) + + print "Save {0}".format(Permutation) + + Body += "# Permutation\n" + for i in Permutation: + Body += "{0:2d} ".format(i) + Body += "\n" + + Body += "# SymFactor\n{0}\n".format(SymFactor) + + Body += "# GType\n" + for i in range(self.GNum): + if Permutation[i] == 0 or i == 0 or i == 1: + Body += "{0:2d} ".format(-2) + else: + Body += "{0:2d} ".format(GType[i]) + + Body += "\n" + + Body += "# VertexBasis\n" + for i in range(self.GNum): + Body += "{0:2d} ".format(self.__VerBasis(i, Permutation)) + Body += "\n" + for i in range(self.GNum): + Body += "{0:2d} ".format(self.__VerBasis(Permutation[i], Permutation)) + Body += "\n" + + Body += "# LoopBasis\n" + + # basis_temp = np.copy(loopBasis) + # if loc_extloop > 0: + # if loopBasis[loc_extloop, 0] == 1: + # basis_temp[0, :] = loopBasis[loc_extloop, :] + # else: + # basis_temp[0, :] = -loopBasis[loc_extloop, :] + # basis_temp[loc_extloop:-1, :] = loopBasis[loc_extloop+1:, :] + # basis_temp[-1, :] = loopBasis[0, :] + # print yellow("{0}".format(loc_extloop)) + for i in range(self.LoopNum): + for j in range(self.GNum): + # Body += "{0:2d} ".format(basis_temp[i, j]) + Body += "{0:2d} ".format(Mom[i, j]) + Body += "\n" + # print basis_temp + + Body += "# Ver4Legs(InL,OutL,InR,OutR)\n" + for i in range(0, self.Ver4Num): + # skip the external vertexes 0 and 1 + end1, end2 = 2*i, 2*i+1 + start1 = Permutation.index(end1) + start2 = Permutation.index(end2) + Body += "{0:2d} {1:2d} {2:2d} {3:2d} |".format( + start1, end1, start2, end2) + Body += "\n" + + # Get interaction Momemtnum list + InterMom = self.__GetInteractionMom(Permutation, Mom) + + Body += "# WType(Direct,Exchange)\n" + for i in range(0, self.Ver4Num): + Body += "{0:2d} {1:2d} |".format(VerType[i], VerType[i]) + Body += "\n" + + Body += "# SpinFactor\n" + + FeynList = self.HugenToFeyn(Permutation) + FactorList = [] + + for idx, FeynPermu in enumerate(FeynList): + # if self.__IsHartree(FeynPermu, basis_temp, vertype, gtype): + if self.__IsHartree(FeynPermu, Mom, vertype, gtype): + prefactor = 0 + else: + prefactor = 1 + Path = diag.FindAllLoops(FeynPermu) + nloop = len(Path) - 1 + Sign = (-1)**nloop*(-1)**(self.Order-1) / \ + (Diag.SymFactor/abs(Diag.SymFactor)) + + # make sure the sign of the Spin factor of the first diagram is positive + # spinfactor = SPIN**(nloop) * int(Sign)*FactorList[idx] + spinfactor = SPIN**(nloop) * int(Sign)* prefactor + Body += "{0:2d} ".format(spinfactor) + # Body += "{0:2d} ".format(-(-1)**nloop*Factor) + + Body += "\n" + Body += "\n" + DiagNum += 1 + + Title = "#Type: {0}\n".format("SelfEnergy") + # Title = "#Type: {0}\n".format("Green2") + Title += "#DiagNum: {0}\n".format(DiagNum) + Title += "#Order: {0}\n".format(self.Order) + Title += "#GNum: {0}\n".format(self.GNum) + Title += "#Ver4Num: {0}\n".format(self.Ver4Num) + # if IsSelfEnergy: + # Title += "#LoopNum: {0}\n".format(self.LoopNum-1) + # else: + Title += "#LoopNum: {0}\n".format(self.LoopNum) + Title += "#ExtLoopIndex: {0}\n".format(0) + Title += "#DummyLoopIndex: \n" + # if IsSelfEnergy: + # Title += "#TauNum: {0}\n".format(self.Ver4Num) + # else: + Title += "#TauNum: {0}\n".format(self.Ver4Num) + Title += "#ExtTauIndex: {0} {1}\n".format(0, 2) + Title += "#DummyTauIndex: \n" + Title += "\n" + + if Body == "": + return None + else: + print Body + return Title+Body + + def HugenToFeyn(self, HugenPermu): + """construct a list of feyn diagram permutation from a hugen diagram permutation""" + FeynList = [] + FeynList.append(HugenPermu) + Permutation = HugenPermu + for j in range(1, self.Order): + end1, end2 = 2*j, 2*j+1 + start1 = Permutation.index(end1) + start2 = Permutation.index(end2) + + TempFeynList = [] + for permu in FeynList: + TempPermu = list(permu) + TempFeynList.append(tuple(TempPermu)) + TempPermu[start1], TempPermu[start2] = TempPermu[start2], TempPermu[start1] + TempFeynList.append(tuple(TempPermu)) + + FeynList = TempFeynList + return FeynList + + def __VerBasis(self, index, Permutation): + return int(index/2) + + def __IsHartree(self, Permutation, LoopBasis, vertype, gtype): + ExterLoop = [0, ]*self.LoopNum + ExterLoop[0] = 1 + for i in range(0, self.Ver4Num): + end1, end2 = 2*i, 2*i+1 + start1 = Permutation.index(end1) + # start2 = Permutation.index(end2) + VerLoopBasis = LoopBasis[:, start1]-LoopBasis[:, end1] + # print Permutation, 2*i, VerLoopBasis + + # ####### Check Polarization diagram ################## + # if(np.array_equal(VerLoopBasis, ExterLoop) or + # np.array_equal(-VerLoopBasis, ExterLoop)): + # return True + + # remove any hartree insertion + if(np.all(VerLoopBasis == 0)): + # print "Contain high-order Hartree: ", Permutation + return True + + ###### Check High order Hatree ###################### + # kG, kW = diag.AssignMomentums( + # Permutation, self.GetReference(), self.GetInteractionPairs(True)) + # last = Permutation.index(1) + # first = 0 + # print '###############################################' + # if abs(kG[first]- kG[last])<1e-6: + # print 'Reduc Perm:', Permutation, 'kG:', kG, 'index:', last + # return True + # print 'irReduc Perm:', Permutation, 'kG:', kG, 'index:', last + + # for i in range(len(kW)): + # if abs(kW[i]) < 1e-12: + # # print "k=0 on W {0}: {1}".format(p, kW[i]) + # print "Contain high-order Hartree: ", Permutation + # return True + return False + + def __IsReducible(self, Permutation, LoopBasis, vertype, gtype): + extK = LoopBasis[:, Permutation.index(0)] + for i in range(0, self.GNum): + if Permutation[i] != 0 and (np.allclose(extK, LoopBasis[:, i]) or np.allclose(-extK, LoopBasis[:, i])): + return True + if Permutation[i] == 0 and gtype[i] > 0: + return True + for i in range(0, self.Ver4Num): + end1, end2 = 2*i, 2*i+1 + start1 = Permutation.index(end1) + # start2 = Permutation.index(end2) + VerLoopBasis = LoopBasis[:, start1]-LoopBasis[:, end1] + + # ####### Check Polarization diagram ################## + if np.array_equal(VerLoopBasis, extK) or np.array_equal(-VerLoopBasis, extK): + return True + + def __IsTwoParticleReducible(self, Permutation, LoopBasis): + extK = LoopBasis[:, Permutation.index(0)] + for i in range(2, self.GNum): + for j in range(2, self.GNum): + if Permutation[i] == 0 or Permutation[j] == 0: + continue + if np.allclose(extK, LoopBasis[:, i]+ LoopBasis[:,j]): + return True + + + def __GetInteractionMom(self, Permutation, Mom): + InteractionMom = [] + for j in range(1, self.Order): + end1, end2 = 2*j, 2*j+1 + start1 = Permutation.index(end1) + start2 = Permutation.index(end2) + InteractionMom.append(Mom[:, start1]-Mom[:, end1]) + InteractionMom.append(Mom[:, start1]-Mom[:, end2]) + return InteractionMom + + # def get_Unique_Permutation(self, permutationList, TimeRotation=True): + # Order = self.Order + # PermutationDict = {} + # for p in permutationList: + # PermutationDict[tuple(p)] = None + # for per in permutationList: + # if not PermutationDict.has_key(tuple(per)): + # continue + # Deformation = [per] + + # if TimeRotation: + # for idx in range(1, Order): + # for i in range(len(Deformation)): + # for j in range(1, idx): + # Deformation.append(diag.SwapTwoInteraction( + # Deformation[i], idx*2, idx*2+1, j*2, j*2+1)) + + # for idx in range(1, Order): + # for i in range(len(Deformation)): + # Deformation.append(diag.SwapTwoVertex( + # Deformation[i], idx*2, idx*2+1)) + + # # for idx in range(1,Order): + # # for i in range(len(Deformation)): + # # Deformation.append(swap_LR_Hugen(Deformation[i], idx*2, idx*2+1)) + + # Deformation = set(Deformation) + # for p in Deformation: + # if tuple(p) == tuple(per): + # continue + # if p in permutationList: + # del PermutationDict[p] + + # print "remaining length of permutation dictionary:", len( + # PermutationDict) + # return PermutationDict.keys() + + def __InterCounterTerms(self, CounterTermOrder): + Collection = [[]] + Sum = [0] + for _ in range(1, self.Ver4Num+1): # number of elements + newCollection = [] + newSum = [] + for ic, c in enumerate(Collection): + for i in range(CounterTermOrder+1): # element value + if Sum[ic]+i <= CounterTermOrder: + newCollection.append(c + [i]) + newSum.append(Sum[ic] + i) + Collection = newCollection + Sum = newSum + + return [c for ic, c in enumerate(Collection) if Sum[ic] == CounterTermOrder] + + def __SigmaCounterTerms(self, CounterTermOrder): + Collection = [[]] + Sum = [0] + for _ in range(1, self.GNum+1): # number of elements + newCollection = [] + newSum = [] + for ic, c in enumerate(Collection): + for i in range(CounterTermOrder+1): # element value + if Sum[ic]+i <= CounterTermOrder: + newCollection.append(c + [i]) + newSum.append(Sum[ic] + i) + Collection = newCollection + Sum = newSum + return [c for ic, c in enumerate(Collection) if Sum[ic] == CounterTermOrder] diff --git a/src/frontend/diagtree.jl b/src/frontend/diagtree.jl deleted file mode 100644 index 2796f4f4..00000000 --- a/src/frontend/diagtree.jl +++ /dev/null @@ -1,89 +0,0 @@ -""" - function Graph!(d::DiagTree.Diagram{W}; map=Dict{Int,DiagTree.DiagramId}()) where {W} - -Converts a DiagTree `d` into a Graph, storing the diagram information (which is a DiagramId object) in a Graph.id to DiagramId dictionary ``map". - -# Arguments: -- `d`: DiagTree.Diagram object. -- `map`: map between the Graph.id and DiagramId. It will be updated with the new nodes and leaves contained in the DiagTree.Diagram `d`. - - -# Example: -```julia-repl -julia> para = DiagParaF64(type = Ver4Diag, innerLoopNum=2); - -julia> ver4=Parquet.build(para) -2×5 DataFrame - Row │ diagram extT hash response type - │ Diagram… Tuple… Int64 Response Analytic… -─────┼───────────────────────────────────────────────────────────────────────────── - 1 │ 5978:↑↑Dyn#[0, 0, 0, 0],t(1, 1, … (1, 1, 1, 1) 5978 UpUp Dynamic - 2 │ 5979:↑↓Dyn#[0, 0, 0, 0],t(1, 1, … (1, 1, 1, 1) 5979 UpDown Dynamic - -julia> d = ver4.diagram[1] # take the first diagram -5978:↑↑Dyn#[0, 0, 0, 0],t(1, 1, 1, 1)=0.0=⨁ (5026, 5071, 5137, 5146, 5175, 5220, 5312, 5321, 5350, 5396, 5463, 5473, 5503, 5549, 5642, 5652, 5682, 5793, 5831, 5968) - -julia> root = FrontEnds.Graph!(d) -``` - -""" -# function Graph!(d::DiagTree.Diagram{W}; map=Dict{Int,DiagTree.DiagramId}()) where {W} -function Graph!(d::DiagTree.Diagram{W}) where {W} - - function op(o) - if o isa DiagTree.Sum - return ComputationalGraphs.Sum() - elseif o isa DiagTree.Prod - return ComputationalGraphs.Prod() - else - error("Unknown operator: $o") - end - end - - subgraphs = ComputationalGraphs.Graph{W,W}[] - for g in d.subdiagram - # res, map = Graph!(g; map=map) - res = Graph!(g) - push!(subgraphs, res) - end - - if isempty(subgraphs) - root = ComputationalGraphs.Graph(subgraphs; subgraph_factors=ones(W, length(subgraphs)), factor=d.factor, name=String(d.name), - operator=op(d.operator), orders=d.id.order, ftype=W, wtype=W, weight=d.weight, properties=d.id) - else - tree = ComputationalGraphs.Graph(subgraphs; subgraph_factors=ones(W, length(subgraphs)), - operator=op(d.operator), orders=d.id.order, ftype=W, wtype=W, weight=d.weight) - root = ComputationalGraphs.Graph([tree,]; subgraph_factors=[d.factor,], orders=tree.orders, - ftype=W, wtype=W, weight=d.weight * d.factor) - end - - return root - # @assert haskey(map, root.id) == false "DiagramId already exists in map: $(root.id)" - # @assert haskey(map, tree.id) == false "DiagramId already exists in map: $(tree.id)" - # map[root.id] = d.id - # map[tree.id] = d.id - - # return root, map -end - -""" - function extract_var_dependence(map::Dict{Int,DiagTree.DiagramId}, ::Type{ID}, numvars::Int) - - Given a map between graph id and DiagramId, extract the variable dependence of all graphs. - -# Arguments: -- `map::Dict{Int,DiagTree.DiagramId}`: A dictionary mapping graph ids to DiagramIds. DiagramId stores the diagram information of the corresponding graph. -- `ID`: The particular type of ID that has the given variable dependence. -- `numvars`: The number of variables which the diagram depends on. -""" -function extract_var_dependence(map::Dict{Int,DiagTree.DiagramId}, ::Type{ID}; numvars::Int=1) where {ID<:PropagatorId} - var_dependence = Dict{Int,Vector{Bool}}() - for (id, diagID) in map - if diagID isa ID - var_dependence[id] = [true for _ in 1:numvars] - else - var_dependence[id] = [false for _ in 1:numvars] - end - end - return var_dependence -end \ No newline at end of file diff --git a/src/frontend/frontends.jl b/src/frontend/frontends.jl index c567323f..96cb22e3 100644 --- a/src/frontend/frontends.jl +++ b/src/frontend/frontends.jl @@ -8,18 +8,14 @@ import ..ComputationalGraphs: FeynmanGraph import ..ComputationalGraphs: Graph import ..ComputationalGraphs: _dtype -using ..DiagTree - include("pool.jl") export LoopPool include("LabelProduct.jl") export LabelProduct -include("parquet.jl") -using .Parquet +# include("parquet/parquet.jl") +# using .Parquet # export Parquet -include("diagtree.jl") - end \ No newline at end of file diff --git a/src/frontend/parquet.jl b/src/frontend/parquet.jl deleted file mode 100644 index 5517df5a..00000000 --- a/src/frontend/parquet.jl +++ /dev/null @@ -1,112 +0,0 @@ -module Parquet -# import ..ComputationalGraphs -# import .._dtype -# import ..ComputationalGraphs -# import ComputationalGraphs._dtype: _dtype -import ..IR -import ..IR: _dtype -import ..Op - -𝑎⁺(isFermi, i) = isFermi ? Op.𝑓⁺(i) : Op.𝑏⁺(i) -𝑎⁻(isFermi, i) = isFermi ? Op.𝑓⁺(i) : Op.𝑏⁺(i) - -function _bubble(; left_label=[1, 2, 3, 4], right_label=[5, 6, 7, 8], external_indices=[1, 2, 7, 8], topology=Vector{Vector{Int}}([]), isFermi=true, factor=_dtype.factor(1)) - # default topology type should be given, otherwise feynman_diagram report error - if isFermi - a⁺, a⁻ = Op.𝑓⁺, Op.𝑓⁻ - ea⁺, ea⁻ = Op.𝑓⁺ₑ, Op.𝑓⁻ₑ - else - a⁺, a⁻ = Op.𝑏⁺, Op.𝑏⁻ - ea⁺, ea⁻ = Op.𝑏⁺ₑ, Op.𝑏⁻ₑ - end - l1, l2, l3, l4 = left_label - r1, r2, r3, r4 = right_label - # e1, e2, e3, e4 = external - - lver = a⁺(l1) * a⁺(l2) * a⁻(l3) * a⁻(l4) - rver = a⁺(r1) * a⁺(r2) * a⁻(r3) * a⁻(r4) - - g = IR.feynman_diagram([ea⁺(1), ea⁺(2), ea⁻(3), ea⁻(4), lver, rver], topology, external_indices=external_indices, factor=factor) - IR.standardize_order!(g) - return g -end - -""" - function particle_hole_bubble(left_label=[5, 6, 7, 8], right_label=[9, 10, 11, 12], isFermi=true) - -Create a particle-hole bubble diagram. - -3 4 -^ ^ -| | -7---8--->----9---12 -| | | | -| | | | -5---6---<----11--10 -| | -^ ^ -1 2 -""" -function particle_hole_bubble(left_label=[5, 6, 7, 8], right_label=[9, 10, 11, 12], isFermi=true) - l1, l2, l3, l4 = left_label - r1, r2, r3, r4 = right_label - external_indices = [l1, r2, l3, r4] # (5, 10| 7, 12) - topology = [[1, 5], [2, 10], [7, 3], [12, 4], [8, 9], [11, 6]] - factor = _dtype.factor(1) - return _bubble(left_label=left_label, right_label=right_label, external_indices=external_indices, topology=topology, isFermi=isFermi, factor=factor) -end - -""" - function particle_hole_exchange_bubble(left_label=[5, 6, 7, 8], right_label=[9, 10, 11, 12], isFermi=true) - -Create a particle-hole-exchange bubble diagram. It is the same as the particle-hole bubble diagram except that the external ghost operators are exchanged (3, 4) <-> (4, 3) - -4 3 -^ ^ -| | -7---8--->----9---12 -| | | | -| | | | -5---6---<----11--10 -| | -^ ^ -1 2 -""" -function particle_hole_exchange_bubble(left_label=[5, 6, 7, 8], right_label=[9, 10, 11, 12], isFermi=true) - l1, l2, l3, l4 = left_label - r1, r2, r3, r4 = right_label - external_indices = [l1, r2, l3, r4] # (5, 10| 7, 12) - topology = [[1, 5], [2, 10], [12, 3], [7, 4], [8, 9], [11, 6]] - factor = _dtype.factor(1) - return _bubble(left_label=left_label, right_label=right_label, external_indices=external_indices, topology=topology, isFermi=isFermi, factor=factor) -end - -""" - function particle_particle_bubble(left_label=[5, 6, 7, 8], right_label=[9, 10, 11, 12], isFermi=true) - -Create a particle-particle bubble diagram. One of the internal propagator (8->9) is the same as the particle-hole and particle-hole-exchange bubble diagram. The external ghost operators are exchanged (3, 4) <-> (4, 3) compared to the particle-hole bubble diagram. - -4 3 -^ ^ -12---11 -| | -10----9 -| | -^ ^ -| | -7-----8 -| | -5-----6 -^ ^ -1 2 -""" -function particle_particle_bubble(left_label=[5, 6, 7, 8], right_label=[9, 10, 11, 12], isFermi=true) - l1, l2, l3, l4 = left_label - r1, r2, r3, r4 = right_label - external_indices = [l1, l2, r3, r4] # (5, 10| 7, 12) - topology = [[1, 5], [2, 6], [11, 3], [12, 4], [7, 10], [8, 9]] - factor = _dtype.factor(1) / 2 - return _bubble(left_label=left_label, right_label=right_label, external_indices=external_indices, topology=topology, isFermi=isFermi, factor=factor) -end - -end \ No newline at end of file diff --git a/src/parquet_builder/benchmark/benchmark.jl b/src/frontend/parquet/benchmark/benchmark.jl similarity index 100% rename from src/parquet_builder/benchmark/benchmark.jl rename to src/frontend/parquet/benchmark/benchmark.jl diff --git a/src/parquet_builder/benchmark/diagram_count.jl b/src/frontend/parquet/benchmark/diagram_count.jl similarity index 100% rename from src/parquet_builder/benchmark/diagram_count.jl rename to src/frontend/parquet/benchmark/diagram_count.jl diff --git a/src/parquet_builder/benchmark/vertex4.jl b/src/frontend/parquet/benchmark/vertex4.jl similarity index 100% rename from src/parquet_builder/benchmark/vertex4.jl rename to src/frontend/parquet/benchmark/vertex4.jl diff --git a/src/parquet_builder/benchmark/vertex4_eval.jl b/src/frontend/parquet/benchmark/vertex4_eval.jl similarity index 100% rename from src/parquet_builder/benchmark/vertex4_eval.jl rename to src/frontend/parquet/benchmark/vertex4_eval.jl diff --git a/src/parquet_builder/benchmark/vertex4_io.jl b/src/frontend/parquet/benchmark/vertex4_io.jl similarity index 100% rename from src/parquet_builder/benchmark/vertex4_io.jl rename to src/frontend/parquet/benchmark/vertex4_io.jl diff --git a/src/parquet_builder/common.jl b/src/frontend/parquet/common.jl similarity index 51% rename from src/parquet_builder/common.jl rename to src/frontend/parquet/common.jl index 51100f47..b194c0ce 100644 --- a/src/parquet_builder/common.jl +++ b/src/frontend/parquet/common.jl @@ -1,87 +1,23 @@ -import ..Filter -import ..Wirreducible #remove all polarization subdiagrams -import ..Girreducible #remove all self-energy inseration -import ..NoHartree -import ..NoFock -import ..NoBubble # true to remove all bubble subdiagram -import ..Proper #ver4, ver3, and polarization diagrams may require to be irreducible along the transfer momentum/frequency -import ..DirectOnly - -import ..DiagramType -import ..GreenDiag -import ..SigmaDiag -import ..PolarDiag -import ..Ver3Diag -import ..Ver4Diag - -import ..Composite -import ..ChargeCharge -import ..SpinSpin -import ..UpUp -import ..UpDown -import ..Response - -import ..Instant -import ..Dynamic -import ..D_Instant -import ..D_Dynamic -import ..AnalyticProperty - -import ..symbol -import ..short - -import ..Interaction -import ..DiagPara -import ..innerTauNum -import ..interactionTauNum -import ..derivepara - -import ..Diagram - -import ..DiagramId -import ..Ver4Id -import ..Ver3Id -import ..GreenId -import ..SigmaId -import ..PolarId -import ..BareInteractionId -import ..BareGreenId - -import ..TwoBodyChannel -import ..Alli -import ..PHr -import ..PHEr -import ..PPr -import ..AnyChan - -import ..Permutation -import ..Di -import ..Ex -import ..DiEx - -import ..uidreset -import ..toDataFrame -import ..mergeby - -function build(para::DiagPara{W}, extK=nothing, subdiagram=false) where {W} + +function build(para::DiagPara, extK=nothing, subdiagram=false) if para.type == Ver4Diag if isnothing(extK) - extK = [DiagTree.getK(para.totalLoopNum, 1), DiagTree.getK(para.totalLoopNum, 2), DiagTree.getK(para.totalLoopNum, 3)] + extK = [getK(para.totalLoopNum, 1), getK(para.totalLoopNum, 2), getK(para.totalLoopNum, 3)] end return vertex4(para, extK, [PHr, PHEr, PPr, Alli], subdiagram) elseif para.type == SigmaDiag if isnothing(extK) - extK = DiagTree.getK(para.totalLoopNum, 1) + extK = getK(para.totalLoopNum, 1) end return sigma(para, extK, subdiagram) elseif para.type == PolarDiag if isnothing(extK) - extK = DiagTree.getK(para.totalLoopNum, 1) + extK = getK(para.totalLoopNum, 1) end return polarization(para, extK, subdiagram) elseif para.type == Ver3Diag if isnothing(extK) - extK = [DiagTree.getK(para.totalLoopNum, 1), DiagTree.getK(para.totalLoopNum, 2)] + extK = [getK(para.totalLoopNum, 1), getK(para.totalLoopNum, 2)] end return vertex3(para, extK, subdiagram) else @@ -89,34 +25,6 @@ function build(para::DiagPara{W}, extK=nothing, subdiagram=false) where {W} end end -""" - struct ParquetBlocks - - The channels of the left and right sub-vertex4 of a bubble diagram in the parquet equation - -#Members -- `phi` : channels of left sub-vertex for the particle-hole and particle-hole-exchange bubbles -- `ppi` : channels of left sub-vertex for the particle-particle bubble -- `Γ4` : channels of right sub-vertex of all channels -""" -struct ParquetBlocks - phi::Vector{TwoBodyChannel} - ppi::Vector{TwoBodyChannel} - Γ4::Vector{TwoBodyChannel} - function ParquetBlocks(; phi=[Alli, PHEr, PPr], ppi=[Alli, PHr, PHEr], Γ4=union(phi, ppi)) - return new(phi, ppi, Γ4) - end -end - -function Base.isequal(a::ParquetBlocks, b::ParquetBlocks) - if issetequal(a.phi, b.phi) && issetequal(a.ppi, b.ppi) && issetequal(a.Γ4, b.Γ4) - return true - else - return false - end -end -Base.:(==)(a::ParquetBlocks, b::ParquetBlocks) = Base.isequal(a, b) - function orderedPartition(_total, n, lowerbound=1) @assert lowerbound >= 0 total = _total - n * (lowerbound - 1) @@ -136,6 +44,101 @@ function orderedPartition(_total, n, lowerbound=1) return orderedPartition end +""" + function innerTauNum(type::DiagramType, innerLoopNum, interactionTauNum) + + internal imaginary-time degrees of freedom for a given diagram type and internal loop number. + For the vertex functions (self-energy, polarization, vertex3, and vertex4), innerTauNum is equivalent to tauNum. + For the Green function, tauNum = innerTauNum + external tauNum +""" +function innerTauNum(type::DiagramType, innerLoopNum, interactionTauNum) + if type == Ver4Diag + return (innerLoopNum + 1) * interactionTauNum + elseif type == SigmaDiag + return innerLoopNum * interactionTauNum + elseif type == GreenDiag + return innerLoopNum * interactionTauNum + elseif type == VacuumDiag + return (innerLoopNum - 1) * interactionTauNum + elseif type == PolarDiag + return 1 + innerTauNum(Ver3Diag, innerLoopNum - 1, interactionTauNum) + elseif type == Ver3Diag + return 1 + innerTauNum(Ver4Diag, innerLoopNum - 1, interactionTauNum) + else + error("not implemented!") + end +end + +function interactionTauNum(hasTau::Bool, interactionSet) + if hasTau == false + return 0 + end + for interaction in interactionSet + if Dynamic in interaction.type || D_Dynamic in interaction.type + return 2 + end + end + return 1 +end + +function firstTauIdx(type, offset::Int=0) + if type == GreenDiag + return 3 + offset + elseif type == Ver3Diag + return 1 + offset + elseif type == PolarDiag + return 1 + offset + else + return 1 + offset + end +end + +function firstLoopIdx(type, offset::Int=0) + if type == Ver4Diag #three extK + return 4 + offset + elseif type == SigmaDiag #one extK + return 2 + offset + elseif type == GreenDiag #one extK + return 2 + offset + elseif type == PolarDiag #one extK + return 2 + offset + elseif type == Ver3Diag #two extK + return 3 + offset + elseif type == VacuumDiag #no extK + return 1 + offset + else + error("not implemented!") + end +end + +function totalTauNum(type, innerLoopNum, interactionTauNum, offset::Int=0) + return firstTauIdx(type, offset) + innerTauNum(type, innerLoopNum, interactionTauNum) - 1 +end + +function totalLoopNum(type, innerLoopNum, offset::Int=0) + return firstLoopIdx(type, offset) + innerLoopNum - 1 +end + +function totalTauNum(para, type::Symbol=:none) + return para.totalTauNum + # if type == :Ver4 + # return (para.internalLoopNum + 1) * para.interactionTauNum + # else + # error("not implemented!") + # end +end + +function totalLoopNum(para, type::Symbol=:none) + return para.totalLoopNum +end + +function getK(loopNum::Int, loopIdx::Int) + k = zeros(loopNum) + k[loopIdx] = 1.0 + return k +end + + function findFirstLoopIdx(partition, firstidx::Int) ## example: firstidx = 1 # partition = [1, 1, 2, 1], then the loop partition = [1][2][34][5], thus firstTauIdx = [1, 2, 3, 5] diff --git a/src/frontend/parquet/diagram_id.jl b/src/frontend/parquet/diagram_id.jl new file mode 100644 index 00000000..ffa57973 --- /dev/null +++ b/src/frontend/parquet/diagram_id.jl @@ -0,0 +1,167 @@ +""" + abstract type DiagramId end + + The abstract type of all diagrams/subdiagrams/bare propagators +""" +abstract type DiagramId end + +""" + abstract type PropagatorId <: DiagramId end + + The abstract type of all bare propagators +""" +abstract type PropagatorId <: DiagramId end + +# Base.Dict(x::DiagramId) = Dict{Symbol,Any}([fn => getfield(x, fn) for fn ∈ fieldnames(typeof(x))]) +# Base.show(io::IO, d::DiagramId) = error("Base.show not implemented!") +# Base.isequal(a::DiagramId, b::DiagramId) = error("Base.isequal not implemented!") +Base.:(==)(a::DiagramId, b::DiagramId) = Base.isequal(a, b) + +struct BareGreenId <: PropagatorId + para::DiagPara + type::AnalyticProperty #Instant, Dynamic, D_Instant, D_Dynamic + extK::Vector{Float64} + extT::Tuple{Int,Int} #all possible extT from different interactionType + function BareGreenId(para::DiagPara, type::AnalyticProperty=Dynamic; k, t) + return new(para, type, k, Tuple(t)) + end +end +Base.show(io::IO, v::BareGreenId) = print(io, "$(short(v.type)), k$(v.extK), t$(v.extT)") + +struct BareInteractionId <: PropagatorId # bare W-type interaction, with only one extK + para::DiagPara + response::Response #UpUp, UpDown, ... + type::AnalyticProperty #Instant, Dynamic, D_Instant, D_Dynamic + extK::Vector{Float64} + extT::Tuple{Int,Int} #all possible extT from different interactionType + function BareInteractionId(para::DiagPara, response::Response, type::AnalyticProperty=Instant; k, t=(0, 0)) + return new(para, response, type, k, Tuple(t)) + end +end +Base.show(io::IO, v::BareInteractionId) = print(io, "$(short(v.response))$(short(v.type)), k$(v.extK), t$(v.extT)") + +struct GenericId <: DiagramId + para::DiagPara + extra::Any + GenericId(para::DiagPara, extra=Nothing) = new(para, extra) +end +Base.show(io::IO, v::GenericId) = print(io, v.extra == Nothing ? "" : "$(v.extra)") + +struct GreenId <: DiagramId + para::DiagPara + type::AnalyticProperty #Instant, Dynamic, D_Instant, D_Dynamic + extK::Vector{Float64} + extT::Tuple{Int,Int} #all possible extT from different interactionType + function GreenId(para::DiagPara, type::AnalyticProperty=Dynamic; k, t) + return new(para, type, k, Tuple(t)) + end +end +Base.show(io::IO, v::GreenId) = print(io, "$(short(v.type)), k$(v.extK), t$(v.extT)") + +struct SigmaId <: DiagramId + para::DiagPara + type::AnalyticProperty #Instant, Dynamic, D_Instant, D_Dynamic + extK::Vector{Float64} + extT::Tuple{Int,Int} #all possible extT from different interactionType + function SigmaId(para::DiagPara, type::AnalyticProperty; k, t=(0, 0)) + return new(para, type, k, t) + end +end +Base.show(io::IO, v::SigmaId) = print(io, "$(short(v.type))#$(v.order), t$(v.extT)") + +struct PolarId <: DiagramId + para::DiagPara + response::Response #UpUp, UpDown, ... + extK::Vector{Float64} + extT::Tuple{Int,Int} #all possible extT from different interactionType + order::Vector{Int} + function PolarId(para::DiagPara, response::Response; k, t=(0, 0)) + return new(para, response, k, t) + end +end +Base.show(io::IO, v::PolarId) = print(io, "$(short(v.response)), k$(v.extK), t$(v.extT)") + +struct Ver3Id <: DiagramId + para::DiagPara + response::Response #UpUp, UpDown, ... + extK::Vector{Vector{Float64}} + extT::Tuple{Int,Int,Int} #all possible extT from different interactionType + function Ver3Id(para::DiagPara, response::Response; k, t=(0, 0, 0)) + return new(para, response, k, Tuple(t)) + end +end +Base.show(io::IO, v::Ver3Id) = print(io, "$(short(v.response)),t$(v.extT)") + +struct Ver4Id <: DiagramId + para::DiagPara + response::Response #UpUp, UpDown, ... + type::AnalyticProperty #Instant, Dynamic, D_Instant, D_Dynamic + channel::TwoBodyChannel # particle-hole, particle-hole exchange, particle-particle, irreducible + extK::Vector{Vector{Float64}} + extT::Tuple{Int,Int,Int,Int} #all possible extT from different interactionType + function Ver4Id(para::DiagPara, response::Response, type::AnalyticProperty=Dynamic; k, t=(0, 0, 0, 0), chan::TwoBodyChannel=AnyChan) + return new(para, response, type, chan, k, Tuple(t)) + end +end +Base.show(io::IO, v::Ver4Id) = print(io, (v.channel == AnyChan ? "" : "$(v.channel) ") * "$(short(v.response))$(short(v.type)),t$(v.extT)") + +function vstr(r, c) + N = length(r) + # cstr(x) = x ? "⁺" : "⁻" + s = "" + for i = 1:N-1 + s *= "$(r[i])$c" + end + s *= "$(r[end])$c" + return s +end + +function vcstr(r, creation) + N = length(r) + # cstr(x) = x ? "⁺" : "⁻" + s = "" + for i = 1:N-1 + if creation[i] + s *= "$(r[i])⁺" + else + s *= "$(r[i])⁻" + end + end + if creation[end] + s *= "$(r[end])⁺" + else + s *= "$(r[end])⁻" + end + return s +end + +function Base.isequal(a::DiagramId, b::DiagramId) + if typeof(a) != typeof(b) + return false + end + for field in fieldnames(typeof(a)) + # field in [:para, :permutation] && continue #both parameter and permutation needs to be compared + # if field == :extK + # if !(getproperty(a, :extK) ≈ getproperty(b, :extK)) && !(getproperty(a, :extK) ≈ -getproperty(b, :extK)) + # return false + # end + # continue + # end + if getproperty(a, field) != getproperty(b, field) + return false + end + end + return true +end + +function index(type) + if type == BareGreenId + return 1 + elseif type == BareInteractionId + return 2 + else + error("Not Implemented!") + end +end + + diff --git a/src/parquet_builder/ep_coupling.jl b/src/frontend/parquet/ep_coupling.jl similarity index 82% rename from src/parquet_builder/ep_coupling.jl rename to src/frontend/parquet/ep_coupling.jl index 35d0563b..3221e7a1 100644 --- a/src/parquet_builder/ep_coupling.jl +++ b/src/frontend/parquet/ep_coupling.jl @@ -1,11 +1,11 @@ """ - function ep_coupling(para::DiagPara{W}; - extK=[DiagTree.getK(para.totalLoopNum, 1), DiagTree.getK(para.totalLoopNum, 2), DiagTree.getK(para.totalLoopNum, 3)], + function ep_coupling(para::DiagPara; + extK=[getK(para.totalLoopNum, 1), getK(para.totalLoopNum, 2), getK(para.totalLoopNum, 3)], channels::AbstractVector=[PHr, PHEr, PPr, Alli], subdiagram=false, name=:none, resetuid=false, blocks::ParquetBlocks=ParquetBlocks() - ) where {W} + ) Generate electron-phonon 4-vertex diagrams using Parquet Algorithm. The right incoming Tau will be set to the last Tau for all diagrams | | @@ -27,13 +27,13 @@ Generate electron-phonon 4-vertex diagrams using Parquet Algorithm. The right in # Output - A DataFrame with fields :response, :type, :extT, :diagram, :hash """ -function ep_coupling(para::DiagPara{W}; - extK=[DiagTree.getK(para.totalLoopNum, 1), DiagTree.getK(para.totalLoopNum, 2), DiagTree.getK(para.totalLoopNum, 3)], +function ep_coupling(para::DiagPara; + extK=[getK(para.totalLoopNum, 1), getK(para.totalLoopNum, 2), getK(para.totalLoopNum, 3)], channels::AbstractVector=[PHr, PHEr, PPr, Alli], subdiagram=false, name=:none, resetuid=false, blocks::ParquetBlocks=ParquetBlocks() -) where {W} +) @warn("ep vertex4 breaks SU(2) spin symmetry!") if NoBubble in para.filter @@ -47,7 +47,7 @@ function ep_coupling(para::DiagPara{W}; legK = [k[1:para.totalLoopNum] for k in extK[1:3]] push!(legK, legK[1] + legK[3] - legK[2]) - resetuid && uidreset() + resetuid && ComputationalGraphs.uidreset() @assert para.totalTauNum >= maxVer4TauIdx(para) "Increase totalTauNum!\n$para" @assert para.totalLoopNum >= maxVer4LoopIdx(para) "Increase totalLoopNum\n$para" @@ -55,7 +55,7 @@ function ep_coupling(para::DiagPara{W}; loopNum = para.innerLoopNum # @assert loopNum >= 0 - ver4df = DataFrame(response=Response[], type=AnalyticProperty[], extT=Tuple{Int,Int,Int,Int}[], diagram=Diagram{W}[]) + ver4df = DataFrame(response=Response[], type=AnalyticProperty[], extT=Tuple{Int,Int,Int,Int}[], diagram=Graph{Ftype,Wtype}[]) partition = orderedPartition(loopNum - 1, 4, 0) @@ -72,10 +72,10 @@ function ep_coupling(para::DiagPara{W}; # println(bub) diags = ver4df.diagram - @assert all(x -> x.id isa Ver4Id, diags) "not all id are Ver4Id! $diags" - @assert all(x -> x.id.extK ≈ legK, diags) "not all extK are the same! $diags" + @assert all(x -> x.properties isa Ver4Id, diags) "not all id are Ver4Id! $diags" + @assert all(x -> x.properties.extK ≈ legK, diags) "not all extK are the same! $diags" - ver4df = merge_vertex4(para, ver4df, name, legK, W) + ver4df = merge_vertex4(para, ver4df, name, legK) @assert all(x -> x[1] == para.firstTauIdx, ver4df.extT) "not all extT[1] are equal to the first Tau index $(para.firstTauIdx)! $ver4df" # @assert all(x -> x[3] == para.totalTauNum, ver4df.extT) "not all extT[3] are equal to the first Tau index $(para.totalTauNum)! $ver4df" # @assert all(x -> x[4] == para.totalTauNum, ver4df.extT) "not all extT[4] are equal to the first Tau index $(para.totalTauNum)! $ver4df" @@ -83,8 +83,8 @@ function ep_coupling(para::DiagPara{W}; return ver4df end -function ep_bubble!(ver4df::DataFrame, para::DiagPara{W}, legK, chans::Vector{TwoBodyChannel}, partition::Vector{Int}, name::Symbol, blocks::ParquetBlocks, - extrafactor=1.0) where {W} +function ep_bubble!(ver4df::DataFrame, para::DiagPara, legK, chans::Vector{TwoBodyChannel}, partition::Vector{Int}, name::Symbol, blocks::ParquetBlocks, + extrafactor=1.0) @assert partition[3] == 0 @@ -115,19 +115,19 @@ function ep_bubble!(ver4df::DataFrame, para::DiagPara{W}, legK, chans::Vector{Tw Lver = vertex4(lPara, LLegK, chans, true; name=:Γf, blocks=blocks) isempty(Lver) && return - Rver = DataFrame(response=Response[], type=AnalyticProperty[], extT=Tuple{Int,Int,Int,Int}[], diagram=Diagram{W}[]) + Rver = DataFrame(response=Response[], type=AnalyticProperty[], extT=Tuple{Int,Int,Int,Int}[], diagram=Graph{Ftype,Wtype}[]) bareVer4(Rver, rPara, RLegK, [Di,], false) # the external tau is right aligned - Rver = merge_vertex4(rPara, Rver, :bare, RLegK, W) + Rver = merge_vertex4(rPara, Rver, :bare, RLegK) @assert isempty(Rver) == false for ldiag in Lver.diagram for rdiag in Rver.diagram - LvT, RvT = ldiag.id.extT, rdiag.id.extT - extT, G0T, GxT = tauBasis(PHr, ldiag.id.extT, rdiag.id.extT) + LvT, RvT = ldiag.properties.extT, rdiag.properties.extT + extT, G0T, GxT = tauBasis(PHr, ldiag.properties.extT, rdiag.properties.extT) g0 = green(g0Para, K, G0T, true, name=:G0, blocks=blocks) gx = green(gxPara, Kx, GxT, true, name=:Gx, blocks=blocks) - @assert g0 isa Diagram && gx isa Diagram + @assert g0 isa Graph && gx isa Graph # append!(diag, bubble2diag(para, chan, ldiag, rdiag, legK, g0, gx, extrafactor)) bubble2diag!(ver4df, para, PHr, ldiag, rdiag, legK, g0, gx, extrafactor) end diff --git a/src/parquet_builder/filter.jl b/src/frontend/parquet/filter.jl similarity index 100% rename from src/parquet_builder/filter.jl rename to src/frontend/parquet/filter.jl diff --git a/src/parquet_builder/green.jl b/src/frontend/parquet/green.jl similarity index 84% rename from src/parquet_builder/green.jl rename to src/frontend/parquet/green.jl index 9b8202d0..0bab8c62 100644 --- a/src/parquet_builder/green.jl +++ b/src/frontend/parquet/green.jl @@ -1,5 +1,5 @@ """ - green(para::DiagPara, extK = DiagTree.getK(para.totalLoopNum, 1), extT = para.hasTau ? (1, 2) : (0, 0), subdiagram = false; + green(para::DiagPara, extK = getK(para.totalLoopNum, 1), extT = para.hasTau ? (1, 2) : (0, 0), subdiagram = false; name = :G, resetuid = false, blocks::ParquetBlocks=ParquetBlocks()) Build composite Green's function. @@ -16,10 +16,10 @@ By definition, para.firstTauIdx is the first Tau index of the left most self-ene # Output -- A Diagram object or nothing if the Green's function is illegal. +- A Graph object or nothing if the Green's function is illegal. """ -function green(para::DiagPara{W}, extK=DiagTree.getK(para.totalLoopNum, 1), extT=para.hasTau ? (1, 2) : (0, 0), subdiagram=false; - name=:G, resetuid=false, blocks::ParquetBlocks=ParquetBlocks()) where {W} +function green(para::DiagPara, extK=getK(para.totalLoopNum, 1), extT=para.hasTau ? (1, 2) : (0, 0), subdiagram=false; + name=:G, resetuid=false, blocks::ParquetBlocks=ParquetBlocks()) @assert isValidG(para) "$para doesn't gives a valid Green's function" @assert para.type == GreenDiag @@ -30,7 +30,7 @@ function green(para::DiagPara{W}, extK=DiagTree.getK(para.totalLoopNum, 1), extT @assert length(extK) >= para.totalLoopNum "expect dim of extK>=$(para.totalLoopNum), got $(length(extK))" extK = extK[1:para.totalLoopNum] - resetuid && uidreset() + resetuid && ComputationalGraphs.uidreset() tin, tout = extT[1], extT[2] t0 = para.firstTauIdx @@ -40,7 +40,7 @@ function green(para::DiagPara{W}, extK=DiagTree.getK(para.totalLoopNum, 1), extT # end if para.innerLoopNum == 0 - return Diagram{W}(BareGreenId(para, k=extK, t=extT), name=name) + return Graph([]; properties=BareGreenId(para, k=extK, t=extT), name=name) end # ################# after this step, the Green's function must be nontrivial! ################## @@ -55,15 +55,15 @@ function green(para::DiagPara{W}, extK=DiagTree.getK(para.totalLoopNum, 1), extT paraG = reconstruct(para, type=GreenDiag, firstTauIdx=Tidx, firstLoopIdx=Kidx, innerLoopNum=oG) G = Parquet.green(paraG, extK, group[:GT], true; blocks=blocks) # G = Diagram(GreenId(paraG, k = extK, t = group[:GT]), name = Symbol("g#$li")) #there is only one G diagram for a extT - @assert G isa Diagram + @assert G isa Graph # println(group) pairT = (t=(ΣTidx, (group[:GT][2])),) - return Diagram{W}(GenericId(para, pairT), Prod(), [group[:diagram], G], name=:ΣG) + return Graph([group[:diagram], G]; properties=GenericId(para, pairT), operator=Prod(), name=:ΣG) end para0 = reconstruct(para, innerLoopNum=0) #parameter for g0 - g0 = Diagram{W}(BareGreenId(para0, k=extK, t=(tin, t0)), name=:g0) - ΣGpairs = Vector{Diagram{W}}() + g0 = Graph([]; properties=BareGreenId(para0, k=extK, t=(tin, t0)), name=:g0) + ΣGpairs = Vector{Graph{Ftype,Wtype}}() for p in orderedPartition(para.innerLoopNum, 2, 0) oΣ, oG = p @@ -104,7 +104,7 @@ function green(para::DiagPara{W}, extK=DiagTree.getK(para.totalLoopNum, 1), extT # compositeG = Diagram{W}(GreenId(para, k=extK, t=extT), Prod(), [g0, ΣGmerged], name=:G) # PROPOSITION 1: Allow the user's custom name to persist after unwrapping with Parquet.green - compositeG = Diagram{W}(GreenId(para, k=extK, t=extT), Prod(), [g0, ΣGmerged], name=name) + compositeG = Graph([g0, ΣGmerged]; properties=GreenId(para, k=extK, t=extT), operator=Prod(), name=name) # PROPOSITION 2: Allow the user's custom name to persist after unwrapping with Parquet.green # if the string representation contains "G" (e.g., :G₁ and :Gdashed are allowed) diff --git a/src/frontend/parquet/operation.jl b/src/frontend/parquet/operation.jl new file mode 100644 index 00000000..6f9f55c4 --- /dev/null +++ b/src/frontend/parquet/operation.jl @@ -0,0 +1,141 @@ +function _combinegroups(groups, getid, operator, name) + # combine diagrams in a group into one composite diagram + gdf = combine(groups) do group # for each group in groups + # check the documentation of ``combine" for details https://dataframes.juliadata.org/stable/man/split_apply_combine/ + # id = isnothing(getid) ? GenericId(group.diagram[1].id.para, Tuple(group[1, fields])) : getid(group) + id = getid(group) + + if nrow(group) == 1 + # if there is only one diagram in df, and the new id is either GenericId or the id of the existing diagram, + # then simply return the current df without creating a new diagram + # ! the new factor will be multiplied to the factor of the exisiting diagram! + if id isa GenericId || typeof(id) == typeof(group.diagram[1].properties) + # diag = deepcopy(group[1, :diagram]) + diag = group.diagram[1] + return (diagram=diag, hash=diag.id) + end + end + diag = Graph(group.diagram; properties=id, operator=operator, name=name) + return (diagram=diag, hash=diag.id) + end + return gdf +end + +function _mergediag(group, id, operator, name) + if nrow(group) == 1 + # if there is only one diagram in df, and the new id is either GenericId or the id of the existing diagram, + # then simply return the current df without creating a new diagram + # ! the new factor will be multiplied to the factor of the exisiting diagram! + if id isa GenericId || typeof(id) == typeof(group.diagram[1].properties) + # diag = deepcopy(group[1, :diagram]) + diag = group.diagram[1] + return diag + end + end + return Graph(group.diagram; properties=id, operator=operator, name=name) +end + +function _combine(groups, getid, operator, name) + """ + # if fields = [:response, :extT], then + + # 1. groups.cols is like: Vector{Symbol}[:response, :extT] + + # 2. groups.keymap is like: + + # Dict{Any, Int64} with 2 entries: + # (UpDown, (1, 1, 1, 1)) => 2 + # (UpUp, (1, 1, 1, 1)) => 1 + # """ + d = Dict{Symbol,Any}() + _keys = keys(groups) + for col in groupcols(groups) + d[col] = [key[col] for key in _keys] + end + d[:diagram] = [_mergediag(groups[key], getid(groups[key]), operator, name) for key in _keys] + d[:hash] = [diag.id for diag in d[:diagram]] + return DataFrame(d, copycols=false) +end + +# function mergeby(df::DataFrame, fields=Vector{Symbol}(); +# operator=Sum(), name::Symbol=:none, +# getid::Function=g -> GenericId(g[1, :diagram].properties.para, Tuple(g[1, fields])) +# ) +# if isempty(df) +# return df +# else +# return mergeby(df, fields; operator=operator, name=name, getid=getid) +# end +# end + +function mergeby(df::DataFrame, fields=Vector{Symbol}(); + operator=Sum(), name::Symbol=:none, + getid::Function=g -> GenericId(g[1, :diagram].properties.para, Tuple(g[1, fields])) +) + if isempty(df) + return df + else + if all(x -> typeof(x.properties) == typeof(df.diagram[1].properties), df[!, :diagram]) == false + @warn "Not all DiagramIds in $df are the same!" + end + groups = DataFrames.groupby(df, fields, sort=true) + ######## less memory usage but can not pass the test right now ############## + d = _combine(groups, getid, operator, name) + ######## alternative approach (more memory) ################## + # d = _combinegroups(groups, getid, factor, operator, name) + # println("old\n$d \n new\n$cd") + return d + end +end + +function mergeby(diags::Union{Graph,Tuple,AbstractVector}, fields=nothing; idkey=nothing, kwargs...) + if diags isa Graph + return diags + else + if isempty(diags) + return diags + else + W = typeof(diags[1].weight) + @assert all(x -> (x.weight isa W), diags) "all diagrams should be of the same type. \n$diags" + diags = collect(diags) + if isnothing(fields) && isnothing(idkey) + return mergeby(diags; kwargs...) + else + return mergeby(diags, fields; idkey=idkey, kwargs...) + end + end + end +end + +# function mergeby(diags::AbstractVector, fields=[]; idkey::Vector{Symbol}=[], kwargs...) +function mergeby(diags::Vector{Graph{F,W}}, fields; idkey=Vector{Symbol}(), kwargs...) where {F,W} + if isempty(diags) + return diags + else + df = toDataFrame(diags, idkey) + mergedf = mergeby(df, fields; kwargs...) + return Vector{Graph{F,W}}(mergedf.diagram) + end +end + +function mergeby(diags::Vector{Graph{F,W}}; + operator=Sum(), name::Symbol=:none, + getid::Function=d -> GenericId(d[1].properties.para) +) where {F,W} + if isempty(diags) + return diags + else + id = getid(diags) + if length(diags) == 1 && (id isa GenericId || typeof(id) == typeof(diags[1].properties)) + # if there is only one diagram, and the new id is either GenericId or the id of the existing diagram, + # then simply return the current diagram without creating a new diagram + # ! the new factor will be multiplied to the factor of the exisiting diagram! + return diags + end + diag = Graph(diags; properties=id, operator=operator, name=name) + return [diag,] + end +end +# mergeby(df::DataFrame; kwargs...) = mergeby(df, []; kwargs...) +# mergeby(diags::Vector{Graph}; kwargs...) = mergeby(diags, []; kwargs...) + diff --git a/src/common.jl b/src/frontend/parquet/parquet.jl similarity index 52% rename from src/common.jl rename to src/frontend/parquet/parquet.jl index 70a0ee76..88e06060 100644 --- a/src/common.jl +++ b/src/frontend/parquet/parquet.jl @@ -1,3 +1,92 @@ +module Parquet + +import ..ComputationalGraphs +import ..ComputationalGraphs: Graph +import ..ComputationalGraphs: _dtype +import ..ComputationalGraphs: Sum +import ..ComputationalGraphs: Prod +# import ..ComputationalGraphs: Power +Ftype, Wtype = ComputationalGraphs._dtype.factor, ComputationalGraphs._dtype.weight + +using StaticArrays, PyCall +using AbstractTrees +using Parameters, Combinatorics +using DataFrames + +# if isdefined(Base, :Experimental) && isdefined(Base.Experimental, Symbol("@optlevel")) +# @eval Base.Experimental.@optlevel 1 +# end + + +const DI, EX, BOTH = 1, 2, 3 +const INL, OUTL, INR, OUTR = 1, 2, 3, 4 +# orginal diagrams T, U, S; particle-hole counterterm Ts, Us; and their counterterm Tc, Uc, Sc, Tsc, Usc +# symmetry factor for Alli, PHr, PHEr, PPr, PHrc, PHErc +const SymFactor = [1.0, -1.0, 1.0, -0.5, +1.0, -1.0] + +@enum TwoBodyChannel Alli = 1 PHr PHEr PPr AnyChan +@enum Permutation Di = 1 Ex DiEx + +Base.length(r::TwoBodyChannel) = 1 +Base.iterate(r::TwoBodyChannel) = (r, nothing) +function Base.iterate(r::TwoBodyChannel, ::Nothing) end + +Base.length(r::Permutation) = 1 +Base.iterate(r::Permutation) = (r, nothing) +function Base.iterate(r::Permutation, ::Permutation) end + +@enum DiagramType begin + VacuumDiag #vaccum diagram for the free energy + SigmaDiag #self-energy + GreenDiag #green's function + PolarDiag #polarization + Ver3Diag #3-point vertex function + Ver4Diag #4-point vertex function +end +Base.length(r::DiagramType) = 1 +Base.iterate(r::DiagramType) = (r, nothing) +function Base.iterate(r::DiagramType, ::Nothing) end + +@enum Filter begin + Wirreducible #remove all polarization subdiagrams + Girreducible #remove all self-energy inseration + NoHartree + NoFock + NoBubble # true to remove all bubble subdiagram + Proper #ver4, ver3, and polarization diagrams may require to be irreducible along the transfer momentum/frequency + DirectOnly # only direct interaction, this can be useful for debug purpose +end + +Base.length(r::Filter) = 1 +Base.iterate(r::Filter) = (r, nothing) +function Base.iterate(r::Filter, ::Nothing) end + +@enum Response begin + Composite + ChargeCharge + SpinSpin + ProperChargeCharge + ProperSpinSpin + UpUp + UpDown +end + +Base.length(r::Response) = 1 +Base.iterate(r::Response) = (r, nothing) +function Base.iterate(r::Response, ::Nothing) end + +@enum AnalyticProperty begin + Instant + Dynamic + D_Instant #derivative of instant interaction + D_Dynamic #derivative of the dynamic interaction +end + +Base.length(r::AnalyticProperty) = 1 +Base.iterate(r::AnalyticProperty) = (r, nothing) +function Base.iterate(r::AnalyticProperty, ::Nothing) end + + struct Interaction response::Response type::Set{AnalyticProperty} @@ -53,20 +142,47 @@ function symbol(name::Response, type::AnalyticProperty, addition=nothing) end -@with_kw struct DiagPara{W} +""" + struct ParquetBlocks + + The channels of the left and right sub-vertex4 of a bubble diagram in the parquet equation + +#Members +- `phi` : channels of left sub-vertex for the particle-hole and particle-hole-exchange bubbles +- `ppi` : channels of left sub-vertex for the particle-particle bubble +- `Γ4` : channels of right sub-vertex of all channels +""" +struct ParquetBlocks + phi::Vector{TwoBodyChannel} + ppi::Vector{TwoBodyChannel} + Γ4::Vector{TwoBodyChannel} + function ParquetBlocks(; phi=[Alli, PHEr, PPr], ppi=[Alli, PHr, PHEr], Γ4=union(phi, ppi)) + return new(phi, ppi, Γ4) + end +end + +function Base.isequal(a::ParquetBlocks, b::ParquetBlocks) + if issetequal(a.phi, b.phi) && issetequal(a.ppi, b.ppi) && issetequal(a.Γ4, b.Γ4) + return true + else + return false + end +end +Base.:(==)(a::ParquetBlocks, b::ParquetBlocks) = Base.isequal(a, b) + +@with_kw struct DiagPara type::DiagramType innerLoopNum::Int isFermi::Bool = true spin::Int = 2 - # loopDim::Int = 3 interaction::Vector{Interaction} = [Interaction(ChargeCharge, [Instant,]),] # :ChargeCharge, :SpinSpin, ... firstLoopIdx::Int = firstLoopIdx(type) totalLoopNum::Int = firstLoopIdx + innerLoopNum - 1 #### turn the following parameters on if there is tau variables ######## - hasTau::Bool = false + hasTau::Bool = true # enable imaginary-time variables firstTauIdx::Int = firstTauIdx(type) totalTauNum::Int = firstTauIdx + innerTauNum(type, innerLoopNum, interactionTauNum(hasTau, interaction)) - 1 #if there is no imaginary-time at all, then set this number to zero! @@ -76,8 +192,6 @@ end extra::Any = Nothing end -const DiagParaF64 = DiagPara{Float64} - @inline interactionTauNum(para::DiagPara) = interactionTauNum(para.hasTau, para.interaction) @inline innerTauNum(para::DiagPara) = innerTauNum(para.type, para.innerLoopNum, para.interactionTauNum) @@ -86,10 +200,10 @@ const DiagParaF64 = DiagPara{Float64} Type-stable version of the Parameters.reconstruct """ -function Parameters.reconstruct(::Type{DiagPara{W}}, p::DiagPara{W}, di) where {W} +function Parameters.reconstruct(::Type{DiagPara}, p::DiagPara, di) di = !isa(di, AbstractDict) ? Dict(di) : copy(di) get(p, di, key) = pop!(di, key, getproperty(p, key)) - return DiagPara{W}( + return DiagPara( # type = pop!(di, :type, p.type), type=get(p, di, :type), innerLoopNum=get(p, di, :innerLoopNum), @@ -109,10 +223,10 @@ function Parameters.reconstruct(::Type{DiagPara{W}}, p::DiagPara{W}, di) where { length(di) != 0 && error("Fields $(keys(di)) not in type $T") end -function derivepara(p::DiagPara{W}; kwargs...) where {W} +function derivepara(p::DiagPara; kwargs...) di = !isa(kwargs, AbstractDict) ? Dict(kwargs) : copy(kwargs) get(p, di, key) = pop!(di, key, getproperty(p, key)) - return DiagPara{W}( + return DiagPara( # type = pop!(di, :type, p.type), type=get(p, di, :type), innerLoopNum=get(p, di, :innerLoopNum), @@ -132,7 +246,7 @@ function derivepara(p::DiagPara{W}; kwargs...) where {W} length(di) != 0 && error("Fields $(keys(di)) not in type $T") end -function Base.isequal(p::DiagPara{W}, q::DiagPara{W}) where {W} +function Base.isequal(p::DiagPara, q::DiagPara) for field in fieldnames(typeof(p)) #fieldnames doesn't include user-defined entries in Base.getproperty if field == :filter if Set(p.filter) != Set(q.filter) @@ -159,93 +273,36 @@ function Base.isequal(p::DiagPara{W}, q::DiagPara{W}) where {W} return true end -Base.:(==)(a::DiagPara{W}, b::DiagPara{W}) where {W} = Base.isequal(a, b) +Base.:(==)(a::DiagPara, b::DiagPara) = Base.isequal(a, b) -""" - function innerTauNum(type::DiagramType, innerLoopNum, interactionTauNum) - - internal imaginary-time degrees of freedom for a given diagram type and internal loop number. - For the vertex functions (self-energy, polarization, vertex3, and vertex4), innerTauNum is equivalent to tauNum. - For the Green function, tauNum = innerTauNum + external tauNum -""" -function innerTauNum(type::DiagramType, innerLoopNum, interactionTauNum) - if type == Ver4Diag - return (innerLoopNum + 1) * interactionTauNum - elseif type == SigmaDiag - return innerLoopNum * interactionTauNum - elseif type == GreenDiag - return innerLoopNum * interactionTauNum - elseif type == VacuumDiag - return (innerLoopNum - 1) * interactionTauNum - elseif type == PolarDiag - return 1 + innerTauNum(Ver3Diag, innerLoopNum - 1, interactionTauNum) - elseif type == Ver3Diag - return 1 + innerTauNum(Ver4Diag, innerLoopNum - 1, interactionTauNum) - else - error("not implemented!") - end -end - -function interactionTauNum(hasTau::Bool, interactionSet) - if hasTau == false - return 0 - end - for interaction in interactionSet - if Dynamic in interaction.type || D_Dynamic in interaction.type - return 2 - end - end - return 1 -end +include("common.jl") -function firstTauIdx(type::DiagramType, offset::Int=0) - if type == GreenDiag - return 3 + offset - elseif type == Ver3Diag - return 1 + offset - elseif type == PolarDiag - return 1 + offset - else - return 1 + offset - end -end +include("diagram_id.jl") +include("operation.jl") -function firstLoopIdx(type::DiagramType, offset::Int=0) - if type == Ver4Diag #three extK - return 4 + offset - elseif type == SigmaDiag #one extK - return 2 + offset - elseif type == GreenDiag #one extK - return 2 + offset - elseif type == PolarDiag #one extK - return 2 + offset - elseif type == Ver3Diag #two extK - return 3 + offset - elseif type == VacuumDiag #no extK - return 1 + offset - else - error("not implemented!") - end -end +include("filter.jl") +include("vertex4.jl") -function totalTauNum(type::DiagramType, innerLoopNum, interactionTauNum, offset::Int=0) - return firstTauIdx(type, offset) + innerTauNum(type, innerLoopNum, interactionTauNum) - 1 -end +include("sigma.jl") +include("green.jl") +include("vertex3.jl") +include("polarization.jl") -function totalLoopNum(type::DiagramType, innerLoopNum, offset::Int=0) - return firstLoopIdx(type, offset) + innerLoopNum - 1 -end +include("ep_coupling.jl") -function totalTauNum(para, type::Symbol=:none) - return para.totalTauNum - # if type == :Ver4 - # return (para.internalLoopNum + 1) * para.interactionTauNum - # else - # error("not implemented!") - # end -end +include("benchmark/benchmark.jl") -function totalLoopNum(para, type::Symbol=:none) - return para.totalLoopNum -end +export DiagPara, ParquetBlocks +export Interaction, interactionTauNum, innerTauNum +export DiagramType, VacuumDiag, SigmaDiag, GreenDiag, PolarDiag, Ver3Diag, Ver4Diag +export Filter, Wirreducible, Girreducible, NoBubble, NoHartree, NoFock, Proper, DirectOnly +export Response, Composite, ChargeCharge, SpinSpin, ProperChargeCharge, ProperSpinSpin, UpUp, UpDown +export AnalyticProperty, Instant, Dynamic, D_Instant, D_Dynamic +export TwoBodyChannel, Alli, PHr, PHEr, PPr, AnyChan +export Permutation, Di, Ex, DiEx +export DiagramId, GenericId, Ver4Id, Ver3Id, GreenId, SigmaId, PolarId +export PropagatorId, BareGreenId, BareInteractionId +# export BareGreenNId, BareHoppingId, GreenNId, ConnectedGreenNId +export mergeby +end \ No newline at end of file diff --git a/src/parquet_builder/polarization.jl b/src/frontend/parquet/polarization.jl similarity index 85% rename from src/parquet_builder/polarization.jl rename to src/frontend/parquet/polarization.jl index a84a681d..b95f1d7b 100644 --- a/src/parquet_builder/polarization.jl +++ b/src/frontend/parquet/polarization.jl @@ -1,7 +1,6 @@ """ - function polarization(para, extK = DiagTree.getK(para.totalLoopNum, 1), subdiagram = false; name = :Π, resetuid = false, blocks::ParquetBlocks=ParquetBlocks()) - + function polarization(para::DiagPara, extK=getK(para.totalLoopNum, 1), subdiagram=false; name=:Π, resetuid=false, blocks::ParquetBlocks=ParquetBlocks()) Generate polarization diagrams using Parquet Algorithm. # Arguments @@ -16,9 +15,9 @@ Generate polarization diagrams using Parquet Algorithm. - A DataFrame with fields `:response`, `:diagram`, `:hash`. - All polarization share the same external Tau index. With imaginary-time variables, they are extT = (para.firstTauIdx, para.firstTauIdx+1) """ -function polarization(para::DiagPara{W}, extK=DiagTree.getK(para.totalLoopNum, 1), subdiagram=false; name=:Π, resetuid=false, +function polarization(para::DiagPara, extK=getK(para.totalLoopNum, 1), subdiagram=false; name=:Π, resetuid=false, blocks::ParquetBlocks=ParquetBlocks() -) where {W} +) resetuid && uidreset() @assert para.type == PolarDiag @assert para.innerLoopNum >= 1 @@ -46,7 +45,7 @@ function polarization(para::DiagPara{W}, extK=DiagTree.getK(para.totalLoopNum, 1 extT = para.hasTau ? (t0, t0 + 1) : (t0, t0) legK = [extK, K, K .- extK] - polar = DataFrame(response=Response[], extT=Tuple{Int,Int}[], diagram=Diagram{W}[]) + polar = DataFrame(response=Response[], extT=Tuple{Int,Int}[], diagram=Graph{Ftype,Wtype}[]) for (oVer3, oGin, oGout) in orderedPartition(para.innerLoopNum - 1, 3, 0) # ! Vertex3 must be in the first place, because we want to make sure that the bosonic extT of the vertex3 start with t0+1 @@ -72,10 +71,10 @@ function polarization(para::DiagPara{W}, extK=DiagTree.getK(para.totalLoopNum, 1 polarid = PolarId(para, response, k=extK, t=extT) gin = green(paraGin, K, (extT[1], extT[2]), true, name=:Gin) gout = green(paraGout, K .- extK, (extT[2], extT[1]), true, name=:Gout) - @assert gin isa Diagram && gout isa Diagram "$gin or $gout is not a single diagram" + @assert gin isa Graph && gout isa Graph "$gin or $gout is not a single graph" sign = para.isFermi ? -1.0 : 1.0 - polardiag = Diagram{W}(polarid, Prod(), [gin, gout], name=name, factor=sign) + polardiag = Graph([gin, gout], properties=polarid, operator=Prod(), name=name, factor=sign) push!(polar, (response=response, extT=extT, diagram=polardiag)) else ##################### composite polarization ##################################### @@ -102,7 +101,7 @@ function polarization(para::DiagPara{W}, extK=DiagTree.getK(para.totalLoopNum, 1 #transform extT coloum into extT for Vertex4 and the extT for Gin and Gout df = transform(ver3, :extT => ByRow(x -> [extT, (extT[1], x[2]), (x[3], extT[1])]) => [:extT, :GinT, :GoutT]) - groups = mergeby(W, df, [:response, :GinT, :GoutT, :extT], operator=Sum()) + groups = mergeby(df, [:response, :GinT, :GoutT, :extT], operator=Sum()) for v3 in eachrow(groups) response = v3.response @@ -111,9 +110,9 @@ function polarization(para::DiagPara{W}, extK=DiagTree.getK(para.totalLoopNum, 1 polarid = PolarId(para, response, k=extK, t=v3.extT) gin = green(paraGin, K, v3.GinT, true, name=:Gin, blocks=blocks) gout = green(paraGout, K .- extK, v3.GoutT, true, name=:Gout, blocks=blocks) - @assert gin isa Diagram && gout isa Diagram + @assert gin isa Graph && gout isa Graph - polardiag = Diagram{W}(polarid, Prod(), [gin, gout, v3.diagram], name=name) + polardiag = Graph([gin, gout, v3.diagram], properties=polarid, operator=Prod(), name=name) push!(polar, (response=response, extT=v3.extT, diagram=polardiag)) end end @@ -121,17 +120,14 @@ function polarization(para::DiagPara{W}, extK=DiagTree.getK(para.totalLoopNum, 1 end if isempty(polar) == false - # legK = [extK, K, K, extK] - # Factor = 1 / (2π)^para.loopDim - Factor = 1.0 - polar = mergeby(W, polar, [:response, :extT]; name=name, factor=Factor, + polar = mergeby(polar, [:response, :extT]; name=name, getid=g -> PolarId(para, g[1, :response], k=extK, t=extT) ) end return polar end -function _properPolarPara(p::DiagPara{W}, q) where {W} +function _properPolarPara(p::DiagPara, q) # ############ reset transferLoop to be q ################ if !(Proper in p.filter) || (length(p.transferLoop) != length(q)) || (p.transferLoop ≈ q) return derivepara(p, transferLoop=q, filter=union(Proper, p.filter)) diff --git a/src/parquet_builder/sigma.jl b/src/frontend/parquet/sigma.jl similarity index 89% rename from src/parquet_builder/sigma.jl rename to src/frontend/parquet/sigma.jl index b0700d41..36310a5c 100644 --- a/src/parquet_builder/sigma.jl +++ b/src/frontend/parquet/sigma.jl @@ -1,6 +1,7 @@ """ - function sigma(para, extK = DiagTree.getK(para.totalLoopNum, 1), subdiagram = false; name = :Σ, resetuid = false, blocks::ParquetBlocks=ParquetBlocks()) - + function sigma(para::DiagPara, extK=getK(para.totalLoopNum, 1), subdiagram=false; + name=:Σ, resetuid=false, blocks::ParquetBlocks=ParquetBlocks()) + Build sigma diagram. When sigma is created as a subdiagram, then no Fock diagram is generated if para.filter contains NoFock, and no sigma diagram is generated if para.filter contains Girreducible @@ -16,10 +17,10 @@ When sigma is created as a subdiagram, then no Fock diagram is generated if para - A DataFrame with fields `:type`, `:extT`, `:diagram`, `:hash` - All sigma share the same incoming Tau index, but not the outgoing one """ -function sigma(para::DiagPara{W}, extK=DiagTree.getK(para.totalLoopNum, 1), subdiagram=false; +function sigma(para::DiagPara, extK=getK(para.totalLoopNum, 1), subdiagram=false; name=:Σ, resetuid=false, blocks::ParquetBlocks=ParquetBlocks() -) where {W} - resetuid && uidreset() +) + resetuid && ComputationalGraphs.uidreset() (para.type == SigmaDiag) || error("$para is not for a sigma diagram") (para.innerLoopNum >= 1) || error("sigma must has more than one inner loop") # @assert length(extK) == para.totalLoopNum @@ -31,7 +32,7 @@ function sigma(para::DiagPara{W}, extK=DiagTree.getK(para.totalLoopNum, 1), subd (length(extK) >= para.totalLoopNum) || error("expect dim of extK>=$(para.totalLoopNum), got $(length(extK))") extK = extK[1:para.totalLoopNum] - compositeSigma = DataFrame(type=AnalyticProperty[], extT=Tuple{Int,Int}[], diagram=Diagram{W}[]) + compositeSigma = DataFrame(type=AnalyticProperty[], extT=Tuple{Int,Int}[], diagram=Graph{Ftype,Wtype}[]) if isValidSigma(para.filter, para.innerLoopNum, subdiagram) == false # return DataFrame(type=[], extT=[], diagram=[]) @@ -58,7 +59,7 @@ function sigma(para::DiagPara{W}, extK=DiagTree.getK(para.totalLoopNum, 1), subd response, type = group[:response], group[:type] sid = SigmaId(para, type, k=extK, t=group[:extT]) g = green(paraG, K, group[:GT], true; name=(oW == 0 ? :Gfock : :G_Σ), blocks=blocks) #there is only one G diagram for a extT - (g isa Diagram) || error("green function must return a Diagram") + (g isa Graph) || error("green function must return a Graph") # Sigma = G*(2 W↑↑ - W↑↓) # ! The sign of ↑↓ is from the spin symmetry, not from the fermionic statistics! spinfactor = (response == UpUp) ? 2 : -1 @@ -66,7 +67,7 @@ function sigma(para::DiagPara{W}, extK=DiagTree.getK(para.totalLoopNum, 1), subd spinfactor *= 0.5 end # plot_tree(mergeby(DataFrame(group)), maxdepth = 7) - sigmadiag = Diagram{W}(sid, Prod(), [g, group[:diagram]], factor=spinfactor, name=name) + sigmadiag = Graph([g, group[:diagram]]; properties=sid, operator=Prod(), factor=spinfactor, name=name) # plot_tree(sigmadiag, maxdepth = 7) return (type=type, extT=group[:extT], diagram=sigmadiag) end @@ -112,7 +113,7 @@ function sigma(para::DiagPara{W}, extK=DiagTree.getK(para.totalLoopNum, 1), subd # plot_tree(ver4) df = transform(ver4, :extT => ByRow(x -> [(x[INL], x[OUTR]), (x[OUTL], x[INR])]) => [:extT, :GT]) - groups = mergeby(W, df, [:response, :type, :GT, :extT], operator=Sum()) + groups = mergeby(df, [:response, :type, :GT, :extT], operator=Sum()) for mergedVer4 in eachrow(groups) push!(compositeSigma, GWwithGivenExTtoΣ(mergedVer4, oW, paraG)) end @@ -123,11 +124,9 @@ function sigma(para::DiagPara{W}, extK=DiagTree.getK(para.totalLoopNum, 1), subd if isempty(compositeSigma) return compositeSigma else - # Factor = 1 / (2π)^para.loopDim - Factor = 1.0 # sigmaid(g) = SigmaId(para, g[1, :type], k=extK, t=g[1, :extT]) # sigmadf = mergeby(compositeSigma, [:type, :extT], name=name, factor=Factor, getid=sigmaid) - sigmadf = mergeby(W, compositeSigma, [:type, :extT], name=name, factor=Factor, + sigmadf = mergeby(compositeSigma, [:type, :extT], name=name, getid=g -> SigmaId(para, g[1, :type], k=extK, t=g[1, :extT])) all(x -> x[1] == para.firstTauIdx, sigmadf.extT) || error("all sigma should share the same in Tidx\n$sigmadf") diff --git a/src/parquet_builder/sigmaGV.jl b/src/frontend/parquet/sigmaGV.jl similarity index 86% rename from src/parquet_builder/sigmaGV.jl rename to src/frontend/parquet/sigmaGV.jl index 3253b075..e15826e4 100644 --- a/src/parquet_builder/sigmaGV.jl +++ b/src/frontend/parquet/sigmaGV.jl @@ -1,6 +1,6 @@ """ - function sigmaGV(para, extK = DiagTree.getK(para.totalLoopNum, 1), subdiagram = false; name = :Σ, resetuid = false, blocks::ParquetBlocks=ParquetBlocks()) + function sigmaGV(para, extK = getK(para.totalLoopNum, 1), subdiagram = false; name = :Σ, resetuid = false, blocks::ParquetBlocks=ParquetBlocks()) Build sigma diagram. When sigma is created as a subdiagram, then no Fock diagram is generated if para.filter contains NoFock, and no sigma diagram is generated if para.filter contains Girreducible @@ -17,9 +17,9 @@ When sigma is created as a subdiagram, then no Fock diagram is generated if para - A DataFrame with fields `:type`, `:extT`, `:diagram`, `:hash` - All sigma share the same incoming Tau index, but not the outgoing one """ -function sigmaGV(para::DiagPara{W}, extK=DiagTree.getK(para.totalLoopNum, 1), subdiagram=false; +function sigmaGV(para::DiagPara, extK=getK(para.totalLoopNum, 1), subdiagram=false; name=:Σ, resetuid=false, blocks::ParquetBlocks=ParquetBlocks() -) where {W} +) resetuid && uidreset() for i in para.interaction @assert (Dynamic in i.type) == false "Dynamic interaction is not supported for sigmaGV diagrams." @@ -37,7 +37,7 @@ function sigmaGV(para::DiagPara{W}, extK=DiagTree.getK(para.totalLoopNum, 1), su (length(extK) >= para.totalLoopNum) || error("expect dim of extK>=$(para.totalLoopNum), got $(length(extK))") extK = extK[1:para.totalLoopNum] - compositeSigma = DataFrame(type=AnalyticProperty[], extT=Tuple{Int,Int}[], diagram=Diagram{W}[]) + compositeSigma = DataFrame(type=AnalyticProperty[], extT=Tuple{Int,Int}[], diagram=Graph{Ftype,Wtype}[]) if isValidSigma(para.filter, para.innerLoopNum, subdiagram) == false # return DataFrame(type=[], extT=[], diagram=[]) @@ -64,7 +64,7 @@ function sigmaGV(para::DiagPara{W}, extK=DiagTree.getK(para.totalLoopNum, 1), su response, type = group[:response], group[:type] sid = SigmaId(para, type, k=extK, t=group[:extT]) g = green(paraG, K, group[:GT], true; name=(oW == 0 ? :Gfock : :G_Σ), blocks=blocks) #there is only one G diagram for a extT - (g isa Diagram) || error("green function must return a Diagram") + (g isa Graph) || error("green function must return a Graph") # Sigma = G*(2 W↑↑ - W↑↓) # ! The sign of ↑↓ is from the spin symmetry, not from the fermionic statistics! spinfactor = (response == UpUp) ? 2 : -1 @@ -72,7 +72,7 @@ function sigmaGV(para::DiagPara{W}, extK=DiagTree.getK(para.totalLoopNum, 1), su spinfactor *= 0.5 end # plot_tree(mergeby(DataFrame(group)), maxdepth = 7) - sigmadiag = Diagram{W}(sid, Prod(), [g, group[:diagram]], factor=spinfactor, name=name) + sigmadiag = Graph([g, group[:diagram]], properties=sid, operator=Prod(), factor=spinfactor, name=name) # plot_tree(sigmadiag, maxdepth = 7) return (type=type, extT=group[:extT], diagram=sigmadiag) end @@ -103,7 +103,7 @@ function sigmaGV(para::DiagPara{W}, extK=DiagTree.getK(para.totalLoopNum, 1), su ver4 = bareV df = transform(ver4, :extT => ByRow(x -> [(x[INL], x[OUTR]), (x[OUTL], x[INR])]) => [:extT, :GT]) - groups = mergeby(W, df, [:response, :type, :GT, :extT], operator=Sum()) + groups = mergeby(df, [:response, :type, :GT, :extT], operator=Sum()) for mergedVer4 in eachrow(groups) push!(compositeSigma, GWwithGivenExTtoΣ(mergedVer4, oW, paraG)) end @@ -119,11 +119,7 @@ function sigmaGV(para::DiagPara{W}, extK=DiagTree.getK(para.totalLoopNum, 1), su if isempty(compositeSigma) return compositeSigma else - # Factor = 1 / (2π)^para.loopDim - Factor = 1.0 - # sigmaid(g) = SigmaId(para, g[1, :type], k=extK, t=g[1, :extT]) - # sigmadf = mergeby(compositeSigma, [:type, :extT], name=name, factor=Factor, getid=sigmaid) - sigmadf = mergeby(W, compositeSigma, [:type, :extT], name=name, factor=Factor, + sigmadf = mergeby(compositeSigma, [:type, :extT], name=name, getid=g -> SigmaId(para, g[1, :type], k=extK, t=g[1, :extT])) all(x -> x[1] == para.firstTauIdx, sigmadf.extT) || error("all sigma should share the same in Tidx\n$sigmadf") diff --git a/src/parquet_builder/vertex3.jl b/src/frontend/parquet/vertex3.jl similarity index 84% rename from src/parquet_builder/vertex3.jl rename to src/frontend/parquet/vertex3.jl index affedb7f..d5302d88 100644 --- a/src/parquet_builder/vertex3.jl +++ b/src/frontend/parquet/vertex3.jl @@ -1,8 +1,6 @@ """ - function vertex3(para, extK = [DiagTree.getK(para.totalLoopNum, 1), DiagTree.getK(para.totalLoopNum, 2)], - subdiagram = false; name = :Γ3, chan = [PHr, PHEr, PPr, Alli], resetuid = false, - blocks::ParquetBlocks=ParquetBlocks() - ) + function vertex3(para::DiagPara, _extK=[getK(para.totalLoopNum, 1), getK(para.totalLoopNum, 2)], subdiagram=false; + name=:Γ3, chan=[PHr, PHEr, PPr, Alli], resetuid=false, blocks::ParquetBlocks=ParquetBlocks()) Generate 3-vertex diagrams using Parquet Algorithm. With imaginary-time variables, all vertex3 generated has the same bosonic Tidx ``extT[1]=para.firstTauIdx`` and the incoming fermionic Tidx ``extT[2]=para.firstTauIdx+1``. @@ -19,16 +17,16 @@ With imaginary-time variables, all vertex3 generated has the same bosonic Tidx ` # Output - A DataFrame with fields :response, :extT, :diagram, :hash. """ -function vertex3(para::DiagPara{WW}, - _extK=[DiagTree.getK(para.totalLoopNum, 1), DiagTree.getK(para.totalLoopNum, 2)], +function vertex3(para::DiagPara, + _extK=[getK(para.totalLoopNum, 1), getK(para.totalLoopNum, 2)], subdiagram=false; name=:Γ3, chan=[PHr, PHEr, PPr, Alli], resetuid=false, blocks::ParquetBlocks=ParquetBlocks() -) where {WW} +) - resetuid && uidreset() + resetuid && ComputationalGraphs.uidreset() @assert para.type == Ver3Diag @assert para.innerLoopNum >= 1 "Only generates vertex corrections with more than one internal loops." for k in _extK @@ -44,7 +42,7 @@ function vertex3(para::DiagPara{WW}, para = _properVer3Para(para, q) t0 = para.firstTauIdx - vertex3 = DataFrame(response=Response[], extT=Tuple{Int,Int,Int}[], diagram=Diagram{WW}[]) + vertex3 = DataFrame(response=Response[], extT=Tuple{Int,Int,Int}[], diagram=Graph{Ftype,Wtype}[]) # if para.innerLoopNum == 0 # push!(vertex3, (response = UpUp, extT = (t0, t0, t0), diagram = ver3diag)) @@ -88,7 +86,7 @@ function vertex3(para::DiagPara{WW}, #transform extT coloum into extT for Vertex4 and the extT for Gin and Gout df = transform(ver4, :extT => ByRow(x -> [(t0, x[INL], x[OUTL]), (t0, x[INR]), (x[OUTR], t0)]) => [:extT, :GinT, :GoutT]) - groups = mergeby(WW, df, [:response, :GinT, :GoutT, :extT], operator=Sum()) + groups = mergeby(df, [:response, :GinT, :GoutT, :extT], operator=Sum()) for v4 in eachrow(groups) response = v4.response @@ -97,9 +95,9 @@ function vertex3(para::DiagPara{WW}, ver3id = Ver3Id(para, response, k=extK, t=v4.extT) gin = green(paraGin, K, v4.GinT, true, name=:Gin, blocks=blocks) gout = green(paraGout, K .+ q, v4.GoutT, true, name=:Gout, blocks=blocks) - @assert gin isa Diagram && gout isa Diagram + @assert gin isa Graph && gout isa Graph - ver3diag = Diagram{WW}(ver3id, Prod(), [gin, gout, v4.diagram], name=name) + ver3diag = Graph([gin, gout, v4.diagram], properties=ver3id, operator=Prod(), name=name) push!(vertex3, (response=response, extT=v4.extT, diagram=ver3diag)) end end @@ -107,16 +105,14 @@ function vertex3(para::DiagPara{WW}, # println(vertex3) if isempty(vertex3) == false - # Factor = 1 / (2π)^para.loopDim - Factor = 1.0 - vertex3 = mergeby(WW, vertex3, [:response, :extT]; name=name, factor=Factor, + vertex3 = mergeby(vertex3, [:response, :extT]; name=name, getid=g -> Ver3Id(para, g[1, :response], k=extK, t=g[1, :extT]) ) end return vertex3 end -function _properVer3Para(p::DiagPara{W}, q) where {W} +function _properVer3Para(p::DiagPara, q) # ############ reset transferLoop to be q ################ if Proper in p.filter if (length(p.transferLoop) != length(q)) || (!(p.transferLoop ≈ q)) #first check if the dimension is wrong diff --git a/src/parquet_builder/vertex4.jl b/src/frontend/parquet/vertex4.jl similarity index 89% rename from src/parquet_builder/vertex4.jl rename to src/frontend/parquet/vertex4.jl index 23bc1637..95a3b8a4 100644 --- a/src/parquet_builder/vertex4.jl +++ b/src/frontend/parquet/vertex4.jl @@ -1,6 +1,6 @@ """ vertex4(para::DiagPara, - extK = [DiagTree.getK(para.totalLoopNum, 1), DiagTree.getK(para.totalLoopNum, 2), DiagTree.getK(para.totalLoopNum, 3)], + extK = [getK(para.totalLoopNum, 1), getK(para.totalLoopNum, 2), getK(para.totalLoopNum, 3)], chan::AbstractVector = [PHr, PHEr, PPr, Alli], subdiagram = false; level = 1, name = :none, resetuid = false, @@ -24,14 +24,14 @@ Generate 4-vertex diagrams using Parquet Algorithm # Output - A DataFrame with fields :response, :type, :extT, :diagram, :hash """ -function vertex4(para::DiagPara{W}, - extK=[DiagTree.getK(para.totalLoopNum, 1), DiagTree.getK(para.totalLoopNum, 2), DiagTree.getK(para.totalLoopNum, 3)], +function vertex4(para::DiagPara, + extK=[getK(para.totalLoopNum, 1), getK(para.totalLoopNum, 2), getK(para.totalLoopNum, 3)], chan::AbstractVector=[PHr, PHEr, PPr, Alli], subdiagram=false; level=1, name=:none, resetuid=false, # phi_toplevel=ParquetBlocks().phi, ppi_toplevel=ParquetBlocks().ppi, Γ4_toplevel=ParquetBlocks().Γ4, blocks::ParquetBlocks=ParquetBlocks(), blockstoplevel::ParquetBlocks=blocks -) where {W} +) # if (para.innerLoopNum > 1) && (NoBubble in para.filter) # @warn "Vertex4 with two or more loop orders still contain bubble subdiagram even if NoBubble is turned on in para.filter!" @@ -44,7 +44,7 @@ function vertex4(para::DiagPara{W}, legK = [k[1:para.totalLoopNum] for k in extK[1:3]] push!(legK, legK[1] + legK[3] - legK[2]) - resetuid && uidreset() + resetuid && ComputationalGraphs.uidreset() @assert para.totalTauNum >= maxVer4TauIdx(para) "Increase totalTauNum!\n$para" @assert para.totalLoopNum >= maxVer4LoopIdx(para) "Increase totalLoopNum\n$para" @@ -60,7 +60,7 @@ function vertex4(para::DiagPara{W}, loopNum = para.innerLoopNum # @assert loopNum >= 0 - ver4df = DataFrame(response=Response[], type=AnalyticProperty[], extT=Tuple{Int,Int,Int,Int}[], diagram=Diagram{W}[]) + ver4df = DataFrame(response=Response[], type=AnalyticProperty[], extT=Tuple{Int,Int,Int,Int}[], diagram=Graph{Ftype,Wtype}[]) if loopNum == 0 if DirectOnly in para.filter @@ -92,28 +92,28 @@ function vertex4(para::DiagPara{W}, # # TODO: add envolpe diagrams end # println(typeof(groups)) - ver4df = merge_vertex4(para, ver4df, name, legK, W) + ver4df = merge_vertex4(para, ver4df, name, legK) @assert all(x -> x[1] == para.firstTauIdx, ver4df.extT) "not all extT[1] are equal to the first Tau index $(para.firstTauIdx)! $ver4df" return ver4df end -function merge_vertex4(para, ver4df, name, legK, W) +function merge_vertex4(para, ver4df, name, legK) diags = ver4df.diagram - @assert all(x -> x.id isa Ver4Id, diags) "not all id are Ver4Id! $diags" - @assert all(x -> x.id.extK ≈ legK, diags) "not all extK are the same! $diags" + @assert all(x -> x.properties isa Ver4Id, diags) "not all id are Ver4Id! $diags" + @assert all(x -> x.properties.extK ≈ legK, diags) "not all extK are the same! $diags" # @assert isempty(diags) == false "got empty ver4! $chan with\n $para\n" if isempty(ver4df) == false - ver4df = mergeby(W, ver4df, [:response, :type, :extT], name=name, + ver4df = mergeby(ver4df, [:response, :type, :extT], name=name, getid=g -> Ver4Id(para, g[1, :response], g[1, :type], k=legK, t=g[1, :extT]) #generate id from the dataframe ) end return ver4df end -function bubble!(ver4df::DataFrame, para::DiagPara{W}, legK, chan::TwoBodyChannel, partition::Vector{Int}, level::Int, name::Symbol, +function bubble!(ver4df::DataFrame, para::DiagPara, legK, chan::TwoBodyChannel, partition::Vector{Int}, level::Int, name::Symbol, blocks::ParquetBlocks, blockstoplevel::ParquetBlocks, - extrafactor=1.0) where {W} + extrafactor=1.0) TauNum = interactionTauNum(para) # maximum tau number for each bare interaction oL, oG0, oR, oGx = partition[1], partition[2], partition[3], partition[4] @@ -162,10 +162,10 @@ function bubble!(ver4df::DataFrame, para::DiagPara{W}, legK, chan::TwoBodyChanne for ldiag in Lver.diagram for rdiag in Rver.diagram - extT, G0T, GxT = tauBasis(chan, ldiag.id.extT, rdiag.id.extT) + extT, G0T, GxT = tauBasis(chan, ldiag.properties.extT, rdiag.properties.extT) g0 = green(g0Para, K, G0T, true, name=:G0, blocks=blocks) gx = green(gxPara, Kx, GxT, true, name=:Gx, blocks=blocks) - @assert g0 isa Diagram && gx isa Diagram + @assert g0 isa Graph && gx isa Graph # append!(diag, bubble2diag(para, chan, ldiag, rdiag, legK, g0, gx, extrafactor)) bubble2diag!(ver8, para, chan, ldiag, rdiag, legK, g0, gx, extrafactor) end @@ -175,16 +175,16 @@ function bubble!(ver4df::DataFrame, para::DiagPara{W}, legK, chan::TwoBodyChanne G0T, GxT, extT, Vresponse, vtype = key g0 = green(g0Para, K, G0T, true, name=:G0, blocks=blocks) gx = green(gxPara, Kx, GxT, true, name=:Gx, blocks=blocks) - @assert g0 isa Diagram && gx isa Diagram + @assert g0 isa Graph && gx isa Graph id = Ver4Id(para, Vresponse, vtype, k=legK, t=extT, chan=chan) if length(ver8[key]) == 1 - diag = Diagram{W}(id, Prod(), [ver8[key][1], g0, gx], factor=1.0) + diag = Graph([ver8[key][1], g0, gx]; properties=id, operator=Prod()) push!(ver4df, (response=Vresponse, type=vtype, extT=extT, diagram=diag)) elseif isempty(ver8[key]) continue else - diag = Diagram{W}(GenericId(para), Sum(), ver8[key], factor=1.0) - ver4diag = Diagram{W}(id, Prod(), [diag, g0, gx], factor=1.0) + diag = Graph(ver8[key]; properties=GenericId(para), operator=Sum()) + ver4diag = Graph([diag, g0, gx]; properties=id, operator=Prod()) push!(ver4df, (response=Vresponse, type=vtype, extT=extT, diagram=ver4diag)) end # push!(ver4df, (response=Vresponse, type=vtype, extT=extT, diagram=diag)) @@ -204,8 +204,8 @@ function RPA_chain!(ver4df::DataFrame, para::DiagPara, legK, chan::TwoBodyChanne return end -function bubble2diag!(ver8, para::DiagPara{W}, chan::TwoBodyChannel, ldiag, rdiag, extK, g0, gx, extrafactor) where {W} - lid, rid = ldiag.id, rdiag.id +function bubble2diag!(ver8, para::DiagPara, chan::TwoBodyChannel, ldiag, rdiag, extK, g0, gx, extrafactor) + lid, rid = ldiag.properties, rdiag.properties ln, rn = lid.response, rid.response lo, ro = lid.para.innerLoopNum, rid.para.innerLoopNum vtype = typeMap(lid.type, rid.type) @@ -223,11 +223,8 @@ function bubble2diag!(ver8, para::DiagPara{W}, chan::TwoBodyChannel, ldiag, rdia if ln == Lresponse && rn == Rresponse nodeName = Symbol("$(spin(Lresponse))x$(spin(Rresponse)) → $chan,") id = GenericId(para) - # diag = Diagram{W}(id, Prod(), [g0, gx, ldiag, rdiag], factor=factor * Factor, name=nodeName) - diag = Diagram{W}(id, Prod(), [ldiag, rdiag], factor=factor * Factor, name=nodeName) + diag = Graph([ldiag, rdiag]; properties=id, operator=Prod(), factor=factor * Factor, name=nodeName) push!(ver8[key], diag) - # push!(ver4df, (response=Vresponse, type=vtype, extT=extT, diagram=diag)) - # push!(diag, Diagram(id, Prod(), [g0, gx, ldiag, rdiag], factor=factor * Factor, name=nodeName)) end end @@ -268,8 +265,8 @@ function bubble2diag!(ver8, para::DiagPara{W}, chan::TwoBodyChannel, ldiag, rdia return end -function _bare(para::DiagPara{W}, diex::Vector{Permutation}, response::Response, type::AnalyticProperty, - _diex::Permutation, _innerT::Tuple{Int,Int}, _q, _factor=1.0) where {W} +function _bare(para::DiagPara, diex::Vector{Permutation}, response::Response, type::AnalyticProperty, + _diex::Permutation, _innerT::Tuple{Int,Int}, _q, _factor=1.0) @assert _diex == Di || _diex == Ex # there is an overall sign coming from Taylor expansion of exp(-S) depsite the statistics @@ -283,24 +280,23 @@ function _bare(para::DiagPara{W}, diex::Vector{Permutation}, response::Response, if notProper(para, _q) == false && _diex in diex #create new bare ver4 only if _diex is required in the diex table - vid = BareInteractionId(para, response, type, k=_q, t=_innerT, permu=_diex) - return Diagram{W}(vid, factor=sign * _factor) + vid = BareInteractionId(para, response, type, k=_q, t=_innerT) + return Graph([]; factor=sign * _factor, properties=vid) else return nothing end end -function _pushbarever4!(para::DiagPara{W}, nodes::DataFrame, response::Response, type::AnalyticProperty, _extT, legK, - vd::Union{Nothing,Diagram{W}}, ve::Union{Nothing,Diagram{W}}) where {W} +function _pushbarever4!(para::DiagPara, nodes::DataFrame, response::Response, type::AnalyticProperty, _extT, legK, vd, ve) if isnothing(vd) == false id_di = Ver4Id(para, response, type, k=legK, t=_extT[DI]) - push!(nodes, (response=response, type=type, extT=_extT[DI], diagram=Diagram{W}(id_di, Sum(), [vd,]))) + push!(nodes, (response=response, type=type, extT=_extT[DI], diagram=Graph([vd,]; operator=Sum(), properties=id_di))) end if isnothing(ve) == false id_ex = Ver4Id(para, response, type, k=legK, t=_extT[EX]) - push!(nodes, (response=response, type=type, extT=_extT[EX], diagram=Diagram{W}(id_ex, Sum(), [ve,]))) + push!(nodes, (response=response, type=type, extT=_extT[EX], diagram=Graph([ve,]; operator=Sum(), properties=id_ex))) end end diff --git a/src/strong_coupling_expansion_builder/Gc.jl b/src/frontend/strong_coupling_expansion_builder/Gc.jl similarity index 90% rename from src/strong_coupling_expansion_builder/Gc.jl rename to src/frontend/strong_coupling_expansion_builder/Gc.jl index 57c75736..76845a6b 100644 --- a/src/strong_coupling_expansion_builder/Gc.jl +++ b/src/frontend/strong_coupling_expansion_builder/Gc.jl @@ -30,7 +30,7 @@ function connectedGreen(para, hop::Vector{BareHoppingId}, subdiagram=false; name if isnothing(subGn) || isnothing(subGc) continue end - push!(Gc, Diagram(GenericId(para), Prod(), [subGc, subGn], factor=-1.0)) #additional minus sign because Gc(s) = Gn(s) - \sum_o Gc(o)Gn(s-o) + push!(Gc, Graph([subGc, subGn], properties=GenericId(para), operator=Prod(), factor=-1.0)) #additional minus sign because Gc(s) = Gn(s) - \sum_o Gc(o)Gn(s-o) end extT, orbital, site, creation = [], [], [], [] @@ -40,7 +40,7 @@ function connectedGreen(para, hop::Vector{BareHoppingId}, subdiagram=false; name append!(creation, [true, false]) append!(orbital, h.orbital) end - return Diagram(ConnectedGreenNId(para, orbital=orbital, t=extT, r=site, creation=creation), Sum(), Gc, name=name) + return Graph(Gc, properties=ConnectedGreenNId(para, orbital=orbital, t=extT, r=site, creation=creation), operator=Sum(), name=name) end # function connectedGreen(para, site::AbstractVector, orbital::AbstractVector, extT::AbstractVector = collect(1:length(orbital)), subdiagram = false; name = Symbol("Gc$(length(site))"), resetuid = false, even = true) diff --git a/src/strong_coupling_expansion_builder/Gn.jl b/src/frontend/strong_coupling_expansion_builder/Gn.jl similarity index 88% rename from src/strong_coupling_expansion_builder/Gn.jl rename to src/frontend/strong_coupling_expansion_builder/Gn.jl index 6e4289da..e03c0a76 100644 --- a/src/strong_coupling_expansion_builder/Gn.jl +++ b/src/frontend/strong_coupling_expansion_builder/Gn.jl @@ -58,7 +58,7 @@ function fullGreen(para, hop::Vector{BareHoppingId}, subdiagram=false; name=Symb o = orbital[ind] c = _creation[ind] bareGId = BareGreenNId(para, orbital=o, t=t, r=r, creation=c) - push!(gn, Diagram(bareGId, name=Symbol("gn$(length(t))"))) + push!(gn, Graph([], properties=bareGId, name=Symbol("gn$(length(t))"))) append!(permutation, ind) end @@ -66,9 +66,9 @@ function fullGreen(para, hop::Vector{BareHoppingId}, subdiagram=false; name=Symb return nothing else for h in hop - push!(gn, Diagram(h, name=:hop)) + push!(gn, Graph([], properties=h, name=:hop)) end # println(permutation) - return Diagram(GreenNId(para, orbital=orbital, t=extT, r=site, creation=_creation), Prod(), gn, name=name, factor=parity(permutation)) + return Graph(gn, properties=GreenNId(para, orbital=orbital, t=extT, r=site, creation=_creation), operator=Prod(), name=name, factor=parity(permutation)) end end \ No newline at end of file diff --git a/src/strong_coupling_expansion_builder/common.jl b/src/frontend/strong_coupling_expansion_builder/common.jl similarity index 99% rename from src/strong_coupling_expansion_builder/common.jl rename to src/frontend/strong_coupling_expansion_builder/common.jl index 1663fb79..1581fbda 100644 --- a/src/strong_coupling_expansion_builder/common.jl +++ b/src/frontend/strong_coupling_expansion_builder/common.jl @@ -35,8 +35,6 @@ import ..Interaction import ..DiagPara import ..innerTauNum -import ..Diagram - import ..DiagramId import ..Ver4Id import ..Ver3Id diff --git a/src/strong_coupling_expansion_builder/strong_coupling_expansion b/src/frontend/strong_coupling_expansion_builder/strong_coupling_expansion.jl similarity index 100% rename from src/strong_coupling_expansion_builder/strong_coupling_expansion rename to src/frontend/strong_coupling_expansion_builder/strong_coupling_expansion.jl diff --git a/src/strong_coupling_expansion_builder/vacuum.jl b/src/frontend/strong_coupling_expansion_builder/vacuum.jl similarity index 100% rename from src/strong_coupling_expansion_builder/vacuum.jl rename to src/frontend/strong_coupling_expansion_builder/vacuum.jl diff --git a/src/parquet_builder/parquet.jl b/src/parquet_builder/parquet.jl deleted file mode 100644 index 8344b657..00000000 --- a/src/parquet_builder/parquet.jl +++ /dev/null @@ -1,34 +0,0 @@ -module Parquet - -using StaticArrays, PyCall -using AbstractTrees -using Parameters, Combinatorics -using DataFrames -using ..DiagTree - -# if isdefined(Base, :Experimental) && isdefined(Base.Experimental, Symbol("@optlevel")) -# @eval Base.Experimental.@optlevel 1 -# end - - -const DI, EX, BOTH = 1, 2, 3 -const INL, OUTL, INR, OUTR = 1, 2, 3, 4 -# orginal diagrams T, U, S; particle-hole counterterm Ts, Us; and their counterterm Tc, Uc, Sc, Tsc, Usc -# symmetry factor for Alli, PHr, PHEr, PPr, PHrc, PHErc -const SymFactor = [1.0, -1.0, 1.0, -0.5, +1.0, -1.0] - -include("common.jl") -export ParquetBlocks - -include("filter.jl") -include("vertex4.jl") - -include("sigma.jl") -include("green.jl") -include("vertex3.jl") -include("polarization.jl") - -include("ep_coupling.jl") - -include("benchmark/benchmark.jl") -end \ No newline at end of file diff --git a/src/utility.jl b/src/utility.jl index 87b0b71e..0c381eb0 100644 --- a/src/utility.jl +++ b/src/utility.jl @@ -5,17 +5,12 @@ using ..ComputationalGraphs: decrement_power using ..ComputationalGraphs: build_all_leaf_derivative, eval!, isfermionic import ..ComputationalGraphs: count_operation, count_expanded_operation using ..ComputationalGraphs.AbstractTrees -using ..DiagTree -using ..DiagTree: Diagram, PropagatorId, BareGreenId, BareInteractionId using ..Taylor @inline apply(::Type{ComputationalGraphs.Sum}, diags::Vector{T}, factors::Vector{F}) where {T<:TaylorSeries,F<:Number} = sum(d * f for (d, f) in zip(diags, factors)) @inline apply(::Type{ComputationalGraphs.Prod}, diags::Vector{T}, factors::Vector{F}) where {T<:TaylorSeries,F<:Number} = prod(d * f for (d, f) in zip(diags, factors)) @inline apply(::Type{ComputationalGraphs.Power{N}}, diags::Vector{T}, factors::Vector{F}) where {N,T<:TaylorSeries,F<:Number} = (diags[1])^N * factors[1] -@inline apply(::Type{DiagTree.Sum}, diags::Vector{T}, factors::Vector{F}) where {T<:TaylorSeries,F<:Number} = sum(d * f for (d, f) in zip(diags, factors)) -@inline apply(::Type{DiagTree.Prod}, diags::Vector{T}, factors::Vector{F}) where {T<:TaylorSeries,F<:Number} = prod(d * f for (d, f) in zip(diags, factors)) - """ 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} @@ -44,14 +39,14 @@ function taylorexpansion!(graph::G, var_dependence::Dict{Int,Vector{Bool}}=Dict{ if sum(o) == 0 # For a graph the zero order taylor coefficient is just itself. result.coeffs[o] = graph else - coeff = Graph([]; operator=ComputationalGraphs.Sum(), factor=graph.factor, properties=graph.properties, orders=o) + coeff = Graph([]; operator=ComputationalGraphs.Sum(), properties=graph.properties, orders=o) result.coeffs[o] = coeff end end to_coeff_map[graph.id] = result return result, to_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) + to_coeff_map[graph.id] = 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 @@ -80,52 +75,17 @@ function taylorexpansion!(graph::FeynmanGraph{F,W}, var_dependence::Dict{Int,Vec result = TaylorSeries{Graph{F,W}}() for order in collect(Iterators.product(ordtuple...)) #varidx specifies the variables graph depends on. Iterate over all taylor coefficients of those variables. o = collect(order) - coeff = Graph([]; operator=ComputationalGraphs.Sum(), factor=graph.factor, properties=graph.properties, orders=o) + coeff = Graph([]; operator=ComputationalGraphs.Sum(), properties=graph.properties, orders=o) result.coeffs[o] = coeff end to_coeff_map[graph.id] = result return result, to_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) + to_coeff_map[graph.id] = 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::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. -- `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}}(); 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) - var = var_dependence[graph.hash] - else - var = fill(false, get_numvars()) #if dependence not provhashed, assume the graph depends on no variables - end - ordtuple = ((var[idx]) ? (0:get_orders(idx)) : (0:0) for idx in 1:get_numvars()) - result = TaylorSeries{Graph{W,W}}() - for order in collect(Iterators.product(ordtuple...)) #varidx specifies the variables graph depends on. Iterate over all taylor coefficients of those variables. - o = collect(order) - coeff = Graph([]; operator=ComputationalGraphs.Sum(), factor=graph.factor, properties=graph.id, orders=o) - result.coeffs[o] = coeff - end - to_coeff_map[graph.hash] = result - return result, to_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 - end -end - """ 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} @@ -157,22 +117,23 @@ function taylorexpansion!(graph::FeynmanGraph{F,W}, propagator_var::Tuple{Vector end """ - 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. - + function taylorexpansion!(graph::Graph{F,W}, propagator_var::Dict{DataType,Vector{Bool}}; + to_coeff_map::Dict{Int,TaylorSeries{Graph{F,W}}}=Dict{Int,TaylorSeries{Graph{F,W}}}()) where {F,W} + + Return a taylor series of Graph 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. + # Arguments: -- `graph` Target Diagram +- `graph` Target Graph - `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. """ -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::Graph{F,W}, propagator_var::Dict{DataType,Vector{Bool}}; + to_coeff_map::Dict{Int,TaylorSeries{Graph{F,W}}}=Dict{Int,TaylorSeries{Graph{F,W}}}()) where {F,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()] + if haskey(propagator_var, typeof(leaf.properties)) + var_dependence[leaf.id] = [propagator_var[typeof(leaf.properties)][idx] ? true : false for idx in 1:get_numvars()] end end return taylorexpansion!(graph, var_dependence; to_coeff_map=to_coeff_map) @@ -188,17 +149,8 @@ function taylorexpansion!(graphs::Vector{G}, var_dependence::Dict{Int,Vector{Boo return result, to_coeff_map end -function taylorexpansion!(graphs::Vector{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} - result = Vector{TaylorSeries{Graph{W,W}}}() - for graph in graphs - taylor, _ = taylorexpansion!(graph, var_dependence; to_coeff_map=to_coeff_map) - push!(result, taylor) - end - return result, to_coeff_map -end - -function taylorexpansion!(graphs::Vector{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}}}()) where {F,W} +function taylorexpansion!(graphs::Vector{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}}}()) where {F,W} result = Vector{TaylorSeries{Graph{F,W}}}() for graph in graphs taylor, _ = taylorexpansion!(graph, propagator_var; to_coeff_map=to_coeff_map) @@ -207,9 +159,9 @@ function taylorexpansion!(graphs::Vector{FeynmanGraph{F,W}}, propagator_var::Tup return result, to_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} - result = Vector{TaylorSeries{Graph{W,W}}}() +function taylorexpansion!(graphs::Vector{Graph{F,W}}, propagator_var::Dict{DataType,Vector{Bool}}; + to_coeff_map::Dict{Int,TaylorSeries{Graph{F,W}}}=Dict{Int,TaylorSeries{Graph{F,W}}}()) where {F,W} + result = Vector{TaylorSeries{Graph{F,W}}}() for graph in graphs taylor, _ = taylorexpansion!(graph, propagator_var; to_coeff_map=to_coeff_map) push!(result, taylor) @@ -248,10 +200,9 @@ function taylorexpansion_withmap(g::G; coeffmode=true, var::Vector{Bool}=fill(tr if ordernew[idx] <= get_orders(idx) if !haskey(result.coeffs, ordernew) if coeffmode - funcAD = Graph([]; operator=ComputationalGraphs.Sum(), factor=g.factor) + funcAD = Graph([]; operator=ComputationalGraphs.Sum()) else - #funcAD = taylor_factorial(ordernew) * Graph([]; operator=ComputationalGraphs.Sum(), factor=g.factor) - funcAD = Graph([]; operator=ComputationalGraphs.Sum(), factor=taylor_factorial(ordernew) * g.factor) + funcAD = Graph([]; operator=ComputationalGraphs.Sum(), factor=taylor_factorial(ordernew)) end new_func[ordernew] = funcAD result.coeffs[ordernew] = funcAD diff --git a/test/common.jl b/test/common.jl deleted file mode 100644 index c6a84b44..00000000 --- a/test/common.jl +++ /dev/null @@ -1,22 +0,0 @@ -@testset "Parameter" begin - p = DiagParaF64(type=Ver4Diag, innerLoopNum=1) - q = DiagParaF64(type=Ver4Diag, innerLoopNum=2) - a = DiagParaF64(type=Ver4Diag, innerLoopNum=2) - - @test p != q - @test q == a - - aa = reconstruct(a, transferLoop=[0.0, 0.0, 0.0]) - @test a != aa - - # reconstruct with the same type but different interaction - aaa = reconstruct(a, interaction=[]) - @test a != aaa - - # reconstruct with different diagram type leads to different parameter - #reconstructed DiagPara uses the old parameters such as firstLoopIdx, totalLoopNum etc., which are different between types - s = reconstruct(a, type=SigmaDiag) - ss = DiagParaF64(type=SigmaDiag, innerLoopNum=2) - @test s != ss - -end \ No newline at end of file diff --git a/test/computational_graph.jl b/test/computational_graph.jl index f61a5c05..bf1853ac 100644 --- a/test/computational_graph.jl +++ b/test/computational_graph.jl @@ -51,7 +51,6 @@ Graphs.unary_istrivial(::Type{O}) where {O<:Union{O1,O2,O3}} = true Graphs.name(g::ConcreteGraph) = g.name Graphs.orders(g::ConcreteGraph) = g.orders Graphs.operator(g::ConcreteGraph) = g.operator - Graphs.factor(g::ConcreteGraph) = g.factor Graphs.weight(g::ConcreteGraph) = g.weight Graphs.subgraph(g::ConcreteGraph, i=1) = g.subgraphs[i] Graphs.subgraphs(g::ConcreteGraph) = g.subgraphs @@ -78,7 +77,6 @@ Graphs.unary_istrivial(::Type{O}) where {O<:Union{O1,O2,O3}} = true @test Graphs.name(g) == "" @test Graphs.orders(g) == zeros(Int, 0) @test Graphs.operator(g) == O - @test Graphs.factor(g) == 1.0 @test Graphs.weight(g) == 1.0 @test Graphs.subgraph(g) == g1 @test Graphs.subgraph(g, 2) == g2 @@ -133,9 +131,8 @@ end # Test equivalence modulo fields id/factor @test isequiv(g1, g1_new_instance) == false @test isequiv(g1, g1_new_instance, :id) - @test isequiv(g1, g2p, :id) == false - @test isequiv(g1, g2p, :factor) == false - @test isequiv(g1, g2p, :id, :factor) + @test isequiv(g1, eldest(g2p), :id) + @test isequiv(g2, g2p, :id) # Test inequivalence when subgraph lengths are different t = g1 + g1 @test isequiv(t, g1, :id) == false @@ -149,7 +146,6 @@ end end @testset "Addition" begin g3 = g1 + g2 - @test g3.factor == 1 @test g3.subgraphs == [g1] @test g3.subgraph_factors == [3] # @test g3.subgraphs == [g1, g1] @@ -158,7 +154,6 @@ end end @testset "Subtraction" begin g4 = g1 - g2 - @test g4.factor == 1 @test g4.subgraphs == [g1] @test g4.subgraph_factors == [-1] @test g4.subgraphs[1] == g1 @@ -201,15 +196,13 @@ end @testset verbose = true "Transformations" begin @testset "Replace subgraph" begin g1 = Graph([]) - g2 = Graph([]; factor=2) - g3 = Graph([]; factor=3) + g1p = Graph([]; operator=O()) + g2 = Graph([]; factor=2, operator=O()) + g3 = Graph([]; factor=3, operator=O()) gsum = g2 + g3 groot = g1 + gsum - replace_subgraph!(groot, g2, g3) - @test isequiv(gsum.subgraphs[1], gsum.subgraphs[2]) - gnew = replace_subgraph(groot, g2, g3) - @test isequiv(gnew, g1 + Graph([g3, g3], operator=Graphs.Sum()), :id) - # @test isequiv(gnew, g1 + (g3 + g3), :id) # gnew has repeated subgraphs g3! + replace_subgraph!(groot, g1, g1p) + @test isequiv(groot, g1p + Graph([g1p, g1p], subgraph_factors=[2, 3], operator=Graphs.Sum()), :id) end @testset "Prune trivial unary operations" begin g1 = Graph([]) @@ -242,23 +235,32 @@ end g1 = propagator(𝑓⁺(1)𝑓⁻(2)) h1 = FeynmanGraph([g1, g1], drop_topology(g1.properties); subgraph_factors=[1, 2], operator=Graphs.Sum()) h1_lc = linear_combination(g1, g1, 1, 2) - @test h1_lc.subgraph_factors == [3] + @test h1_lc.subgraph_factors == [-3.0] h2 = merge_linear_combination(h1) @test h2.subgraph_factors == [3] @test length(h2.subgraphs) == 1 @test h2.subgraphs[1] == g1 - @test isequiv(h1_lc, h2, :id) + h2_lc = FeynmanGraph([g1,], drop_topology(g1.properties); subgraph_factors=[3], operator=Graphs.Sum()) + @test isequiv(h2_lc, h2, :id) + g2 = propagator(𝑓⁺(1)𝑓⁻(2), factor=2) h3 = linear_combination(g1, g2, 1, 2) + g1s = propagator(𝑓⁺(1)𝑓⁻(2), factor=-1) + @test isequiv(h3, FeynmanGraph([g1s, g1s], drop_topology(g1.properties); subgraph_factors=[-1, -4]), :id) h4 = merge_linear_combination(h3) - @test isequiv(h3, h4, :id) + # @test isequiv(h3, h4, :id) + @test isequiv(h4, FeynmanGraph([g1s], drop_topology(g1.properties); subgraph_factors=[-5]), :id) + h5 = FeynmanGraph([g1, g2, g2, g1], drop_topology(g1.properties); subgraph_factors=[3, 5, 7, 9], operator=Graphs.Sum()) h5_lc = linear_combination([g1, g2, g2, g1], [3, 5, 7, 9]) h6 = merge_linear_combination(h5) @test length(h6.subgraphs) == 2 @test h6.subgraphs == [g1, g2] @test h6.subgraph_factors == [12, 12] - @test isequiv(h5_lc, h6, :id) + # @test isequiv(h5_lc, h6, :id) + @test isequiv(h5_lc, FeynmanGraph([g1s, g1s], drop_topology(g1.properties); subgraph_factors=[-12, -24]), :id) + @test isequiv(h6, FeynmanGraph([g1, g2], drop_topology(g1.properties); subgraph_factors=[12, 12]), :id) + g3 = 2 * g1 # h7 = FeynmanGraph([g1, g3, g3, g1]; subgraph_factors=[3, 5, 7, 9], operator=Graphs.Sum()) h7 = FeynmanGraph([g1, g1, g1, g1], drop_topology(g1.properties); subgraph_factors=[3, 5 * 2, 7 * 2, 9], operator=Graphs.Sum()) @@ -267,7 +269,7 @@ end @test length(h8.subgraphs) == 1 @test h8.subgraphs == [g1] @test h8.subgraph_factors == [36] - @test isequiv(h7_lc, h8, :id) + @test isequiv(h7_lc, FeynmanGraph([g1s,], drop_topology(g1.properties); subgraph_factors=[-36], operator=Graphs.Sum()), :id) end @testset "Merge multi-pproduct" begin g1 = Graph([]) @@ -350,7 +352,7 @@ end rvec = deepcopy([r1, r2, r3]) rvec1 = deepcopy([r1, r2, r3]) Graphs.flatten_all_chains!(r1) - @test isequiv(g1, Graph([l0, l2]; subgraph_factors=[-2, 1]), :id) + @test isequiv(g1, Graph([l0, l0]; subgraph_factors=[-2, 3]), :id) @test isequiv(r1, 210g1, :id) @test isequiv(g2, 2g1, :id) @test isequiv(g3, 6g1, :id) @@ -434,20 +436,21 @@ end g2 = 2 * g1 g3 = Graph([g2,]; subgraph_factors=[3,], operator=Graphs.Prod()) g4 = Graph([g3,]; subgraph_factors=[5,], operator=Graphs.Prod()) - g5 = Graph([], factor=3.0) + g5 = Graph([], factor=3.0, operator=O()) h0 = Graph([g1, g4, g5], subgraph_factors=[2, -1, 1]) h1 = Graph([h0], operator=Graphs.Prod(), subgraph_factors=[2]) h = Graph([h1, g5]) - _h = Graph([Graph([g1, g5], subgraph_factors=[-28, 1]), g5], subgraph_factors=[2, 1]) + + g1p = Graph([], operator=O()) + _h = Graph([Graph([g1, g1p], subgraph_factors=[-28, 3]), g1p], subgraph_factors=[2, 3]) 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]) ≈ Graphs.eval!(h) + @test Graphs.eval!(hvec_op[1], randseed=1) ≈ Graphs.eval!(_h, randseed=1) Graphs.optimize!([h]) @test isequiv(h, _h, :id, :weight) + @test Graphs.eval!(h, randseed=2) ≈ Graphs.eval!(_h, randseed=2) end end end @@ -495,10 +498,9 @@ end @test isequiv(g1, g1_new_instance) == false @test isequiv(g1, g1_from_properties) == false @test isequiv(g1, g2p, :id) == false - @test isequiv(g1, g2p, :factor) == false @test isequiv(g1, g1_new_instance, :id) @test isequiv(g1, g1_from_properties, :id) - @test isequiv(g1, g2p, :id, :factor) + @test isequiv(g1, eldest(g2p), :id) # Test inequivalence when subgraph lengths are different t = g1 + g1 @test isequiv(t, g1, :id) == false @@ -520,7 +522,6 @@ end g3 = g1 + g2 @test vertices(g3) == vertices(g1) @test external_operators(g3) == external_operators(g1) - @test g3.factor == 1 @test g3.subgraphs == [g1] @test g3.subgraph_factors == [3] # @test g3.subgraphs == [g1, g1] @@ -531,7 +532,6 @@ end g4 = g1 - g2 @test vertices(g4) == vertices(g1) @test external_operators(g4) == external_operators(g1) - @test g4.factor == 1 @test g4.subgraphs == [g1,] @test g4.subgraph_factors == [-1,] # @test g4.subgraphs == [g1, g1] @@ -628,47 +628,6 @@ end g5 = FeynmanGraph([g1,], drop_topology(g1.properties); operator=O()) @test Graphs.unary_istrivial(O) == false end - g1 = propagator(𝑓⁻(1)𝑓⁺(2)) - g2 = FeynmanGraph([g1,], g1.properties; subgraph_factors=[5,], operator=Graphs.Prod()) - g3 = FeynmanGraph([g2,], g2.properties; subgraph_factors=[3,], operator=Graphs.Prod()) - # g = 2*(3*(5*g1)) - g = FeynmanGraph([g3,], g3.properties; subgraph_factors=[2,], operator=Graphs.Prod()) - # gp = 2*(3*(g1 + 5*g1)) - # g2p = g1 + g2 - g2p = FeynmanGraph([g1, g2], drop_topology(g1.properties)) - g3p = FeynmanGraph([g2p,], g2p.properties; subgraph_factors=[3,], operator=Graphs.Prod()) - gp = FeynmanGraph([g3p,], g3p.properties; subgraph_factors=[2,], operator=Graphs.Prod()) - @testset "Merge prefactors" begin - g1 = propagator(𝑓⁺(1)𝑓⁻(2)) - h1 = FeynmanGraph([g1, g1], drop_topology(g1.properties), subgraph_factors=[1, 2]) - h1_lc = linear_combination(g1, g1, 1, 2) - @test h1_lc.subgraph_factors == [3] - h2 = merge_linear_combination(h1) - @test h2.subgraph_factors == [3] - @test length(h2.subgraphs) == 1 - @test isequiv(h2.subgraphs[1], g1, :id) - @test isequiv(h1_lc, h2, :id) - g2 = propagator(𝑓⁺(1)𝑓⁻(2), factor=2) - h3 = FeynmanGraph([g1, g2], drop_topology(g1.properties), subgraph_factors=[1, 2]) - h3_lc = linear_combination(g1, g2, 1, 2) - h4 = merge_linear_combination(h3) - @test isequiv(h3, h4, :id) - h5 = FeynmanGraph([g1, g2, g2, g1], drop_topology(g1.properties), subgraph_factors=[3, 5, 7, 9]) - h5_lc = linear_combination([g1, g2, g2, g1], [3, 5, 7, 9]) - h6 = merge_linear_combination(h5) - @test length(h6.subgraphs) == 2 - @test h6.subgraphs == [g1, g2] - @test h6.subgraph_factors == [12, 12] - @test isequiv(h5_lc, h6, :id) - g3 = 2 * g1 - h7 = FeynmanGraph([g1, g1, g1, g1], drop_topology(g1.properties), subgraph_factors=[3, 5 * 2, 7 * 2, 9]) - h7_lc = linear_combination([g1, g3, g3, g1], [3, 5, 7, 9]) - h8 = merge_linear_combination(h7) - @test length(h8.subgraphs) == 1 - @test h8.subgraphs == [g1] - @test h8.subgraph_factors == [36] - @test isequiv(h7_lc, h8, :id) - end end @testset verbose = true "Optimizations" begin @@ -677,20 +636,22 @@ end g2 = 2 * g1 g3 = FeynmanGraph([g2,], g2.properties; subgraph_factors=[3,], operator=Graphs.Prod()) g4 = FeynmanGraph([g3,], g3.properties; subgraph_factors=[5,], operator=Graphs.Prod()) - g5 = propagator(𝑓⁻(1)𝑓⁺(2), factor=3.0) + g5 = propagator(𝑓⁻(1)𝑓⁺(2), factor=3.0, operator=O()) h0 = FeynmanGraph([g1, g4, g5], subgraph_factors=[2, -1, 1]) h1 = FeynmanGraph([h0], operator=Graphs.Prod(), subgraph_factors=[2]) h = FeynmanGraph([h1, g5]) - _h = FeynmanGraph([FeynmanGraph([g1, g5], subgraph_factors=[-28, 1]), g5], subgraph_factors=[2, 1]) + # _h = FeynmanGraph([FeynmanGraph([g1, g5], subgraph_factors=[-28, 1]), g5], subgraph_factors=[2, 1]) + g1p = eldest(g5) + _h = FeynmanGraph([FeynmanGraph([g1, g1p], subgraph_factors=[-28, 3]), g1p], subgraph_factors=[2, 3]) 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]) ≈ Graphs.eval!(h) + @test Graphs.eval!(hvec_op[1], randseed=1) ≈ Graphs.eval!(_h, randseed=1) Graphs.optimize!([h]) @test isequiv(h, _h, :id, :weight) + @test Graphs.eval!(h, randseed=2) ≈ Graphs.eval!(_h, randseed=2) end end @@ -717,7 +678,7 @@ end @testset "Propagator" begin g1 = propagator(𝑓⁺(1)𝑓⁻(2)) - @test g1.factor == -1 + @test g1.subgraph_factors == [-1] @test external_indices(g1) == [2, 1] @test vertices(g1) == [𝑓⁺(1), 𝑓⁻(2)] @test external_operators(g1) == 𝑓⁻(2)𝑓⁺(1) @@ -727,14 +688,14 @@ end @testset "Interaction" begin ops = 𝑓⁺(1)𝑓⁻(2)𝑓⁻(3)𝑓⁺(4)𝜙(5) g1 = interaction(ops) - @test g1.factor == 1 + @test isempty(g1.subgraph_factors) @test external_indices(g1) == [1, 2, 3, 4, 5] @test vertices(g1) == [ops] @test external_operators(g1) == ops @test external_labels(g1) == [1, 2, 3, 4, 5] g2 = interaction(ops, reorder=normal_order) - @test g2.factor == -1 + @test g2.subgraph_factors == [-1] @test vertices(g2) == [ops] @test external_operators(g2) == 𝑓⁺(1)𝑓⁺(4)𝜙(5)𝑓⁻(3)𝑓⁻(2) @test external_labels(g2) == [1, 4, 5, 3, 2] @@ -764,51 +725,50 @@ end g3 = feynman_diagram(interaction.(V3), [[1, 5], [2, 4], [3, 6]]) #vacuum diagram @test vertices(g3) == V3 @test isempty(external_operators(g3)) - @test g3.factor == 1 @test g3.subgraph_factors == ones(Int, 5) - @test g3.subgraphs[3].factor == -1 + @test g3.subgraphs[3].subgraph_factors == [-1] @test vertices(g3.subgraphs[3]) == [𝑓⁺(1), 𝑓⁻(5)] @test external_operators(g3.subgraphs[3]) == 𝑓⁻(5)𝑓⁺(1) V4 = [𝑓⁺(1)𝑓⁻(2), 𝑓⁺(3)𝑓⁻(4)𝜙(5), 𝑓⁺(6)𝑓⁻(7)𝜙(8), 𝑓⁺(9)𝑓⁻(10)] g4 = feynman_diagram([external_vertex(V4[1]), interaction.(V4[2:3])..., external_vertex(V4[4])], [[1, 4], [2, 6], [3, 10], [5, 8], [7, 9]]) # polarization diagram - @test g4.factor == -1 - @test g4.subgraph_factors == ones(Int, 9) + @test g4.subgraph_factors == [-1] + @test eldest(g4).subgraph_factors == ones(Int, 9) @test vertices(g4) == V4 @test external_operators(g4) == 𝑓⁺(1)𝑓⁻(2)𝑓⁺(9)𝑓⁻(10) V5 = [𝑓⁺(1)𝑓⁻(2)𝜙(3), 𝑓⁺(4)𝑓⁻(5)𝜙(6), 𝑓⁺(7)𝑓⁻(8)𝜙(9)] g5 = feynman_diagram(interaction.(V5), [[1, 5], [3, 9], [4, 8]]) # vertex function - @test g5.factor == -1 - @test g5.subgraph_factors == ones(Int, 6) + @test g5.subgraph_factors == [-1] + @test eldest(g5).subgraph_factors == ones(Int, 6) @test vertices(g5) == V5 @test external_operators(g5) == 𝑓⁻(2)𝜙(6)𝑓⁺(7) g5p = feynman_diagram(interaction.(V5), [[1, 5], [3, 9], [4, 8]], [3, 1, 2]) - @test g5.factor ≈ -g5p.factor # reorder of external fake legs will not change the sign. @test g5p.subgraph_factors == ones(Int, 6) @test external_operators(g5p) == 𝑓⁺(7)𝑓⁻(2)𝜙(6) V6 = [𝑓⁻(8), 𝑓⁺(1), 𝑓⁺(2)𝑓⁻(3)𝜙(4), 𝑓⁺(5)𝑓⁻(6)𝜙(7)] g6 = feynman_diagram([external_vertex.(V6[1:2]); interaction.(V6[3:4])], [[2, 4], [3, 7], [5, 8], [6, 1]]) # fermionic Green2 - @test g6.factor == -1 - @test g6.subgraph_factors == ones(Int, 8) + @test g6.subgraph_factors == [-1] + @test eldest(g6).subgraph_factors == ones(Int, 8) @test external_operators(g6) == 𝑓⁻(8)𝑓⁺(1) V7 = [𝑓⁻(7), 𝑓⁺(1)𝑓⁻(2)𝜙(3), 𝑓⁺(4)𝑓⁻(5)𝜙(6)] g7 = feynman_diagram([external_vertex(V7[1]), interaction.(V7[2:3])...], [[2, 6], [4, 7], [5, 1]]) # sigma*G - @test g7.factor == 1 + @test g7.subgraph_factors == ones(Int, 6) @test external_operators(g7) == 𝑓⁻(7)𝑓⁻(2) V8 = [𝑓⁺(2), 𝑓⁻(12), 𝑓⁺(3)𝑓⁻(4)𝜙(5), 𝑓⁺(6)𝑓⁻(7)𝜙(8), 𝑓⁺(9)𝑓⁻(10)𝜙(11), 𝑓⁺(13)𝑓⁻(14)𝜙(15)] g8 = feynman_diagram([external_vertex.(V8[1:2]); interaction.(V8[3:end])], [[1, 4], [3, 7], [5, 14], [6, 13], [8, 11], [9, 2]]) - @test g8.factor == -1 + @test g8.subgraph_factors == [-1] + @test eldest(g8).subgraph_factors == ones(Int, 12) @test vertices(g8) == V8 @test external_operators(g8) == 𝑓⁺(2)𝑓⁻(12)𝑓⁻(10)𝑓⁺(13) g8p = feynman_diagram([external_vertex.(V8[1:2]); interaction.(V8[3:end])], [[1, 4], [3, 7], [5, 14], [6, 13], [8, 11], [9, 2]], [2, 1]) - @test g8p.factor == 1 + @test g8p.subgraph_factors == ones(Int, 12) @test external_operators(g8p) == 𝑓⁺(2)𝑓⁻(12)𝑓⁺(13)𝑓⁻(10) end @testset "f+f+f-f- interaction" begin @@ -816,14 +776,15 @@ end g1 = feynman_diagram([external_vertex.(V1[1:2]); interaction.(V1[3:4])], [[1, 6], [2, 9], [4, 10], [5, 7]]) g1p = feynman_diagram([external_vertex.(V1[2:-1:1]); interaction.(V1[3:4])], [[2, 6], [1, 9], [4, 10], [5, 7]], [2, 1]) - @test g1p.factor ≈ g1.factor + @test g1p.subgraph_factors ≈ g1.subgraph_factors @test external_operators(g1) == 𝑓⁺(3)𝑓⁺(4)𝑓⁺(5)𝑓⁺(10) @test vertices(g1p) == [𝑓⁺(4), 𝑓⁺(3), 𝑓⁺(5)𝑓⁺(6)𝑓⁻(7)𝑓⁻(8), 𝑓⁺(9)𝑓⁺(10)𝑓⁻(11)𝑓⁻(12)] @test external_operators(g1p) == 𝑓⁺(4)𝑓⁺(3)𝑓⁺(10)𝑓⁺(5) V2 = [𝑓⁺(2), 𝑓⁻(3), 𝑓⁺(4)𝑓⁺(5)𝑓⁻(6)𝑓⁻(7), 𝑓⁺(8)𝑓⁺(9)𝑓⁻(10)𝑓⁻(11)] g2 = feynman_diagram([external_vertex.(V2[1:2]); interaction.(V2[3:4])], [[1, 6], [2, 3], [4, 10], [5, 8]]) - @test g2.factor == -1 + @test g2.subgraph_factors == [-1] + @test eldest(g2).subgraph_factors == ones(Int, 8) @test external_operators(g2) == 𝑓⁺(2)𝑓⁻(3)𝑓⁺(8)𝑓⁻(10) @test external_labels(g2) == [2, 3, 8, 10] # labels of external vertices end @@ -843,22 +804,21 @@ end end @testset verbose = true "Conversions" begin - g = Graph([]; factor=-1.0, operator=Graphs.Sum()) - g1 = Graph([]; operator=O1()) - g2 = Graph([]; operator=O2()) + g = Graph([]; operator=Graphs.Sum()) + g1 = Graph([]; factor=-1.0) g_feyn = propagator(𝑓⁺(1)𝑓⁻(2)) # equivalent to g after conversion # Test constructor for FeynmanGraph from Graph and FeynmanProperties - g_feyn_conv = FeynmanGraph(g, g_feyn.properties) + g_feyn_conv = FeynmanGraph(g, g_feyn.properties) * (-1) @test isequiv(g_feyn, g_feyn_conv, :id) # Test implicit and explicit FeynmanGraph -> Graph conversion g_conv_implicit_v1::Graph = g_feyn g_conv_implicit_v2::Graph{Float64,Float64} = g_feyn g_conv_explicit_v1 = convert(Graph, g_feyn) g_conv_explicit_v2 = convert(Graph{Float64,Float64}, g_feyn) - @test isequiv(g, g_conv_implicit_v1, :id) - @test isequiv(g, g_conv_implicit_v2, :id) - @test isequiv(g, g_conv_explicit_v1, :id) - @test isequiv(g, g_conv_explicit_v2, :id) + @test isequiv(g1, g_conv_implicit_v1, :id) + @test isequiv(g1, g_conv_implicit_v2, :id) + @test isequiv(g1, g_conv_explicit_v1, :id) + @test isequiv(g1, g_conv_explicit_v2, :id) end @testset verbose = true "Evaluation" begin @@ -903,21 +863,13 @@ end end @testset "Eval" begin # Current test assign all green's function equal to 1 for simplicity. - # print(eval!(forwardAD(G5, g1.id)),"\n") - # print(eval!(forwardAD(G3, g1.id)),"\n") - # print(eval!(forwardAD(G3, g2.id)),"\n") - # print(eval!(forwardAD(G6, g1.id)),"\n") - # print(eval!(forwardAD(forwardAD(G6, g1.id), g2.id)),"\n") - # print(eval!(forwardAD(forwardAD(G6, g1.id), g3.id)),"\n") - # gs = Compilers.to_julia_str([forwardAD(G5, g1.id),], name="eval_graph!") - # println(gs,"\n") @test eval!(forwardAD(G3, g1.id)) == 1 @test eval!(forwardAD(G4, g1.id)) == 8 @test eval!(forwardAD(G5, g1.id)) == 104 @test eval!(forwardAD(G6, g1.id)) == 62 - @test eval!(forwardAD(G6, g3.id)) == 5 + @test eval!(forwardAD(G6, g2.id)) == 18 @test eval!(forwardAD(forwardAD(G6, g1.id), g2.id)) == 30 - #backAD(G5, true) + @test eval!(forwardAD(G6, g3.id)) == 0 for (i, G) in enumerate([G3, G4, G5, G6, G7]) back_deriv = backAD(G) for (id_pair, value_back) in back_deriv @@ -928,31 +880,14 @@ end # print("value:$(i+2) $(eval!(value_forward))\n") end end - # gs = Compilers.to_julia_str([G6,], name="eval_graph!") - # println("G6 ", gs, "\n") - # for (id, G) in backAD(G6) - # gs = Compilers.to_julia_str([G,], name="eval_graph!") - # println("first order derive id:$(id)", gs, "\n") - # back_deriv = backAD(G) - # for (id_pair, value_back) in back_deriv - # gs = Compilers.to_julia_str([value_back,], name="eval_graph!") - # println("second order derive id:$(id_pair)", gs, "\n") - # value_forward = forwardAD(G, id_pair[2]) - # @test eval!(value_back) == eval!(value_forward) - # print("value:$(id_pair) $(eval!(value_forward))\n") - # end - # end - - # for (order_vec, graph) in build_all_leaf_derivative(G6, 3) - # print("$(order_vec), $(eval!(graph)) \n") - # end end @testset "forwardAD_root!" begin F3 = g1 + g2 F2 = linear_combination([g1, g3, F3], [2, 1, 3]) F1 = Graph([g1, F2, F3], operator=Graphs.Prod(), subgraph_factors=[3.0, 1.0, 1.0]) - kg1, kg2, kg3 = (g1.id, (1,)), (g2.id, (1,)), (g3.id, (1,)) + kg1, kg2 = (g1.id, (1,)), (g2.id, (1,)) + kg3 = (eldest(g3).id, (1,)) kF1, kF2, kF3 = (F1.id, (1,)), (F2.id, (1,)), (F3.id, (1,)) dual = forwardAD_root!(F1) # auto-differentation! @@ -960,7 +895,8 @@ end @test dual[kF2].subgraphs == [dual[kg1], dual[kg3], dual[kF3]] leafmap = Dict{Int,Int}() - leafmap[g1.id], leafmap[g2.id], leafmap[g3.id] = 1, 2, 3 + leafmap[g1.id], leafmap[g2.id] = 1, 2 + leafmap[eldest(g3).id] = 3 leafmap[dual[kg1].id] = 4 leafmap[dual[kg2].id] = 5 leafmap[dual[kg3].id] = 6 @@ -974,9 +910,9 @@ end @test eval!(dual[kF2], leafmap, leaf) == 3.0 @test eval!(dual[kF3], leafmap, leaf) == 1.0 - leaf = [5.0, -1.0, 2.0, 0.0, 0.0, 1.0] # d F1 / d g3 - @test eval!(dual[kF1], leafmap, leaf) == 60.0 - @test eval!(dual[kF2], leafmap, leaf) == 1.0 + leaf = [5.0, -1.0, 2.0, 0.0, 0.0, 1.0] # d F1 / d eldest(g3) + @test eval!(dual[kF1], leafmap, leaf) == 120.0 + @test eval!(dual[kF2], leafmap, leaf) == 2.0 @test eval!(dual[kF3], leafmap, leaf) == 0.0 F0 = F1 * F3 @@ -986,13 +922,13 @@ end leafmap[dual1[kg2].id] = 5 leafmap[dual1[kg3].id] = 6 - leaf = [1.0, 1.0, 1.0, 1.0, 0.0, 0.0] + leaf = [1.0, 1.0, 1.0, 1.0, 0.0, 0.0] # d F1 / d g1 @test eval!(dual1[kF0], leafmap, leaf) == 300.0 - leaf = [5.0, -1.0, 2.0, 0.0, 1.0, 0.0] + leaf = [5.0, -1.0, 2.0, 0.0, 1.0, 0.0] # d F1 / d g2 @test eval!(dual1[kF0], leafmap, leaf) == 3840.0 - leaf = [5.0, -1.0, 2.0, 0.0, 0.0, 1.0] - @test eval!(dual1[kF0], leafmap, leaf) == 240.0 - @test isequiv(dual[kF1], dual1[kF1], :id, :weight, :vertices) + leaf = [5.0, -1.0, 2.0, 0.0, 0.0, 1.0] # d F1 / d eldest(g3) + @test eval!(dual1[kF0], leafmap, leaf) == 480.0 + @test isequiv(dual[kF1], dual1[kF1], :id) F0_r1 = F1 + F3 kF0_r1 = (F0_r1.id, (1,)) @@ -1000,10 +936,10 @@ end leafmap[dual[kg1].id] = 4 leafmap[dual[kg2].id] = 5 leafmap[dual[kg3].id] = 6 - @test eval!(dual[kF0], leafmap, leaf) == 240.0 - @test eval!(dual[kF0_r1], leafmap, leaf) == 60.0 - @test isequiv(dual[kF0], dual1[kF0], :id, :weight) - @test isequiv(dual[kF1], dual1[kF1], :id, :weight) + @test eval!(dual[kF0], leafmap, leaf) == 480.0 + @test eval!(dual[kF0_r1], leafmap, leaf) == 120.0 + @test isequiv(dual[kF0], dual1[kF0], :id) + @test isequiv(dual[kF1], dual1[kF1], :id) end @testset "build_derivative_graph" begin F3 = g1 + g2 @@ -1011,16 +947,17 @@ end F1 = Graph([g1, F2, F3], operator=Graphs.Prod(), subgraph_factors=[3.0, 1.0, 1.0]) leafmap = Dict{Int,Int}() - leafmap[g1.id], leafmap[g2.id], leafmap[g3.id] = 1, 2, 3 + leafmap[g1.id], leafmap[g2.id] = 1, 2 + leafmap[eldest(g3).id] = 3 orders = (3, 2, 2) dual = Graphs.build_derivative_graph(F1, orders) - leafmap[dual[(g1.id, (1, 0, 0))].id], leafmap[dual[(g2.id, (0, 1, 0))].id], leafmap[dual[(g3.id, (0, 0, 1))].id] = 4, 5, 6 + leafmap[dual[(g1.id, (1, 0, 0))].id], leafmap[dual[(g2.id, (0, 1, 0))].id], leafmap[dual[(eldest(g3).id, (0, 0, 1))].id] = 4, 5, 6 burnleafs_id = Int[] for order in Iterators.product((0:x for x in orders)...) order == (0, 0, 0) && continue - for g in [g1, g2, g3] + for g in [g1, g2, eldest(g3)] if !haskey(leafmap, dual[(g.id, order)].id) leafmap[dual[(g.id, order)].id] = 7 push!(burnleafs_id, dual[(g.id, order)].id) @@ -1049,12 +986,12 @@ end dual = Graphs.build_derivative_graph([F0, F0_r1], orders) leafmap = Dict{Int,Int}() - leafmap[g1.id], leafmap[g2.id], leafmap[g3.id] = 1, 2, 3 - leafmap[dual[(g1.id, (1, 0, 0))].id], leafmap[dual[(g2.id, (0, 1, 0))].id], leafmap[dual[(g3.id, (0, 0, 1))].id] = 4, 5, 6 + leafmap[g1.id], leafmap[g2.id], leafmap[eldest(g3).id] = 1, 2, 3 + leafmap[dual[(g1.id, (1, 0, 0))].id], leafmap[dual[(g2.id, (0, 1, 0))].id], leafmap[dual[(eldest(g3).id, (0, 0, 1))].id] = 4, 5, 6 burnleafs_id = Int[] for order in Iterators.product((0:x for x in orders)...) order == (0, 0, 0) && continue - for g in [g1, g2, g3] + for g in [g1, g2, eldest(g3)] if !haskey(leafmap, dual[(g.id, order)].id) leafmap[dual[(g.id, order)].id] = 7 push!(burnleafs_id, dual[(g.id, order)].id) @@ -1090,7 +1027,7 @@ end @testset verbose = true "Tree properties" begin using FeynmanDiagram.ComputationalGraphs: - haschildren, onechild, isleaf, isbranch, ischain, isfactorless, eldest, count_operation + haschildren, onechild, isleaf, isbranch, ischain, eldest, count_operation # Leaves: gᵢ g1 = Graph([]) g2 = Graph([], factor=2) @@ -1116,8 +1053,8 @@ end @test isleaf(g1) @test isbranch(g1) == false @test ischain(g1) - @test isfactorless(g1) - @test isfactorless(g2) == false + # @test isfactorless(g1) + # @test isfactorless(g2) == false @test_throws AssertionError eldest(g1) @test count_operation(g1) == [0, 0] @test count_operation(g2) == [0, 0] @@ -1128,9 +1065,9 @@ end @test isleaf(g3) == false @test isbranch(g3) @test ischain(g3) - @test isfactorless(g3) - @test isfactorless(g4) - @test isfactorless(g5) == false + # @test isfactorless(g3) + # @test isfactorless(g4) + # @test isfactorless(g5) == false @test isleaf(eldest(g3)) @test has_zero_subfactors(h1) end @@ -1140,8 +1077,8 @@ end @test isleaf(g6) == false @test isbranch(g6) == false @test ischain(g6) - @test isfactorless(g6) - @test isfactorless(g7) == false + # @test isfactorless(g6) + # @test isfactorless(g7) == false @test isbranch(eldest(g6)) end @testset "General" begin @@ -1150,7 +1087,7 @@ end @test isleaf(g8) == false @test isbranch(g8) == false @test ischain(g8) == false - @test isfactorless(g8) == false + # @test isfactorless(g8) == false @test onechild(eldest(g8)) == false @test count_operation(g8) == [1, 0] @test count_operation(g9) == [2, 0] diff --git a/test/diagram_tree.jl b/test/diagram_tree.jl deleted file mode 100644 index f55982de..00000000 --- a/test/diagram_tree.jl +++ /dev/null @@ -1,246 +0,0 @@ -@testset "Diagram" begin - # Diagram = DiagTreeNew.Diagram - # DiagramId = DiagTreeNew.DiagramId - # add_subdiagram! = DiagTreeNew.add_subdiagram! - - struct ID <: DiagramId - uid::Int - end - Base.show(io::IO, d::ID) = print(io, d.uid) - # Base.isequal(a::ID, b::ID) = (a.index == b.index) - # Base.Dict(d::ID) = Dict(:id => d.index) - - DiagTree.uidreset() - - W = Int - ll = Diagram{W}(ID(3)) - l = Diagram{W}(ID(1), Sum(), [ll,]) - r = Diagram{W}(ID(2)) - root = Diagram{W}(ID(0), Sum(), [l, r]) - print_tree(root) - """ - 4 : 0=0=⨁ (2, 3) - ├─ 2 : 1=0=⨁ (1) - │ └─ 1 : 3=0 - └─ 3 : 2=0 - """ - - collect(PostOrderDFS(root)) - @test [node.id.uid for node in PostOrderDFS(root)] == [3, 1, 2, 0] - @test [node.id.uid for node in PreOrderDFS(root)] == [0, 1, 3, 2] - @test [node.id.uid for node in Leaves(root)] == [3, 2] - - # eval(d::ID, vargs...) = d.uid - @test DiagTree.eval!(root; eval=(d -> d.uid)) == sum(node.id.uid for node in Leaves(root)) - - print_tree(root) - # DiagTreeNew.plot_tree(root) - - println(toDataFrame([root,])) -end - -function getdiagram(spin=2.0, D=3, Nk=4, Nt=2) - """ - k1-k3 k2+k3 - | | - t1.L ↑ t1.L t2.L ↑ t2.L - |-------------->----------| - | | k3+k4 | | - | v | | v | - | | k4 | | - |--------------<----------| - t1.L ↑ t1.L t2.L ↑ t2.L - | | - k1 k2 - """ - - DiagTree.uidreset() - # We only consider the direct part of the above diagram - - paraG = DiagParaF64(type=GreenDiag, - innerLoopNum=0, totalLoopNum=Nk, - hasTau=true, totalTauNum=Nt) - paraV = paraG - - # #construct the propagator table - gK = [[0.0, 0.0, 1.0, 1.0], [0.0, 0.0, 0.0, 1.0]] - gT = [(1, 2), (2, 1)] - g = [Diagram{Float64}(BareGreenId(paraG, k=gK[i], t=gT[i]), name=:G) for i in 1:2] - - vdK = [[0.0, 0.0, 1.0, 0.0], [0.0, 0.0, 1.0, 0.0]] - # vdT = [[1, 1], [2, 2]] - vd = [Diagram{Float64}(BareInteractionId(paraV, ChargeCharge, k=vdK[i], permu=Di), name=:Vd) for i in 1:2] - - veK = [[1, 0, -1, -1], [0, 1, 0, -1]] - # veT = [[1, 1], [2, 2]] - ve = [Diagram{Float64}(BareInteractionId(paraV, ChargeCharge, k=veK[i], permu=Ex), name=:Ve) for i in 1:2] - - Id = GenericId(paraV) - # contruct the tree - ggn = Diagram{Float64}(Id, Prod(), [g[1], g[2]]) - vdd = Diagram{Float64}(Id, Prod(), [vd[1], vd[2]], factor=spin) - vde = Diagram{Float64}(Id, Prod(), [vd[1], ve[2]], factor=-1.0) - ved = Diagram{Float64}(Id, Prod(), [ve[1], vd[2]], factor=-1.0) - vsum = Diagram{Float64}(Id, Sum(), [vdd, vde, ved]) - root = Diagram{Float64}(Id, Prod(), [vsum, ggn], factor=1 / (2π)^D, name=:root) - - return root, gK, gT, vdK, veK -end - -@testset "Generic Diagrams" begin - - DiagTree.uidreset() - # We only consider the direct part of the above diagram - spin = 1.0 - D = 3 - kF, β, mass2 = 1.919, 0.5, 1.0 - Nk, Nt = 4, 2 - - root, gK, gT, vdK, veK = getdiagram(spin, D, Nk, Nt) - - #optimize the diagram - DiagTree.optimize!([root,]) - - # autodiff - droot_dg = DiagTree.derivative([root,], BareGreenId)[1] - droot_dv = DiagTree.derivative([root,], BareInteractionId)[1] - # plot_tree(droot_dg) - - DiagTree.eval!(root; eval=(x -> 1.0)) - factor = 1 / (2π)^D - @test root.weight ≈ (-2 + spin) * factor - - DiagTree.eval!(droot_dg; eval=(x -> 1.0)) - @test droot_dg.weight ≈ (-2 + spin) * 2 * factor - - DiagTree.eval!(droot_dv; eval=(x -> 1.0)) - @test droot_dv.weight ≈ (-2 + spin) * 2 * factor - - # #more sophisticated test of the weight evaluation - varK = rand(D, Nk) - varT = [rand() * β for t in 1:Nt] - - function evalG(K, τBasis, varT, order=0) - ϵ = dot(K, K) / 2 - kF^2 - τ = varT[τBasis[2]] - varT[τBasis[1]] - if order == 0 - return Spectral.kernelFermiT(τ, ϵ, β) - elseif order == 1 - return Spectral.kernelFermiT(τ, ϵ, β) * 3.1415 - else - error("not implemented!") - end - end - - function evalV(K, order=0) - if order == 0 - return 8π / (dot(K, K) + mass2) - elseif order == 1 - return 8π / (dot(K, K) + mass2) * 3.1415 - else - error("not implemented!") - end - end - - # # getK(basis, varK) = sum([basis[i] * K for (i, K) in enumerate(varK)]) - getK(basis, varK) = varK * basis - - eval(id::BareGreenId, varK, varT) = evalG(getK(id.extK, varK), id.extT, varT, id.order[1]) - eval(id::BareInteractionId, varK, varT) = evalV(getK(id.extK, varK), id.order[2]) - - gw = [evalG(getK(gK[i], varK), gT[i], varT) for i = 1:2] - vdw = [evalV(getK(vdK[i], varK)) for i = 1:2] - vew = [evalV(getK(veK[i], varK)) for i = 1:2] - - dgw = [evalG(getK(gK[i], varK), gT[i], varT, 1) for i = 1:2] - dvdw = [evalV(getK(vdK[i], varK), 1) for i = 1:2] - dvew = [evalV(getK(veK[i], varK), 1) for i = 1:2] - - Vweight = spin * vdw[1] * vdw[2] - vdw[1] * vew[2] - vew[1] * vdw[2] - Gweight = gw[1] * gw[2] - Weight = Gweight * Vweight / (2π)^D - - dVweight = spin * (dvdw[1] * vdw[2] + vdw[1] * dvdw[2]) - - (dvdw[1] * vew[2] + vdw[1] * dvew[2]) - - (dvew[1] * vdw[2] + vew[1] * dvdw[2]) - - dGweight = dgw[1] * gw[2] + gw[1] * dgw[2] - dWeight_dg = dGweight * Vweight / (2π)^D - dWeight_dv = Gweight * dVweight / (2π)^D - - # print_tree(root) - DiagTree.eval!(root, varK, varT; eval=eval) - @test root.weight ≈ Weight - - DiagTree.eval!(droot_dg, varK, varT; eval=eval) - @test droot_dg.weight ≈ dWeight_dg - - DiagTree.eval!(droot_dv, varK, varT; eval=eval) - @test droot_dv.weight ≈ dWeight_dv - - ############### test diagram optimization ################# - uniqueG, uniqueInt = DiagTree.removeDuplicatedLeaves!([root,], verbose=1) - @test length(uniqueG) == 2 - @test length(uniqueInt) == 3 - DiagTree.eval!(root, varK, varT; eval=eval) - @test root.weight ≈ Weight -end - -@testset "dataframe" begin - DiagTree.uidreset() - # We only consider the direct part of the above diagram - spin = 2.0 - D = 3 - kF, β, mass2 = 1.919, 0.5, 1.0 - Nk, Nt = 4, 2 - - root, gK, gT, vdK, veK = getdiagram(spin, D, Nk, Nt) - diags = root.subdiagram - diags = collect(Leaves(root)) - df1 = DiagTree.toDataFrame(diags) - df2 = DiagTree.toDataFrame(diags, :extT) - s1 = size(df1) - s2 = size(df2) - @assert s1[1] == s2[1] - @assert s1[2] == s2[2] - 1 - - d = mergeby(diags) #should return a vector of a single diagram - @assert length(d) == 1 -end - -@testset "optimize" begin - DiagTree.uidreset() - - W = Int - lll = Diagram{W}(ID(5)) - ll = Diagram{W}(ID(3), Prod(), [lll,]) - l = Diagram{W}(ID(1), Sum(), [ll,]) - r = Diagram{W}(ID(2)) - root = Diagram{W}(ID(0), Sum(), [l, r]) - # print_tree(root) - """ - 5 : 0=0=⨁ (3, 4) - ├─ 3 : 1=0=⨁ (2) - │ └─ 2 : 3=0=Ⓧ (1) - │ └─ 1 : 5=0 - └─ 4 : 2=0 - """ - - #remove the 2, which only has one child - DiagTree.removeOneChildParent!([root,]) - """ - 4 : 0=0=⨁ (1, 3) - ├─ 1 : 3=0 - └─ 3 : 2=0 - """ - - # print_tree(root) - - @test root.subdiagram[1].hash == 1 - # print_tree(root) - - # root, gK, gT, vdK, veK = getdiagram() - # uniqueG, uniqueInt = DiagTree.removeDuplicatedLeaves!(root, verbose = 1) - # @test length(uniqueG) == 2 - # @test length(uniqueInt) == 3 -end \ No newline at end of file diff --git a/test/expression_tree.jl b/test/expression_tree.jl deleted file mode 100644 index 2d2b3271..00000000 --- a/test/expression_tree.jl +++ /dev/null @@ -1,150 +0,0 @@ -@testset "LoopPool" begin - dim, N = 3, 4 - loopPool = ExprTree.LoopPool(:K, dim, N, Float64) - basis1 = [1.0, 0.0, 0.0, 1.0] - basis2 = [1.0, 1.0, 0.0, 0.0] - basis3 = [1.0, 0.0, -1.0, 1.0] - idx1 = ExprTree.append(loopPool, basis1) - idx2 = ExprTree.append(loopPool, basis2) - idx3 = ExprTree.append(loopPool, basis2) - idx4 = ExprTree.append(loopPool, basis1) - idx5 = ExprTree.append(loopPool, basis3) - @test length(loopPool) == 3 - @test idx1 == idx4 - @test idx2 == idx3 - - varK = rand(dim, N) - ExprTree.update(loopPool, varK) - @test ExprTree.current(loopPool, 1) ≈ varK * basis1 - @test ExprTree.current(loopPool, 2) ≈ varK * basis2 - @test ExprTree.current(loopPool, 3) ≈ varK * basis3 - -end - -# @testset "CachedPool" begin -# objType, weightType = Int, Float64 -# pool = ExprTree.CachedPool(:P, objType, weightType) -# idx1 = ExprTree.append(pool, 1) -# idx2 = ExprTree.append(pool, 2) -# idx3 = ExprTree.append(pool, 2) -# idx4 = ExprTree.append(pool, 1) -# @test length(pool) == 2 -# @test idx1 == idx4 -# @test idx2 == idx3 -# end - -@testset "Generic Diagrams" begin - - """ - k1-k3 k2+k3 - | | - t1.L ↑ t1.L t2.L ↑ t2.L - |-------------->----------| - | | k3+k4 | | - | v | | v | - | | k4 | | - |--------------<----------| - t1.L ↑ t1.L t2.L ↑ t2.L - | | - k1 k2 - """ - # We only consider the direct part of the above diagram - Gtype, Wtype = 1, 2 - spin = 2.0 - D = 3 - kF, β, mass2 = 1.919, 0.5, 1.0 - - # varK = [rand(D) for i = 1:4] #k1, k2, k3, k4 - - varK = rand(D, 4) - varT = [rand() * β, rand() * β] - - K0 = [0.0, 0.0, 0.0] - T0 = 0.0 - - calcK(para, basis) = sum([para[i] .* basis[i] for i = 1:length(para)]) - calcT(para, basis) = para[basis[2]] - para[basis[1]] - - gorder, vorder = 0, 1 - - weightType = Float64 - - # function LoopPool(name::Symbol, dim::Int, N::Int, type::DataType) - MomPool = ExprTree.LoopPool(:K, D, 4) - - diag = ExprTree.ExpressionTree(loopBasis=MomPool, nodePara=Int, weight=weightType) - - # #construct the propagator table - gK = [[0.0, 0.0, 1.0, 1.0], [0.0, 0.0, 0.0, 1.0]] - gT = [(1, 2), (2, 1)] - g = [ExprTree.addpropagator!(diag, :G; site=gT[i], loop=gK[i], para=1) for i = 1:2] - - vdK = [[0.0, 0.0, 1.0, 0.0], [0.0, 0.0, 1.0, 0.0]] - vdT = [[1, 1], [2, 2]] - vd = [ExprTree.addpropagator!(diag, :Vd; loop=vdK[i], para=2) for i = 1:2] - - veK = [[1, 0, -1, -1], [0, 1, 0, -1]] - veT = [[1, 1], [2, 2]] - ve = [ExprTree.addpropagator!(diag, :Ve; loop=veK[i], para=2) for i = 1:2] - # ve = [ExprTree.addPropagator!(diag, Wtype, 1, veK[i], veT[i], Wsym)[1] for i = 1:2] - # # W order is 1 - - # # contruct the tree - MUL, ADD = ExprTree.MUL, ExprTree.ADD - ggn = ExprTree.addnode!(diag, MUL, :gxg, [g[1], g[2]], 1.0, para=0) - vdd = ExprTree.addnode!(diag, MUL, :dxd, [vd[1], vd[2]], spin, para=0) - vde = ExprTree.addnode!(diag, MUL, :dxe, [vd[1], ve[2]], -1.0, para=0) - ved = ExprTree.addnode!(diag, MUL, :exd, [ve[1], vd[2]], -1.0, para=0) - vsum = ExprTree.addnode!(diag, ADD, :sum, [vdd, vde, ved], 1.0, para=0) - root = ExprTree.addnode!(diag, MUL, :root, [ggn, vsum], 1.0, para=0) - push!(diag.root, root) - ExprTree.initialize!(diag.node) - - # printBasisPool(diag) - # printPropagator(diag) - # ExprTree.printNodes(diag) - # ExprTree.showTree(diag, diag.root[1]) - - # #make sure the total number of diagrams are correct - let - DiagTree.eval(para, K, Tbasis, varT) = 1.0 - ExprTree.evalKT!(diag, varK, varT) - @test diag[1] ≈ -2 + 1 * spin - end - - # #more sophisticated test of the weight evaluation - let - function evalG(K, τBasis, varT) - ϵ = dot(K, K) / 2 - kF^2 - τ = varT[τBasis[2]] - varT[τBasis[1]] - return Spectral.kernelFermiT(τ, ϵ, β) - end - - evalV(K) = 8π / (dot(K, K) + mass2) - - function DiagTree.eval(para, K, Tbasis, varT) - if para[1] == 1 - return evalG(K, Tbasis, varT) - elseif para[1] == 2 - return evalV(K) - else - error("not implemented") - end - end - - # getK(basis, varK) = sum([basis[i] * K for (i, K) in enumerate(varK)]) - getK(basis, varK) = varK * basis - - gw = [evalG(getK(gK[i], varK), gT[i], varT) for i = 1:2] - vdw = [evalV(getK(vdK[i], varK)) for i = 1:2] - vew = [evalV(getK(veK[i], varK)) for i = 1:2] - - Vweight = spin * vdw[1] * vdw[2] - vdw[1] * vew[2] - vew[1] * vdw[2] - Weight = gw[1] * gw[2] * Vweight - - # println(ExprTree.printPropagator(diag)) - ExprTree.evalKT!(diag, varK, varT) - @test diag[1] ≈ Weight - end - -end \ No newline at end of file diff --git a/test/front_end.jl b/test/front_end.jl index f05a585c..c5dad0d3 100644 --- a/test/front_end.jl +++ b/test/front_end.jl @@ -59,4 +59,710 @@ end @test eltype(typeof(labelProd)) == (eltype(typeof(flavors)), eltype(typeof(tau_labels)), eltype(typeof(loopbasis))) @test FrontEnds._find_label(typeof(labelProd.labels), typeof(loopbasis)) == 3 +end + +@testset "Parquet" begin + using FeynmanDiagram: ComputationalGraphs as Graphs + Ftype, Wtype = Graphs._dtype.factor, Graphs._dtype.weight + + @testset "Parameter" begin + p = DiagPara(type=Ver4Diag, innerLoopNum=1) + q = DiagPara(type=Ver4Diag, innerLoopNum=2) + a = DiagPara(type=Ver4Diag, innerLoopNum=2) + + @test p != q + @test q == a + + aa = reconstruct(a, transferLoop=[0.0, 0.0, 0.0]) + @test a != aa + + # reconstruct with the same type but different interaction + aaa = reconstruct(a, interaction=[]) + @test a != aaa + + # reconstruct with different diagram type leads to different parameter + #reconstructed DiagPara uses the old parameters such as firstLoopIdx, totalLoopNum etc., which are different between types + s = reconstruct(a, type=SigmaDiag) + ss = DiagPara(type=SigmaDiag, innerLoopNum=2) + @test s != ss + + end + + @testset "Partition" begin + p = Parquet.orderedPartition(5, 2) + expect = [[4, 1], [1, 4], [2, 3], [3, 2]] + @test Set(p) == Set(expect) + + p = Parquet.orderedPartition(3, 2, 0) + expect = [[3, 0], [0, 3], [1, 2], [2, 1]] + @test Set(p) == Set(expect) + end + + @testset "FindFirstIdx" begin + function testLoopIdx(partition, firstidx, expected) + firstLoopIdx, total = Parquet.findFirstLoopIdx(partition, firstidx) + @test firstLoopIdx == expected + totalExp = sum(partition) + firstidx - 1 + @test total == totalExp + end + + testLoopIdx([1, 1, 2, 1], 1, [1, 2, 3, 5]) + testLoopIdx([1, 1, 2, 1], 0, [0, 1, 2, 4]) + testLoopIdx([1, 0, 2, 0], 1, [1, 2, 2, 4]) + testLoopIdx([1,], 1, [1,]) + + function testTauIdx(partition, isG, firstidx, tauNum, expected) + firstIdx, total = Parquet.findFirstTauIdx(partition, isG, firstidx, tauNum) + @test firstIdx == expected + end + tauNum = 1 + # isG = [false, true, false, true] + isG = [Ver4Diag, GreenDiag, Ver4Diag, GreenDiag] + testTauIdx([1, 1, 2, 1], isG, 1, tauNum, [1, 3, 4, 7]) + testTauIdx([1, 1, 2, 1], isG, 0, tauNum, [0, 2, 3, 6]) + testTauIdx([1, 0, 2, 0], isG, 1, tauNum, [1, 3, 3, 6]) + + end + + @testset "Filter" begin + # for G irreducible diagrams, only 0-loop G is allowed + @test Parquet.isValidG([Girreducible,], 0) == true + @test Parquet.isValidG([Girreducible,], 1) == false + @test Parquet.isValidG([Girreducible,], 2) == false + + # for Fock irreducible diagrams, only 0-loop or 2, 3, 4...-loop G is allowed + @test Parquet.isValidG([NoFock,], 0) == true + @test Parquet.isValidG([NoFock,], 1) == true + #one-loop G diagram becomes invalid only if both Hartree and Fock are filtered + @test Parquet.isValidG([NoFock, NoHartree], 1) == false + @test Parquet.isValidG([NoFock, NoHartree], 2) == true + + # for G irreducible diagrams, no sigma subdiagram is allowed + @test Parquet.isValidSigma([Girreducible,], 0, true) == false + @test Parquet.isValidSigma([Girreducible,], 1, true) == false + @test Parquet.isValidSigma([Girreducible,], 2, true) == false + + @test Parquet.isValidSigma([Girreducible,], 0, false) == false + @test Parquet.isValidSigma([Girreducible,], 1, false) == true + @test Parquet.isValidSigma([Girreducible,], 2, false) == true + + # for Fock irreducible diagrams, no Fock sigma subdiagram is allowed + @test Parquet.isValidSigma([NoFock,], 0, true) == false + #one-loop sigma diagram can be either Hartree or Fock diagram + #one-loop sigma sub-diagram becomes invalid only if both Hartree and Fock are filtered + @test Parquet.isValidSigma([NoFock,], 1, true) == true + @test Parquet.isValidSigma([NoFock, NoHartree], 1, true) == false + @test Parquet.isValidSigma([NoFock, NoHartree], 2, true) == true + + @test Parquet.isValidSigma([NoFock,], 0, false) == false + @test Parquet.isValidSigma([NoFock,], 1, false) == true + @test Parquet.isValidSigma([NoFock, NoHartree], 1, false) == true + @test Parquet.isValidSigma([NoFock,], 2, false) == true + end + + function getdiagram(spin=2.0, D=3, Nk=4, Nt=2) + """ + k1-k3 k2+k3 + | | + t1.L ↑ t1.L t2.L ↑ t2.L + |-------------->----------| + | | k3+k4 | | + | v | | v | + | | k4 | | + |--------------<----------| + t1.L ↑ t1.L t2.L ↑ t2.L + | | + k1 k2 + """ + + Graphs.uidreset() + # We only consider the direct part of the above diagram + + paraG = DiagPara(type=GreenDiag, + innerLoopNum=0, totalLoopNum=Nk, + hasTau=true, totalTauNum=Nt) + paraV = paraG + + # #construct the propagator table + gK = [[0.0, 0.0, 1.0, 1.0], [0.0, 0.0, 0.0, 1.0]] + gT = [(1, 2), (2, 1)] + g = [Graph([], properties=BareGreenId(paraG, k=gK[i], t=gT[i]), name=:G) for i in 1:2] + + vdK = [[0.0, 0.0, 1.0, 0.0], [0.0, 0.0, 1.0, 0.0]] + # vdT = [[1, 1], [2, 2]] + vd = [Graph([], properties=BareInteractionId(paraV, ChargeCharge, k=vdK[i]), name=:Vd) for i in 1:2] + + veK = [[1, 0, -1, -1], [0, 1, 0, -1]] + # veT = [[1, 1], [2, 2]] + ve = [Graph([], properties=BareInteractionId(paraV, ChargeCharge, k=veK[i]), name=:Ve) for i in 1:2] + + Id = GenericId(paraV) + # contruct the tree + ggn = Graph([g[1], g[2]], properties=Id, operator=Graphs.Prod()) + vdd = Graph([vd[1], vd[2]], properties=Id, operator=Graphs.Prod(), factor=spin) + vde = Graph([vd[1], ve[2]], properties=Id, operator=Graphs.Prod(), factor=-1.0) + ved = Graph([ve[1], vd[2]], properties=Id, operator=Graphs.Prod(), factor=-1.0) + vsum = Graph([vdd, vde, ved], properties=Id, operator=Graphs.Sum()) + root = Graph([vsum, ggn], properties=Id, operator=Graphs.Prod(), factor=1 / (2π)^D, name=:root) + + return root, gK, gT, vdK, veK + end + + function assign_leaves(g::Graph, taylormap) #This should be written more generic later. + #For bench mark purpose, currently it assigns taylor coefficients of leaves with 1.0 / taylor_factorial(order)) so that it corresponds to assign all derivatives with 1. + leafmap = Dict{Int,Int}() + leafvec = Vector{Float64}() + idx = 0 + for leaf in Leaves(g) + taylor = taylormap[leaf.id] + for (order, coeff) in taylor.coeffs + idx += 1 + push!(leafvec, 1.0 / Taylor.taylor_factorial(order)) + leafmap[coeff.id] = idx + #print("assign $(order) $(coeff.id) $(taylor_factorial(order)) $(leafvec[idx])\n") + end + end + return leafmap, leafvec + end + + + @testset "Generic Parquet-generated graphs" begin + Graphs.uidreset() + # We only consider the direct part of the above diagram + spin = 1.0 + D = 3 + kF, β, mass2 = 1.919, 0.5, 1.0 + Nk, Nt = 4, 2 + + root, gK, gT, vdK, veK = getdiagram(spin, D, Nk, Nt) + rootval = Graphs.eval!(root) + Graphs.optimize!([root]) + @test Graphs.eval!(root) == rootval + + # autodiff + factor = 1 / (2π)^D + Taylor.set_variables("x y"; orders=[1, 1]) + propagator_var = Dict(BareGreenId => [true, false], BareInteractionId => [false, true]) # Specify variable dependence of fermi (first element) and bose (second element) particles. + t, taylormap = Utility.taylorexpansion!(root, propagator_var) + + taylorleafmap, taylorleafvec = assign_leaves(root, taylormap) + @test eval!(t.coeffs[[0, 0]], taylorleafmap, taylorleafvec) ≈ (-2 + spin) * factor + @test eval!(t.coeffs[[0, 1]], taylorleafmap, taylorleafvec) ≈ (-2 + spin) * 2 * factor / Taylor.taylor_factorial([0, 1]) + @test eval!(t.coeffs[[1, 0]], taylorleafmap, taylorleafvec) ≈ (-2 + spin) * 2 * factor / Taylor.taylor_factorial([1, 0]) + + # #more sophisticated test of the weight evaluation + varK = rand(D, Nk) + varT = [rand() * β for t in 1:Nt] + + function evalG(K, τBasis, varT, order=0) + ϵ = dot(K, K) / 2 - kF^2 + τ = varT[τBasis[2]] - varT[τBasis[1]] + if order == 0 + return Spectral.kernelFermiT(τ, ϵ, β) + elseif order == 1 + return Spectral.kernelFermiT(τ, ϵ, β) * 3.1415 + else + error("not implemented!") + end + end + + function evalV(K, order=0) + if order == 0 + return 8π / (dot(K, K) + mass2) + elseif order == 1 + return 8π / (dot(K, K) + mass2) * 3.1415 + else + error("not implemented!") + end + end + + # # getK(basis, varK) = sum([basis[i] * K for (i, K) in enumerate(varK)]) + getK(basis, varK) = varK * basis + + # eval(id::BareGreenId, varK, varT) = evalG(getK(id.extK, varK), id.extT, varT, id.order[1]) + # eval(id::BareInteractionId, varK, varT) = evalV(getK(id.extK, varK), id.order[2]) + + # gw = [evalG(getK(gK[i], varK), gT[i], varT) for i = 1:2] + # vdw = [evalV(getK(vdK[i], varK)) for i = 1:2] + # vew = [evalV(getK(veK[i], varK)) for i = 1:2] + + # dgw = [evalG(getK(gK[i], varK), gT[i], varT, 1) for i = 1:2] + # dvdw = [evalV(getK(vdK[i], varK), 1) for i = 1:2] + # dvew = [evalV(getK(veK[i], varK), 1) for i = 1:2] + + # Vweight = spin * vdw[1] * vdw[2] - vdw[1] * vew[2] - vew[1] * vdw[2] + # Gweight = gw[1] * gw[2] + # Weight = Gweight * Vweight / (2π)^D + + # dVweight = spin * (dvdw[1] * vdw[2] + vdw[1] * dvdw[2]) - + # (dvdw[1] * vew[2] + vdw[1] * dvew[2]) - + # (dvew[1] * vdw[2] + vew[1] * dvdw[2]) + + # dGweight = dgw[1] * gw[2] + gw[1] * dgw[2] + # dWeight_dg = dGweight * Vweight / (2π)^D + # dWeight_dv = Gweight * dVweight / (2π)^D + + + end + + function evalG(K, τin, τout) + # println(τBasis, ", ", varT) + kF, β = 1.0, 1.0 + ϵ = dot(K, K) / 2 - kF^2 + τ = τout - τin + if τ ≈ 0.0 + return Spectral.kernelFermiT(-1e-8, ϵ, β) + else + return Spectral.kernelFermiT(τ, ϵ, β) + end + end + evalV(K) = 8π / (dot(K, K) + 1) + + evalGfixK(K, τin, τout) = evalG(zero(K), τin, τout) + evalVfixK(K) = 1.0 + + evalFakeG(K, τin, τout) = 1.0 + evalFakeV(K) = 1.0 + + ################## api for expression tree ############################## + evalPropagator(id::BareGreenId, K, extT, varT) = evalG(K, varT[extT[1]], varT[extT[2]]) + evalPropagator(id::BareInteractionId, K, extT, varT) = evalV(K) + evalPropagatorfixK(id::BareGreenId, K, extT, varT) = evalGfixK(K, varT[extT[1]], varT[extT[2]]) + evalPropagatorfixK(id::BareInteractionId, K, extT, varT) = evalVfixK(K) + evalFakePropagator(id::PropagatorId, K, extT, varT) = 1.0 + + # @testset "ep Ver4" begin + # loopnum = 2 + # para = DiagPara(type=Ver4Diag, hasTau=true, innerLoopNum=loopnum, interaction=[Interaction(ChargeCharge, [Instant, Dynamic])]) + # Parquet.ep_coupling(para) # make sure ep_coupling runs + # end + + @testset "Ver4 RPA chain" begin + + loopnum = 3 + + para = DiagPara(type=Ver4Diag, hasTau=true, innerLoopNum=loopnum, interaction=[Interaction(ChargeCharge, [Instant, Dynamic])]) + + + legK1, legK2, legK3 = Parquet.getK(para.totalLoopNum, 1), Parquet.getK(para.totalLoopNum, 2), Parquet.getK(para.totalLoopNum, 3) + extK = [legK1, legK2, legK3, legK1 + legK3 - legK2] + level = 0 + + varK = rand(3, para.totalLoopNum) + varT = [rand() for i in 1:para.totalTauNum] + + weight = (2^loopnum) * (2^(loopnum + 1)) + + ############ PHEr ############ + c = PHEr + ver4df = DataFrame(response=Response[], type=AnalyticProperty[], extT=Tuple{Int,Int,Int,Int}[], diagram=Graph{Ftype,Wtype}[]) + Parquet.RPA_chain!(ver4df, para, extK, c, level, :RPA, -1.0) + diags = mergeby(ver4df, :response) + # DiagTree.evalKT!(diags, varK, varT; eval=evalFakePropagator) + Graphs.eval!.(diags.diagram) + w = [diags.diagram[1].weight, diags.diagram[2].weight] + # plot_tree(diags, maxdepth=15) + # println(w1) + #each bubble contribute 2, each dynamic interaction contribute 2, and there is two spin configuration upup, updown + @test w[1] ≈ -weight #additional minus sign from the exchange diagram + @test w[2] ≈ 0.0 # updown is not allowed in exchange diagram + + + ############ PHr ############ + c = PHr + ver4df = DataFrame(response=Response[], type=AnalyticProperty[], extT=Tuple{Int,Int,Int,Int}[], diagram=Graph{Ftype,Wtype}[]) + Parquet.RPA_chain!(ver4df, para, extK, c, level, :RPA, -1.0) + diags = mergeby(ver4df, :response) + # DiagTree.evalKT!(diags, varK, varT; eval=evalFakePropagator) + Graphs.eval!.(diags.diagram) + w = [diags.diagram[1].weight, diags.diagram[2].weight] + # plot_tree(diags, maxdepth=15) + # println(w1) + weight = (2^loopnum) * (2^(loopnum + 1)) + #each bubble contribute 2, each dynamic interaction contribute 2, and there is two spin configuration upup, updown + @test w[1] ≈ weight + @test w[2] ≈ weight + end + + + @testset "ParquetNew Ver4" begin + Benchmark = Parquet.Benchmark + + function getfunction(type) + if type == :physical + return evalG, evalV, evalPropagator + elseif type == :fixK + return evalGfixK, evalVfixK, evalPropagatorfixK + elseif type == :fake + return evalFakeG, evalFakeV, evalFakePropagator + else + error("not implemented") + end + end + + function testVertex4(loopNum, chan, type::Symbol; filter=[NoHartree,], timing=false, toeval=true) + println("$(Int.(chan)) Channel Test") + Kdim, spin = 3, 2 + interactionTauNum = 1 + isFermi = true + + K0 = zeros(loopNum + 2) + KinL, KoutL, KinR, KoutR = deepcopy(K0), deepcopy(K0), deepcopy(K0), deepcopy(K0) + KinL[1] = KoutL[1] = 1 + KinR[2] = KoutR[2] = 1 + legK = [KinL, KoutL, KinR, KoutR] + + blocks = ParquetBlocks(phi=[PHEr, PPr], ppi=[PHr, PHEr]) + + para = DiagPara( + type=Ver4Diag, + # loopDim=Kdim, + isFermi=isFermi, + hasTau=true, + innerLoopNum=loopNum, + totalLoopNum=length(KinL), + totalTauNum=(loopNum + 1) * interactionTauNum, + spin=spin, + firstLoopIdx=3, + firstTauIdx=1, + filter=union(filter, [Girreducible,]), #ver4 evaluation only support one-particle-irreducible diagram + transferLoop=KinL - KoutL, + interaction=[Interaction(ChargeCharge, Instant),], + extra=blocks + ) + + varK = rand(Kdim, para.totalLoopNum) + varT = [rand() for i in 1:para.totalTauNum] + + #################### DiagTree #################################### + diags = Parquet.vertex4(para, legK, chan) + diags = mergeby(diags, :response) + # DiagTreeNew.plot_tree(diags[1]) + # DiagTreeNew.plot_tree(diags[2]) + + ################### ExprTree ################################### + # tree = ExprTree.build(diags.diagram, Kdim) + # println("root", root) + + ################### original Parquet builder ################################### + ver4 = Benchmark.Ver4{Benchmark.Weight}(para, Int.(chan), Int.(blocks.phi), Int.(blocks.ppi)) + + + if toeval + + evalG, evalV, evalPropagator = getfunction(type) + + # DiagTree.evalKT!(diags, varK, varT; eval=evalPropagator) + Graphs.eval!.(diags.diagram) + w1 = [diags.diagram[1].weight, diags.diagram[2].weight] + if timing + printstyled("naive Graph evaluator cost:", color=:green) + # @time DiagTree.evalKT!(diags, varK, varT; eval=evalPropagator) + @time Graphs.eval!.(diags.diagram) + end + + Graphs.optimize!(diags.diagram) + Graphs.eval!.(diags.diagram) + w1opt = [diags.diagram[1].weight, diags.diagram[2].weight] + if timing + printstyled("naive optimized Graph evaluator cost:", color=:green) + @time Graphs.eval!.(diags.diagram) + end + + # ExprTree.evalNaive!(tree, varK, varT; eval=evalPropagator) + # w1e = [tree[1], tree[2]] + # if timing + # printstyled("naive ExprTree cost:", color=:green) + # @time ExprTree.evalKT!(tree, varK, varT; eval=evalPropagator) + # end + + + # optdiags = DiagTree.optimize!(diags.diagram) + # opttree = ExprTree.build(diags.diagram, Kdim) + # ExprTree.evalKT!(opttree, varK, varT; eval=evalPropagator) + # w1eopt = [opttree[1], opttree[2]] + + # if timing + # printstyled("naive optimized ExprTree cost:", color=:green) + # @time ExprTree.evalKT!(opttree, varK, varT; eval=evalPropagator) + # end + + ##################### lower level subroutines ####################################### + + KinL, KoutL, KinR, KoutR = varK[:, 1], varK[:, 1], varK[:, 2], varK[:, 2] + legK = [KinL, KoutL, KinR, KoutR] + # Benchmark.eval(para, ver4, varK, varT, [KinL, KoutL, KinR, KoutR], evalG, evalV, true) + Benchmark.eval(para, ver4, varK, varT, legK, evalG, evalV, true) + + if timing + printstyled("parquet evaluator cost:", color=:green) + # @btime sin(p, ver4, var) setup = (x = rand()) + # @time Benchmark.eval(para, ver4, varK, varT, [KinL, KoutL, KinR, KoutR], evalG, evalV, true) + @time Benchmark.eval(para, ver4, varK, varT, legK, evalG, evalV, true) + # @btime Benchmark.eval(p, v4, vK, vT, lK, eG, eV, flag) setup = (p = para, v4 = ver4, vK = varK, vT = varT, l = legK, eG = evalG, eV = evalV, flag = true) + end + + w2 = ver4.weight[1] + + # println(w1, " vs ", w1e, " vs ", w2) + + # @assert w1 ≈ w1e + @assert w1 ≈ w1opt + + # The upup channel of charge-charge vertex4 == Direct + exchange + # @test w1[1] ≈ w2[1] + w2[2] + # # The updown channel of charge-charge vertex4 == Direct + # @test w1[2] ≈ w2[1] + + end + + return para, diags, ver4 + end + + function testEval(type) + for l = 1:3 + testVertex4(l, [PHr,], type) + testVertex4(l, [PHEr,], type) + testVertex4(l, [PPr,], type) + testVertex4(l, [PHr, PHEr, PPr], type; timing=true) + end + end + + # testEval(:fake) + # testEval(:fixK) + testEval(:physical) + + #test only proper diagrams are generated if the switch is turned on + # para, diag, ver4 = testVertex4(3, [Parquet.T, Parquet.U, Parquet.S], :physical; filter = [Builder.Proper], eval = false) + # for i in 1:length(diag.basisPool) + # @test (diag.basisPool.basis[:, i] ≈ para.transferLoop) == false + # end + end + + @testset "Parquet Sigma" begin + function getSigma(loopNum; Kdim=3, spin=2, interactionTauNum=1, filter=[NoHartree,], isFermi=true, subdiagram=false) + println("LoopNum =$loopNum Sigma Test") + + para = DiagPara( + type=SigmaDiag, + # loopDim=Kdim, + hasTau=true, + innerLoopNum=loopNum, + totalLoopNum=loopNum + 1, + totalTauNum=loopNum * interactionTauNum, + isFermi=isFermi, + spin=spin, + firstLoopIdx=2, + firstTauIdx=1, + filter=filter, + interaction=[Interaction(ChargeCharge, Instant),], + extra=ParquetBlocks(phi=[PHEr, PPr], ppi=[PHr, PHEr]) + ) + + extK = zeros(para.totalLoopNum) + extK[1] = 1.0 + + varK = rand(Kdim, para.totalLoopNum) + varT = [rand() for i in 1:para.totalTauNum] + + #################### DiagTree #################################### + diag = Parquet.sigma(para, extK, subdiagram) + diag = mergeby(diag) + # print_tree(diag.diagram[1]) + + return para, diag.diagram[1], varK, varT + end + + + function testDiagramNumber(para, diag, varK, varT) + w = Graphs.eval!(diag) + # plot_tree(diag, maxdepth = 7) + # factor = (1 / (2π)^para.loopDim)^para.innerLoopNum + factor = 1.0 + num = w / factor + @test num * (-1)^(para.innerLoopNum) ≈ Parquet.Benchmark.count_sigma_G2v(para.innerLoopNum, para.spin) + end + + + ################## G^2*v expansion ######################################### + for l = 1:4 + # ret = getSigma(l, spin = 1, isFermi = false, filter = [Builder.Girreducible,]) + # testDiagramNumber(ret...) + ret = getSigma(l, spin=2, isFermi=false, filter=[NoHartree, Girreducible,]) + testDiagramNumber(ret...) + end + + # para, diag, varK, varT = getSigma(1, spin = 2, isFermi = false, filter = [Builder.NoFock,], subdiagram = true) + # @test isempty(diag.root) + + end + + @testset "Green" begin + function buildG(loopNum, extT; Kdim=3, spin=2, interactionTauNum=1, filter=[NoHartree,], isFermi=true) + para = DiagPara( + type=GreenDiag, + # loopDim=Kdim, + hasTau=true, + innerLoopNum=loopNum, + isFermi=isFermi, + spin=spin, + filter=filter, + interaction=[Interaction(ChargeCharge, Instant),] + ) + extK = zeros(para.totalLoopNum) + extK[1] = 1.0 + if Parquet.isValidG(para) + G = Parquet.green(para, extK, extT) + return G + else + return nothing + end + end + # diag, Gidx = buildG(2, [1, 2], 3; filter = []) + # DiagTree.showTree(diag, Gidx) + + # If G is irreducible, then only loop-0 G exist for main diagram, and no G exist for subdiagram + G = buildG(0, [1, 2]; filter=[NoHartree, Girreducible,]) + @test G isa Graph + G = buildG(1, [1, 2]; filter=[NoHartree, Girreducible,]) + @test isnothing(G) + G = buildG(2, [1, 2]; filter=[NoHartree, Girreducible,]) + @test isnothing(G) + + # If Fock diagram is not allowed, then one-loop G diagram should not be exist for subdiagram + G = buildG(0, [1, 2]; filter=[NoHartree, NoFock,]) + @test G isa Graph + G = buildG(1, [1, 2]; filter=[NoHartree, NoFock,]) + @test isnothing(G) + G = buildG(2, [1, 2]; filter=[NoHartree, NoFock,]) #high order subdiagram is allowed + @test G isa Graph + + end + + + @testset "Parquet Vertex3" begin + function getGamma3(loopNum; Kdim=3, spin=2, interactionTauNum=1, filter=[NoHartree, Girreducible, Proper,], isFermi=true, subdiagram=false) + println("LoopNum =$loopNum Vertex3 Test") + + para = DiagPara( + type=Ver3Diag, + # loopDim=Kdim, + innerLoopNum=loopNum, + isFermi=isFermi, + hasTau=true, + filter=filter, + interaction=[Interaction(ChargeCharge, Instant),] + ) + + K0 = zeros(para.totalLoopNum) + KinL, Q = deepcopy(K0), deepcopy(K0) + Q[1] = 1 + KinL[2] = 1 + legK = [Q, KinL] + + varK = rand(Kdim, para.totalLoopNum) + varT = [rand() for i in 1:para.totalTauNum] + + #################### DiagTree #################################### + vertex3 = Parquet.vertex3(para, legK) + diag = mergeby(vertex3) + # print_tree(diag.diagram[1]) + + return para, diag.diagram[1], varK, varT + end + + + function testDiagramNumber(para, diag, varK, varT) + # w = DiagTree.evalKT!(diag, varK, varT; eval=evalFakePropagator) + w = Graphs.eval!(diag) + # plot_tree(diag, maxdepth = 9) + # factor = (1 / (2π)^para.loopDim)^para.innerLoopNum + factor = 1.0 + num = w / factor + @test num * (-1)^(para.innerLoopNum) ≈ Parquet.Benchmark.count_ver3_G2v(para.innerLoopNum, para.spin) + end + + + ################## G^2*v expansion ######################################### + for l = 1:3 + # ret = getSigma(l, spin = 1, isFermi = false, filter = [Builder.Girreducible,]) + # testDiagramNumber(ret...) + ret = getGamma3(l, isFermi=false, filter=[NoHartree, Girreducible, Proper]) + testDiagramNumber(ret...) + end + + # para, diag, varK, varT = getSigma(1, spin = 2, isFermi = false, filter = [Builder.NoFock,], subdiagram = true) + # @test isempty(diag.root) + + end + + + @testset "Parquet Polarization" begin + function getPolar(loopNum; Kdim=3, spin=2, interactionTauNum=1, filter=[NoHartree, Girreducible,], isFermi=true, subdiagram=false) + println("LoopNum =$loopNum Polarization Test") + + para = DiagPara( + type=PolarDiag, + # loopDim=Kdim, + innerLoopNum=loopNum, + isFermi=isFermi, + hasTau=true, + filter=filter, + interaction=[Interaction(ChargeCharge, Instant),] + ) + + Q = zeros(para.totalLoopNum) + Q[1] = 1 + + varK = rand(Kdim, para.totalLoopNum) + varT = [rand() for i in 1:para.totalTauNum] + + #################### DiagTree #################################### + diag = Parquet.polarization(para, Q) + # print_tree(diag.diagram[1]) + return para, diag, varK, varT + end + + # Test polarization Parquet builder when filter 'Proper' is specified explicitly + getPolar(1, filter=[Proper, NoHartree, NoFock,]) + + ################## G^2*v expansion ######################################### + for l = 1:4 + para, diag, varK, varT = getPolar(l, isFermi=false, filter=[NoHartree, Girreducible,]) + diag = mergeby(diag).diagram[1] + # w = DiagTree.evalKT!(diag, varK, varT; eval=evalFakePropagator) + w = Graphs.eval!(diag) + # factor = (1 / (2π)^para.loopDim)^para.innerLoopNum + factor = 1.0 + num = w / factor + # println(num * para.spin) + @test num * para.spin * (-1)^(para.innerLoopNum - 1) ≈ Parquet.Benchmark.count_polar_G2v(para.innerLoopNum, para.spin) + end + + ################## g^2*v expansion ######################################### + for l = 1:4 + para, diag, varK, varT = getPolar(l, isFermi=false, filter=[NoHartree, NoFock,]) + diag = mergeby(diag).diagram[1] + # w = DiagTree.evalKT!(diag, varK, varT, eval=evalFakePropagator) + w = Graphs.eval!(diag) + # factor = (1 / (2π)^para.loopDim)^para.innerLoopNum + factor = 1.0 + num = w / factor + # println(num * para.spin) + @test num * para.spin * (-1)^(para.innerLoopNum - 1) ≈ Parquet.Benchmark.count_polar_g2v_noFock(para.innerLoopNum, para.spin) + end + + ################## g^2*v expansion for the upup polarization ######################################### + for l = 1:4 + para, diag, varK, varT = getPolar(l, isFermi=false, filter=[NoHartree, NoFock,]) + # w = DiagTree.evalKT!(diag.diagram[1], varK, varT, eval=evalFakePropagator) + w = Graphs.eval!(diag.diagram[1]) + # factor = (1 / (2π)^para.loopDim)^para.innerLoopNum + factor = 1.0 + num = w / factor + # println(num * para.spin) + # println("$diag") + @test num * para.spin * (-1)^(para.innerLoopNum - 1) ≈ Parquet.Benchmark.count_polar_g2v_noFock_upup(para.innerLoopNum, para.spin) + end + end end \ No newline at end of file diff --git a/test/parquet_builder.jl b/test/parquet_builder.jl deleted file mode 100644 index c1ee383e..00000000 --- a/test/parquet_builder.jl +++ /dev/null @@ -1,521 +0,0 @@ -@testset "Partition" begin - p = Parquet.orderedPartition(5, 2) - expect = [[4, 1], [1, 4], [2, 3], [3, 2]] - @test Set(p) == Set(expect) - - p = Parquet.orderedPartition(3, 2, 0) - expect = [[3, 0], [0, 3], [1, 2], [2, 1]] - @test Set(p) == Set(expect) -end - -@testset "FindFirstIdx" begin - function testLoopIdx(partition, firstidx, expected) - firstLoopIdx, total = Parquet.findFirstLoopIdx(partition, firstidx) - @test firstLoopIdx == expected - totalExp = sum(partition) + firstidx - 1 - @test total == totalExp - end - - testLoopIdx([1, 1, 2, 1], 1, [1, 2, 3, 5]) - testLoopIdx([1, 1, 2, 1], 0, [0, 1, 2, 4]) - testLoopIdx([1, 0, 2, 0], 1, [1, 2, 2, 4]) - testLoopIdx([1,], 1, [1,]) - - function testTauIdx(partition, isG, firstidx, tauNum, expected) - firstIdx, total = Parquet.findFirstTauIdx(partition, isG, firstidx, tauNum) - @test firstIdx == expected - end - tauNum = 1 - # isG = [false, true, false, true] - isG = [Ver4Diag, GreenDiag, Ver4Diag, GreenDiag] - testTauIdx([1, 1, 2, 1], isG, 1, tauNum, [1, 3, 4, 7]) - testTauIdx([1, 1, 2, 1], isG, 0, tauNum, [0, 2, 3, 6]) - testTauIdx([1, 0, 2, 0], isG, 1, tauNum, [1, 3, 3, 6]) - -end - -@testset "Filter" begin - - # for G irreducible diagrams, only 0-loop G is allowed - @test Parquet.isValidG([Girreducible,], 0) == true - @test Parquet.isValidG([Girreducible,], 1) == false - @test Parquet.isValidG([Girreducible,], 2) == false - - # for Fock irreducible diagrams, only 0-loop or 2, 3, 4...-loop G is allowed - @test Parquet.isValidG([NoFock,], 0) == true - @test Parquet.isValidG([NoFock,], 1) == true - #one-loop G diagram becomes invalid only if both Hartree and Fock are filtered - @test Parquet.isValidG([NoFock, NoHartree], 1) == false - @test Parquet.isValidG([NoFock, NoHartree], 2) == true - - # for G irreducible diagrams, no sigma subdiagram is allowed - @test Parquet.isValidSigma([Girreducible,], 0, true) == false - @test Parquet.isValidSigma([Girreducible,], 1, true) == false - @test Parquet.isValidSigma([Girreducible,], 2, true) == false - - @test Parquet.isValidSigma([Girreducible,], 0, false) == false - @test Parquet.isValidSigma([Girreducible,], 1, false) == true - @test Parquet.isValidSigma([Girreducible,], 2, false) == true - - # for Fock irreducible diagrams, no Fock sigma subdiagram is allowed - @test Parquet.isValidSigma([NoFock,], 0, true) == false - #one-loop sigma diagram can be either Hartree or Fock diagram - #one-loop sigma sub-diagram becomes invalid only if both Hartree and Fock are filtered - @test Parquet.isValidSigma([NoFock,], 1, true) == true - @test Parquet.isValidSigma([NoFock, NoHartree], 1, true) == false - @test Parquet.isValidSigma([NoFock, NoHartree], 2, true) == true - - @test Parquet.isValidSigma([NoFock,], 0, false) == false - @test Parquet.isValidSigma([NoFock,], 1, false) == true - @test Parquet.isValidSigma([NoFock, NoHartree], 1, false) == true - @test Parquet.isValidSigma([NoFock,], 2, false) == true -end - -function evalG(K, τin, τout) - # println(τBasis, ", ", varT) - kF, β = 1.0, 1.0 - ϵ = dot(K, K) / 2 - kF^2 - τ = τout - τin - if τ ≈ 0.0 - return Spectral.kernelFermiT(-1e-8, ϵ, β) - else - return Spectral.kernelFermiT(τ, ϵ, β) - end -end -evalV(K) = 8π / (dot(K, K) + 1) - -evalGfixK(K, τin, τout) = evalG(zero(K), τin, τout) -evalVfixK(K) = 1.0 - -evalFakeG(K, τin, τout) = 1.0 -evalFakeV(K) = 1.0 - -################## api for expression tree ############################## -evalPropagator(id::BareGreenId, K, extT, varT) = evalG(K, varT[extT[1]], varT[extT[2]]) -evalPropagator(id::BareInteractionId, K, extT, varT) = evalV(K) -evalPropagatorfixK(id::BareGreenId, K, extT, varT) = evalGfixK(K, varT[extT[1]], varT[extT[2]]) -evalPropagatorfixK(id::BareInteractionId, K, extT, varT) = evalVfixK(K) -evalFakePropagator(id::PropagatorId, K, extT, varT) = 1.0 - -# @testset "ep Ver4" begin -# loopnum = 2 -# para = DiagParaF64(type=Ver4Diag, hasTau=true, innerLoopNum=loopnum, interaction=[Interaction(ChargeCharge, [Instant, Dynamic])]) -# Parquet.ep_coupling(para) # make sure ep_coupling runs -# end - - -@testset "Ver4 RPA chain" begin - - loopnum = 3 - - para = DiagParaF64(type=Ver4Diag, hasTau=true, innerLoopNum=loopnum, interaction=[Interaction(ChargeCharge, [Instant, Dynamic])]) - - - legK1, legK2, legK3 = DiagTree.getK(para.totalLoopNum, 1), DiagTree.getK(para.totalLoopNum, 2), DiagTree.getK(para.totalLoopNum, 3) - extK = [legK1, legK2, legK3, legK1 + legK3 - legK2] - level = 0 - - varK = rand(3, para.totalLoopNum) - varT = [rand() for i in 1:para.totalTauNum] - - weight = (2^loopnum) * (2^(loopnum + 1)) - - ############ PHEr ############ - c = PHEr - ver4df = DataFrame(response=Response[], type=AnalyticProperty[], extT=Tuple{Int,Int,Int,Int}[], diagram=Diagram{Float64}[]) - Parquet.RPA_chain!(ver4df, para, extK, c, level, :RPA, -1.0) - diags = mergeby(ver4df, :response) - DiagTree.evalKT!(diags, varK, varT; eval=evalFakePropagator) - w = [diags.diagram[1].weight, diags.diagram[2].weight] - # plot_tree(diags, maxdepth=15) - # println(w1) - #each bubble contribute 2, each dynamic interaction contribute 2, and there is two spin configuration upup, updown - @test w[1] ≈ -weight #additional minus sign from the exchange diagram - @test w[2] ≈ 0.0 # updown is not allowed in exchange diagram - - - ############ PHr ############ - c = PHr - ver4df = DataFrame(response=Response[], type=AnalyticProperty[], extT=Tuple{Int,Int,Int,Int}[], diagram=Diagram{Float64}[]) - Parquet.RPA_chain!(ver4df, para, extK, c, level, :RPA, -1.0) - diags = mergeby(ver4df, :response) - DiagTree.evalKT!(diags, varK, varT; eval=evalFakePropagator) - w = [diags.diagram[1].weight, diags.diagram[2].weight] - # plot_tree(diags, maxdepth=15) - # println(w1) - weight = (2^loopnum) * (2^(loopnum + 1)) - #each bubble contribute 2, each dynamic interaction contribute 2, and there is two spin configuration upup, updown - @test w[1] ≈ weight - @test w[2] ≈ weight -end - - -@testset "ParquetNew Ver4" begin - Benchmark = Parquet.Benchmark - - function getfunction(type) - if type == :physical - return evalG, evalV, evalPropagator - elseif type == :fixK - return evalGfixK, evalVfixK, evalPropagatorfixK - elseif type == :fake - return evalFakeG, evalFakeV, evalFakePropagator - else - error("not implemented") - end - end - - function testVertex4(loopNum, chan, type::Symbol; filter=[NoHartree,], timing=false, toeval=true) - println("$(Int.(chan)) Channel Test") - Kdim, spin = 3, 2 - interactionTauNum = 1 - isFermi = true - - K0 = zeros(loopNum + 2) - KinL, KoutL, KinR, KoutR = deepcopy(K0), deepcopy(K0), deepcopy(K0), deepcopy(K0) - KinL[1] = KoutL[1] = 1 - KinR[2] = KoutR[2] = 1 - legK = [KinL, KoutL, KinR, KoutR] - - blocks = ParquetBlocks(phi=[PHEr, PPr], ppi=[PHr, PHEr]) - - para = DiagParaF64( - type=Ver4Diag, - # loopDim=Kdim, - isFermi=isFermi, - hasTau=true, - innerLoopNum=loopNum, - totalLoopNum=length(KinL), - totalTauNum=(loopNum + 1) * interactionTauNum, - spin=spin, - firstLoopIdx=3, - firstTauIdx=1, - filter=union(filter, [Girreducible,]), #ver4 evaluation only support one-particle-irreducible diagram - transferLoop=KinL - KoutL, - interaction=[Interaction(ChargeCharge, Instant),], - extra=blocks - ) - - varK = rand(Kdim, para.totalLoopNum) - varT = [rand() for i in 1:para.totalTauNum] - - #################### DiagTree #################################### - diags = Parquet.vertex4(para, legK, chan) - diags = mergeby(diags, :response) - # DiagTreeNew.plot_tree(diags[1]) - # DiagTreeNew.plot_tree(diags[2]) - - ################### ExprTree ################################### - tree = ExprTree.build(diags.diagram, Kdim) - # println("root", root) - - ################### original Parquet builder ################################### - ver4 = Benchmark.Ver4{Benchmark.Weight}(para, Int.(chan), Int.(blocks.phi), Int.(blocks.ppi)) - - - if toeval - - evalG, evalV, evalPropagator = getfunction(type) - - # w1 = DiagTree.evalNaive(diag, varK, varT, evalPropagator) - DiagTree.evalKT!(diags, varK, varT; eval=evalPropagator) - w1 = [diags.diagram[1].weight, diags.diagram[2].weight] - if timing - printstyled("naive DiagTree evaluator cost:", color=:green) - @time DiagTree.evalKT!(diags, varK, varT; eval=evalPropagator) - end - - ExprTree.evalNaive!(tree, varK, varT; eval=evalPropagator) - w1e = [tree[1], tree[2]] - if timing - printstyled("naive ExprTree cost:", color=:green) - @time ExprTree.evalKT!(tree, varK, varT; eval=evalPropagator) - end - - - # optdiags = DiagTree.optimize!(diags.diagram) - opttree = ExprTree.build(diags.diagram, Kdim) - ExprTree.evalKT!(opttree, varK, varT; eval=evalPropagator) - w1eopt = [opttree[1], opttree[2]] - - if timing - printstyled("naive optimized ExprTree cost:", color=:green) - @time ExprTree.evalKT!(opttree, varK, varT; eval=evalPropagator) - end - - ##################### lower level subroutines ####################################### - - KinL, KoutL, KinR, KoutR = varK[:, 1], varK[:, 1], varK[:, 2], varK[:, 2] - legK = [KinL, KoutL, KinR, KoutR] - # Benchmark.eval(para, ver4, varK, varT, [KinL, KoutL, KinR, KoutR], evalG, evalV, true) - Benchmark.eval(para, ver4, varK, varT, legK, evalG, evalV, true) - - if timing - printstyled("parquet evaluator cost:", color=:green) - # @btime sin(p, ver4, var) setup = (x = rand()) - # @time Benchmark.eval(para, ver4, varK, varT, [KinL, KoutL, KinR, KoutR], evalG, evalV, true) - @time Benchmark.eval(para, ver4, varK, varT, legK, evalG, evalV, true) - # @btime Benchmark.eval(p, v4, vK, vT, lK, eG, eV, flag) setup = (p = para, v4 = ver4, vK = varK, vT = varT, l = legK, eG = evalG, eV = evalV, flag = true) - end - - w2 = ver4.weight[1] - - # println(w1, " vs ", w1e, " vs ", w2) - - @assert w1 ≈ w1e - @assert w1 ≈ w1eopt - - # The upup channel of charge-charge vertex4 == Direct + exchange - @test w1[1] ≈ w2[1] + w2[2] - # The updown channel of charge-charge vertex4 == Direct - @test w1[2] ≈ w2[1] - - end - - return para, diags, ver4 - end - - function testEval(type) - for l = 1:3 - testVertex4(l, [PHr,], type) - testVertex4(l, [PHEr,], type) - testVertex4(l, [PPr,], type) - testVertex4(l, [PHr, PHEr, PPr], type; timing=true) - end - end - - # testEval(:fake) - # testEval(:fixK) - testEval(:physical) - - #test only proper diagrams are generated if the switch is turned on - # para, diag, ver4 = testVertex4(3, [Parquet.T, Parquet.U, Parquet.S], :physical; filter = [Builder.Proper], eval = false) - # for i in 1:length(diag.basisPool) - # @test (diag.basisPool.basis[:, i] ≈ para.transferLoop) == false - # end -end - -@testset "Parquet Sigma" begin - function getSigma(loopNum; Kdim=3, spin=2, interactionTauNum=1, filter=[NoHartree,], isFermi=true, subdiagram=false) - println("LoopNum =$loopNum Sigma Test") - - para = DiagParaF64( - type=SigmaDiag, - # loopDim=Kdim, - hasTau=true, - innerLoopNum=loopNum, - totalLoopNum=loopNum + 1, - totalTauNum=loopNum * interactionTauNum, - isFermi=isFermi, - spin=spin, - firstLoopIdx=2, - firstTauIdx=1, - filter=filter, - interaction=[Interaction(ChargeCharge, Instant),], - extra=ParquetBlocks(phi=[PHEr, PPr], ppi=[PHr, PHEr]) - ) - - extK = zeros(para.totalLoopNum) - extK[1] = 1.0 - - varK = rand(Kdim, para.totalLoopNum) - varT = [rand() for i in 1:para.totalTauNum] - - #################### DiagTree #################################### - diag = Parquet.sigma(para, extK, subdiagram) - diag = mergeby(diag) - # print_tree(diag.diagram[1]) - - return para, diag.diagram[1], varK, varT - end - - - function testDiagramNumber(para, diag, varK, varT) - # w = DiagTree.evalNaive(diag, varK, varT, evalFakePropagator) - w = DiagTree.evalKT!(diag, varK, varT; eval=evalFakePropagator) - # plot_tree(diag, maxdepth = 7) - # factor = (1 / (2π)^para.loopDim)^para.innerLoopNum - factor = 1.0 - num = w / factor - @test num * (-1)^(para.innerLoopNum) ≈ Parquet.Benchmark.count_sigma_G2v(para.innerLoopNum, para.spin) - end - - - ################## G^2*v expansion ######################################### - for l = 1:4 - # ret = getSigma(l, spin = 1, isFermi = false, filter = [Builder.Girreducible,]) - # testDiagramNumber(ret...) - ret = getSigma(l, spin=2, isFermi=false, filter=[NoHartree, Girreducible,]) - testDiagramNumber(ret...) - end - - # para, diag, varK, varT = getSigma(1, spin = 2, isFermi = false, filter = [Builder.NoFock,], subdiagram = true) - # @test isempty(diag.root) - -end - -@testset "Green" begin - function buildG(loopNum, extT; Kdim=3, spin=2, interactionTauNum=1, filter=[NoHartree,], isFermi=true) - para = DiagParaF64( - type=GreenDiag, - # loopDim=Kdim, - hasTau=true, - innerLoopNum=loopNum, - isFermi=isFermi, - spin=spin, - filter=filter, - interaction=[Interaction(ChargeCharge, Instant),] - ) - extK = zeros(para.totalLoopNum) - extK[1] = 1.0 - if Parquet.isValidG(para) - G = Parquet.green(para, extK, extT) - return G - else - return nothing - end - end - # diag, Gidx = buildG(2, [1, 2], 3; filter = []) - # DiagTree.showTree(diag, Gidx) - - # If G is irreducible, then only loop-0 G exist for main diagram, and no G exist for subdiagram - G = buildG(0, [1, 2]; filter=[NoHartree, Girreducible,]) - @test G isa Diagram - G = buildG(1, [1, 2]; filter=[NoHartree, Girreducible,]) - @test isnothing(G) - G = buildG(2, [1, 2]; filter=[NoHartree, Girreducible,]) - @test isnothing(G) - - # If Fock diagram is not allowed, then one-loop G diagram should not be exist for subdiagram - G = buildG(0, [1, 2]; filter=[NoHartree, NoFock,]) - @test G isa Diagram - G = buildG(1, [1, 2]; filter=[NoHartree, NoFock,]) - @test isnothing(G) - G = buildG(2, [1, 2]; filter=[NoHartree, NoFock,]) #high order subdiagram is allowed - @test G isa Diagram - -end - - -@testset "Parquet Vertex3" begin - function getGamma3(loopNum; Kdim=3, spin=2, interactionTauNum=1, filter=[NoHartree, Girreducible, Proper,], isFermi=true, subdiagram=false) - println("LoopNum =$loopNum Vertex3 Test") - - para = DiagParaF64( - type=Ver3Diag, - # loopDim=Kdim, - innerLoopNum=loopNum, - isFermi=isFermi, - hasTau=true, - filter=filter, - interaction=[Interaction(ChargeCharge, Instant),] - ) - - K0 = zeros(para.totalLoopNum) - KinL, Q = deepcopy(K0), deepcopy(K0) - Q[1] = 1 - KinL[2] = 1 - legK = [Q, KinL] - - varK = rand(Kdim, para.totalLoopNum) - varT = [rand() for i in 1:para.totalTauNum] - - #################### DiagTree #################################### - vertex3 = Parquet.vertex3(para, legK) - diag = mergeby(vertex3) - # print_tree(diag.diagram[1]) - - return para, diag.diagram[1], varK, varT - end - - - function testDiagramNumber(para, diag, varK, varT) - # w = DiagTree.evalNaive(diag, varK, varT, evalFakePropagator) - w = DiagTree.evalKT!(diag, varK, varT; eval=evalFakePropagator) - # plot_tree(diag, maxdepth = 9) - # factor = (1 / (2π)^para.loopDim)^para.innerLoopNum - factor = 1.0 - num = w / factor - @test num * (-1)^(para.innerLoopNum) ≈ Parquet.Benchmark.count_ver3_G2v(para.innerLoopNum, para.spin) - end - - - ################## G^2*v expansion ######################################### - for l = 1:3 - # ret = getSigma(l, spin = 1, isFermi = false, filter = [Builder.Girreducible,]) - # testDiagramNumber(ret...) - ret = getGamma3(l, isFermi=false, filter=[NoHartree, Girreducible, Proper]) - testDiagramNumber(ret...) - end - - # para, diag, varK, varT = getSigma(1, spin = 2, isFermi = false, filter = [Builder.NoFock,], subdiagram = true) - # @test isempty(diag.root) - -end - - -@testset "Parquet Polarization" begin - function getPolar(loopNum; Kdim=3, spin=2, interactionTauNum=1, filter=[NoHartree, Girreducible,], isFermi=true, subdiagram=false) - println("LoopNum =$loopNum Polarization Test") - - para = DiagParaF64( - type=PolarDiag, - # loopDim=Kdim, - innerLoopNum=loopNum, - isFermi=isFermi, - hasTau=true, - filter=filter, - interaction=[Interaction(ChargeCharge, Instant),] - ) - - Q = zeros(para.totalLoopNum) - Q[1] = 1 - - varK = rand(Kdim, para.totalLoopNum) - varT = [rand() for i in 1:para.totalTauNum] - - #################### DiagTree #################################### - diag = Parquet.polarization(para, Q) - # print_tree(diag.diagram[1]) - return para, diag, varK, varT - end - - # Test polarization Parquet builder when filter 'Proper' is specified explicitly - getPolar(1, filter=[Proper, NoHartree, NoFock,]) - - ################## G^2*v expansion ######################################### - for l = 1:4 - para, diag, varK, varT = getPolar(l, isFermi=false, filter=[NoHartree, Girreducible,]) - diag = mergeby(diag).diagram[1] - w = DiagTree.evalKT!(diag, varK, varT; eval=evalFakePropagator) - # factor = (1 / (2π)^para.loopDim)^para.innerLoopNum - factor = 1.0 - num = w / factor - # println(num * para.spin) - @test num * para.spin * (-1)^(para.innerLoopNum - 1) ≈ Parquet.Benchmark.count_polar_G2v(para.innerLoopNum, para.spin) - end - - ################## g^2*v expansion ######################################### - for l = 1:4 - para, diag, varK, varT = getPolar(l, isFermi=false, filter=[NoHartree, NoFock,]) - diag = mergeby(diag).diagram[1] - w = DiagTree.evalKT!(diag, varK, varT, eval=evalFakePropagator) - # factor = (1 / (2π)^para.loopDim)^para.innerLoopNum - factor = 1.0 - num = w / factor - # println(num * para.spin) - @test num * para.spin * (-1)^(para.innerLoopNum - 1) ≈ Parquet.Benchmark.count_polar_g2v_noFock(para.innerLoopNum, para.spin) - end - - ################## g^2*v expansion for the upup polarization ######################################### - for l = 1:4 - para, diag, varK, varT = getPolar(l, isFermi=false, filter=[NoHartree, NoFock,]) - w = DiagTree.evalKT!(diag.diagram[1], varK, varT, eval=evalFakePropagator) - # factor = (1 / (2π)^para.loopDim)^para.innerLoopNum - factor = 1.0 - num = w / factor - # println(num * para.spin) - # println("$diag") - @test num * para.spin * (-1)^(para.innerLoopNum - 1) ≈ Parquet.Benchmark.count_polar_g2v_noFock_upup(para.innerLoopNum, para.spin) - end -end \ No newline at end of file diff --git a/test/runtests.jl b/test/runtests.jl index 635665b0..22914595 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -38,12 +38,10 @@ end # doctest(FeynmanDiagram) # end if isempty(ARGS) - include("common.jl") include("quantum_operator.jl") include("computational_graph.jl") - include("diagram_tree.jl") - include("expression_tree.jl") - include("parquet_builder.jl") + # include("diagram_tree.jl") + # include("graph_deriv.jl") include("compiler.jl") include("front_end.jl") include("taylor.jl") diff --git a/test/taylor.jl b/test/taylor.jl index e39e5578..d3fc6f13 100644 --- a/test/taylor.jl +++ b/test/taylor.jl @@ -1,6 +1,7 @@ using FeynmanDiagram using FeynmanDiagram: Taylor as Taylor -using ..DiagTree +using FeynmanDiagram: ComputationalGraphs as Graphs + function assign_random_numbers(g, taylormap1, taylormap2) #Benchmark taylor expansion generated by two different methods leafmap1 = Dict{Int,Int}() leafvec1 = Vector{Float64}() @@ -15,9 +16,24 @@ function assign_random_numbers(g, taylormap1, taylormap2) #Benchmark taylor expa num = rand() push!(leafvec1, num) push!(leafvec2, num) - leafmap1[coeff.id] = idx - leafmap2[taylor2.coeffs[order].id] = idx - #print("assign $(order) $(coeff.id) $(taylor_factorial(order)) $(leafvec[idx])\n") + # leafmap1[coeff.id] = idx + if isleaf(coeff) + leafmap1[coeff.id] = idx + else + @assert onechild(coeff) && isleaf(eldest(coeff)) + println("taylor: $(coeff.id) -> $(eldest(coeff).id)") + leafmap1[eldest(coeff).id] = idx + end + coeff2 = taylor2.coeffs[order] + if isleaf(coeff2) + leafmap2[coeff2.id] = idx + else + @assert onechild(coeff2) && isleaf(eldest(coeff2)) + println("backAD: $(coeff2.id) -> $(eldest(coeff2).id)") + leafmap2[eldest(coeff2).id] = idx + end + # leafmap2[taylor2.coeffs[order].id] = idx + # print("assign $(order) $(coeff.id) $(coeff2.id) $(taylor_factorial(order)) $(leafvec1[idx]) $(leafvec2[idx])\n") end end return leafmap1, leafvec1, leafmap2, leafvec2 @@ -46,29 +62,31 @@ end eval!, forwardAD, node_derivative, backAD, build_all_leaf_derivative, count_operation using FeynmanDiagram.Utility: taylorexpansion!, build_derivative_backAD! - g1 = Graph([]) - g2 = Graph([]) - g3 = Graph([], factor=2.0) - G3 = g1 - G4 = 1.0 * g1 * g1 - G5 = 1.0 * (3.0 * G3 + 0.5 * G4) - G6 = (1.0 * g1 + 2.0 * g2) * (g1 + g3) - - set_variables("x y z", orders=[2, 3, 2]) - var_dependence = Dict{Int,Vector{Bool}}() - for G in [G3, G4, G5, G6] - for leaf in Leaves(G) - if !haskey(var_dependence, leaf.id) - var_dependence[leaf.id] = [true for _ in 1:get_numvars()] - end - end - T, taylormap = taylorexpansion!(G, var_dependence) - 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 - @test eval!(coeff, leafmap2, leafvec2) ≈ taylor_factorial(order) * eval!(T.coeffs[order], leafmap1, leafvec1) - end - end + + ### backAD has bugs! + # g1 = Graph([]) + # g2 = Graph([]) + # g3 = Graph([], factor=2.0) + # G3 = g1 + # G4 = 1.0 * g1 * g1 + # G5 = 1.0 * (3.0 * G3 + 0.5 * G4) + # G6 = (1.0 * g1 + 2.0 * g2) * (g1 + g3) + + # set_variables("x y z", orders=[2, 3, 2]) + # var_dependence = Dict{Int,Vector{Bool}}() + # for G in [G3, G4, G5, G6] + # for leaf in Leaves(G) + # if !haskey(var_dependence, leaf.id) + # var_dependence[leaf.id] = [true for _ in 1:get_numvars()] + # end + # end + # T, taylormap = taylorexpansion!(G, var_dependence) + # 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 + # @test eval!(coeff, leafmap2, leafvec2) ≈ taylor_factorial(order) * eval!(T.coeffs[order], leafmap1, leafvec1) + # end + # end end @@ -95,7 +113,6 @@ end end end - function getdiagram(spin=2.0, D=3, Nk=4, Nt=2) """ k1-k3 k2+k3 @@ -111,10 +128,10 @@ function getdiagram(spin=2.0, D=3, Nk=4, Nt=2) k1 k2 """ - DiagTree.uidreset() + Graphs.uidreset() # We only consider the direct part of the above diagram - paraG = DiagParaF64(type=GreenDiag, + paraG = DiagPara(type=GreenDiag, innerLoopNum=0, totalLoopNum=Nk, hasTau=true, totalTauNum=Nt) paraV = paraG @@ -122,35 +139,35 @@ function getdiagram(spin=2.0, D=3, Nk=4, Nt=2) # #construct the propagator table gK = [[0.0, 0.0, 1.0, 1.0], [0.0, 0.0, 0.0, 1.0]] gT = [(1, 2), (2, 1)] - g = [Diagram{Float64}(BareGreenId(paraG, k=gK[i], t=gT[i]), name=:G) for i in 1:2] + g = [Graph([], properties=BareGreenId(paraG, k=gK[i], t=gT[i]), name=:G) for i in 1:2] vdK = [[0.0, 0.0, 1.0, 0.0], [0.0, 0.0, 1.0, 0.0]] # vdT = [[1, 1], [2, 2]] - vd = [Diagram{Float64}(BareInteractionId(paraV, ChargeCharge, k=vdK[i], permu=Di), name=:Vd) for i in 1:2] + vd = [Graph([], properties=BareInteractionId(paraV, ChargeCharge, k=vdK[i]), name=:Vd) for i in 1:2] veK = [[1, 0, -1, -1], [0, 1, 0, -1]] # veT = [[1, 1], [2, 2]] - ve = [Diagram{Float64}(BareInteractionId(paraV, ChargeCharge, k=veK[i], permu=Ex), name=:Ve) for i in 1:2] + ve = [Graph([], properties=BareInteractionId(paraV, ChargeCharge, k=veK[i]), name=:Ve) for i in 1:2] Id = GenericId(paraV) # contruct the tree - ggn = Diagram{Float64}(Id, Prod(), [g[1], g[2]]) - vdd = Diagram{Float64}(Id, Prod(), [vd[1], vd[2]], factor=spin) - vde = Diagram{Float64}(Id, Prod(), [vd[1], ve[2]], factor=-1.0) - ved = Diagram{Float64}(Id, Prod(), [ve[1], vd[2]], factor=-1.0) - vsum = Diagram{Float64}(Id, Sum(), [vdd, vde, ved]) - root = Diagram{Float64}(Id, Prod(), [vsum, ggn], factor=1 / (2π)^D, name=:root) + ggn = Graph([g[1], g[2]], properties=Id, operator=Graphs.Prod()) + vdd = Graph([vd[1], vd[2]], properties=Id, operator=Graphs.Prod(), factor=spin) + vde = Graph([vd[1], ve[2]], properties=Id, operator=Graphs.Prod(), factor=-1.0) + ved = Graph([ve[1], vd[2]], properties=Id, operator=Graphs.Prod(), factor=-1.0) + vsum = Graph([vdd, vde, ved], properties=Id, operator=Graphs.Sum()) + root = Graph([vsum, ggn], properties=Id, operator=Graphs.Prod(), factor=1 / (2π)^D, name=:root) return root, gK, gT, vdK, veK end -function assign_leaves(g::Diagram, taylormap) #This should be written more generic later. +function assign_leaves(g::Graph, taylormap) #This should be written more generic later. #For bench mark purpose, currently it assigns taylor coefficients of leaves with 1.0 / taylor_factorial(order)) so that it corresponds to assign all derivatives with 1. leafmap = Dict{Int,Int}() leafvec = Vector{Float64}() idx = 0 for leaf in Leaves(g) - taylor = taylormap[leaf.hash] + taylor = taylormap[leaf.id] for (order, coeff) in taylor.coeffs idx += 1 push!(leafvec, 1.0 / taylor_factorial(order)) @@ -162,10 +179,9 @@ function assign_leaves(g::Diagram, taylormap) #This should be written more gener end -@testset "Taylor AD of DiagTree" begin - +@testset "Taylor AD of Parquet-generated Graph" begin - DiagTree.uidreset() + Graphs.uidreset() # We only consider the direct part of the above diagram spin = 0.5 D = 3 @@ -175,45 +191,20 @@ end root, gK, gT, vdK, veK = getdiagram(spin, D, Nk, Nt) #optimize the diagram - DiagTree.optimize!([root,]) + Graphs.optimize!([root,]) # autodiff - droot_dg = DiagTree.derivative([root,], BareGreenId)[1] - droot_dv = DiagTree.derivative([root,], BareInteractionId)[1] - droot_dvdg = DiagTree.derivative([droot_dg,], BareInteractionId)[1] - droot_dvdv = DiagTree.derivative([droot_dv,], BareInteractionId)[1] - droot_dgdg = DiagTree.derivative([droot_dg,], BareGreenId)[1] - # plot_tree(droot_dg) factor = 1 / (2π)^D - DiagTree.eval!(root; eval=(x -> 1.0)) - @test root.weight ≈ (-2 + spin) * factor - - DiagTree.eval!(droot_dg; eval=(x -> 1.0)) - @test droot_dg.weight ≈ (-2 + spin) * 2 * factor - - DiagTree.eval!(droot_dv; eval=(x -> 1.0)) - @test droot_dv.weight ≈ (-2 + spin) * 2 * factor - - DiagTree.eval!(droot_dvdv; eval=(x -> 1.0)) - @test droot_dv.weight ≈ (-2 + spin) * 2 * factor - - DiagTree.eval!(droot_dvdg; eval=(x -> 1.0)) - @test droot_dv.weight ≈ (-2 + spin) * 2 * factor - - DiagTree.eval!(droot_dgdg; eval=(x -> 1.0)) - @test droot_dv.weight ≈ (-2 + spin) * 2 * factor - 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. + propagator_var = Dict(BareGreenId => [true, false], BareInteractionId => [false, true]) # Specify variable dependence of fermi (first element) and bose (second element) particles. t, taylormap = taylorexpansion!(root, propagator_var) 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]) - @test eval!(t.coeffs[[1, 0]], taylorleafmap, taylorleafvec) ≈ droot_dg.weight / taylor_factorial([1, 0]) - @test eval!(t.coeffs[[1, 1]], taylorleafmap, taylorleafvec) ≈ droot_dvdg.weight / taylor_factorial([1, 1]) - @test eval!(t.coeffs[[2, 0]], taylorleafmap, taylorleafvec) ≈ droot_dgdg.weight / taylor_factorial([2, 0]) - @test eval!(t.coeffs[[0, 2]], taylorleafmap, taylorleafvec) ≈ droot_dvdv.weight / taylor_factorial([0, 2]) + @test eval!(t.coeffs[[0, 0]], taylorleafmap, taylorleafvec) ≈ (-2 + spin) * factor + @test eval!(t.coeffs[[0, 1]], taylorleafmap, taylorleafvec) ≈ (-2 + spin) * 2 * factor / taylor_factorial([0, 1]) + @test eval!(t.coeffs[[1, 0]], taylorleafmap, taylorleafvec) ≈ (-2 + spin) * 2 * factor / taylor_factorial([1, 0]) + @test eval!(t.coeffs[[1, 1]], taylorleafmap, taylorleafvec) ≈ (-2 + spin) * 4 * factor / taylor_factorial([1, 1]) + @test eval!(t.coeffs[[2, 0]], taylorleafmap, taylorleafvec) ≈ (-2 + spin) * 4 * factor / taylor_factorial([2, 0]) + @test eval!(t.coeffs[[0, 2]], taylorleafmap, taylorleafvec) ≈ (-2 + spin) * 4 * factor / taylor_factorial([0, 2]) end