diff --git a/.JuliaFormatter.toml b/.JuliaFormatter.toml index e6b5e1f..d43955e 100644 --- a/.JuliaFormatter.toml +++ b/.JuliaFormatter.toml @@ -1,5 +1,5 @@ indent = 4 -margin = 80 +margin = 120 always_for_in = true for_in_replacement = "in" whitespace_typedefs = true diff --git a/docs/src/lib/internals/models.md b/docs/src/lib/internals/models.md index 192b91c..a2537e3 100644 --- a/docs/src/lib/internals/models.md +++ b/docs/src/lib/internals/models.md @@ -1,5 +1,15 @@ # Models +## Interface + +The interface that has to be implemented for a model to be usable is defined in `src/models/interface.jl`. + +```@autodocs +Modules = [MetagraphOptimization] +Pages = ["models/interface.jl"] +Order = [:type, :constant, :function] +``` + ## ABC-Model ### Types diff --git a/examples/import_bench.jl b/examples/import_bench.jl index 64a5000..5143504 100644 --- a/examples/import_bench.jl +++ b/examples/import_bench.jl @@ -13,16 +13,15 @@ function bench_txt(filepath::String, bench::Bool = true) return end + model = ABCModel() + println(name, ":") - g = parse_abc(filepath) + g = parse_dag(filepath, model) print(g) - println( - " Graph size in memory: ", - bytes_to_human_readable(MetagraphOptimization.mem(g)), - ) + println(" Graph size in memory: ", bytes_to_human_readable(MetagraphOptimization.mem(g))) if (bench) - @btime parse_abc($filepath) + @btime parse_dag($filepath, $model) end println(" Get Operations: ") diff --git a/examples/plot_chain.jl b/examples/plot_chain.jl index 4e9cb1c..3b57044 100644 --- a/examples/plot_chain.jl +++ b/examples/plot_chain.jl @@ -12,7 +12,7 @@ function gen_plot(filepath) return end - g = parse_abc(filepath) + g = parse_dag(filepath, ABCModel()) Random.seed!(1) @@ -48,23 +48,10 @@ function gen_plot(filepath) println("\rDone.") - plot( - [x[1], x[2]], - [y[1], y[2]], - linestyle = :solid, - linewidth = 1, - color = :red, - legend = false, - ) + plot([x[1], x[2]], [y[1], y[2]], linestyle = :solid, linewidth = 1, color = :red, legend = false) # Create lines connecting the reference point to each data point for i in 3:length(x) - plot!( - [x[i - 1], x[i]], - [y[i - 1], y[i]], - linestyle = :solid, - linewidth = 1, - color = :red, - ) + plot!([x[i - 1], x[i]], [y[i - 1], y[i]], linestyle = :solid, linewidth = 1, color = :red) end return gui() diff --git a/examples/plot_star.jl b/examples/plot_star.jl index 3f82fb5..8f8ad68 100644 --- a/examples/plot_star.jl +++ b/examples/plot_star.jl @@ -12,7 +12,7 @@ function gen_plot(filepath) return end - g = parse_abc(filepath) + g = parse_dag(filepath, ABCModel()) Random.seed!(1) @@ -60,14 +60,7 @@ function gen_plot(filepath) push!(y, props.computeEffort) pop_operation!(g) - push!( - names, - "NF: (" * - string(props.data) * - ", " * - string(props.computeEffort) * - ")", - ) + push!(names, "NF: (" * string(props.data) * ", " * string(props.computeEffort) * ")") end for op in opt.nodeReductions push_operation!(g, op) @@ -76,14 +69,7 @@ function gen_plot(filepath) push!(y, props.computeEffort) pop_operation!(g) - push!( - names, - "NR: (" * - string(props.data) * - ", " * - string(props.computeEffort) * - ")", - ) + push!(names, "NR: (" * string(props.data) * ", " * string(props.computeEffort) * ")") end for op in opt.nodeSplits push_operation!(g, op) @@ -92,33 +78,13 @@ function gen_plot(filepath) push!(y, props.computeEffort) pop_operation!(g) - push!( - names, - "NS: (" * - string(props.data) * - ", " * - string(props.computeEffort) * - ")", - ) + push!(names, "NS: (" * string(props.data) * ", " * string(props.computeEffort) * ")") end - plot( - [x0, x[1]], - [y0, y[1]], - linestyle = :solid, - linewidth = 1, - color = :red, - legend = false, - ) + plot([x0, x[1]], [y0, y[1]], linestyle = :solid, linewidth = 1, color = :red, legend = false) # Create lines connecting the reference point to each data point for i in 2:length(x) - plot!( - [x0, x[i]], - [y0, y[i]], - linestyle = :solid, - linewidth = 1, - color = :red, - ) + plot!([x0, x[i]], [y0, y[i]], linestyle = :solid, linewidth = 1, color = :red) end #scatter!(x, y, label=names) diff --git a/scripts/bench_threads.fish b/scripts/bench_threads.fish index 28df8c3..5e1ce95 100755 --- a/scripts/bench_threads.fish +++ b/scripts/bench_threads.fish @@ -6,20 +6,20 @@ julia --project=./examples -t 4 -e 'import Pkg; Pkg.instantiate()' #for i in $(seq $minthreads $maxthreads) # printf "(AB->AB, $i) " -# julia --project=./examples -t $i -O3 -e 'using MetagraphOptimization; using BenchmarkTools; @btime get_operations(graph) setup=(graph = parse_abc("input/AB->AB.txt"))' +# julia --project=./examples -t $i -O3 -e 'using MetagraphOptimization; using BenchmarkTools; @btime get_operations(graph) setup=(graph = parse_dag("input/AB->AB.txt"), ABCModel())' #end #for i in $(seq $minthreads $maxthreads) # printf "(AB->ABBB, $i) " -# julia --project=./examples -t $i -O3 -e 'using MetagraphOptimization; using BenchmarkTools; @btime get_operations(graph) setup=(graph = parse_abc("input/AB->ABBB.txt"))' +# julia --project=./examples -t $i -O3 -e 'using MetagraphOptimization; using BenchmarkTools; @btime get_operations(graph) setup=(graph = parse_dag("input/AB->ABBB.txt"), ABCModel())' #end #for i in $(seq $minthreads $maxthreads) # printf "(AB->ABBBBB, $i) " -# julia --project=./examples -t $i -O3 -e 'using MetagraphOptimization; using BenchmarkTools; @btime get_operations(graph) setup=(graph = parse_abc("input/AB->ABBBBB.txt"))' +# julia --project=./examples -t $i -O3 -e 'using MetagraphOptimization; using BenchmarkTools; @btime get_operations(graph) setup=(graph = parse_dag("input/AB->ABBBBB.txt"), ABCModel())' #end for i in $(seq $minthreads $maxthreads) printf "(AB->ABBBBBBB, $i) " - julia --project=./examples -t $i -O3 -e 'using MetagraphOptimization; using BenchmarkTools; @btime get_operations(graph) setup=(graph = parse_abc("input/AB->ABBBBBBB.txt"))' + julia --project=./examples -t $i -O3 -e 'using MetagraphOptimization; using BenchmarkTools; @btime get_operations(graph) setup=(graph = parse_dag("input/AB->ABBBBBBB.txt"), ABCModel())' end diff --git a/src/MetagraphOptimization.jl b/src/MetagraphOptimization.jl index 093536a..29b595d 100644 --- a/src/MetagraphOptimization.jl +++ b/src/MetagraphOptimization.jl @@ -42,7 +42,6 @@ export can_pop export reset_graph! export get_operations -export parse_abc export ComputeTaskP export ComputeTaskS1 export ComputeTaskS2 @@ -51,9 +50,12 @@ export ComputeTaskU export ComputeTaskSum export execute -export gen_particles +export parse_dag, parse_process +export gen_process_input +export get_compute_function export ParticleValue -export Particle +export ParticleA, ParticleB, ParticleC +export ABCProcessDescription, ABCProcessInput, ABCModel export ==, in, show, isempty, delete!, length @@ -114,6 +116,8 @@ include("task/compare.jl") include("task/print.jl") include("task/properties.jl") +include("models/interface.jl") + include("models/abc/types.jl") include("models/abc/particle.jl") include("models/abc/compute.jl") diff --git a/src/code_gen/main.jl b/src/code_gen/main.jl index 56d9734..1aa4cb7 100644 --- a/src/code_gen/main.jl +++ b/src/code_gen/main.jl @@ -3,7 +3,7 @@ using DataStructures """ gen_code(graph::DAG) -Generate the code for a given graph. The return value is a tuple of: +Generate the code for a given graph. The return value is a named tuple of: - `code::Expr`: The julia expression containing the code for the whole graph. - `inputSymbols::Dict{String, Vector{Symbol}}`: A dictionary of symbols mapping the names of the input nodes of the graph to the symbols their inputs should be provided on. @@ -47,85 +47,55 @@ function gen_code(graph::DAG) # node is now the last node we looked at -> the output node outSym = Symbol("data_$(to_var_name(node.id))") - return ( - code = Expr(:block, code...), - inputSymbols = inputSyms, - outputSymbol = outSym, - ) + return (code = Expr(:block, code...), inputSymbols = inputSyms, outputSymbol = outSym) end function gen_input_assignment_code( inputSymbols::Dict{String, Vector{Symbol}}, - inOutCount::Dict{ParticleType, Tuple{Int, Int}}, - functionInputSymbol::Symbol = :input, + processDescription::AbstractProcessDescription, + processInputSymbol::Symbol = :input, ) - @assert !isempty(particles[1]) "Can't have 0 input particles!" - @assert !isempty(particles[2]) "Can't have 0 output particles!" - @assert length(inputSymbols) >= length(particles[1]) + length(particles[2]) - - # TODO none of this is very pretty - in_out_count = Dict{ParticleType, Tuple{Int, Int}}() - for type in types(particles[1][1]) - in_out_count[type] = (0, 0) - end - - # we assume that the particles with lower numbers are the inputs, and then the output particles follow - for p in particles[1] - (i, o) = in_out_count[p.type] - in_out_count[p.type] = (i + 1, o) - end - for p in particles[2] - (i, o) = in_out_count[p.type] - in_out_count[p.type] = (i, o + 1) - end + @assert length(inputSymbols) >= + sum(values(in_particles(processDescription))) + sum(values(out_particles(processDescription))) "Number of input Symbols is smaller than the number of particles in the process description" assignInputs = Vector{Expr}() for (name, symbols) in inputSymbols - type = nothing - if startswith(name, "A") - type = A - elseif startswith(name, "B") - type = B - else - type = C - end + type = type_from_name(name) index = parse(Int, name[2:end]) p = nothing - if (index > in_out_count[type][1]) - index -= in_out_count[type][1] - @assert index <= in_out_count[type][2] "Too few particles of type $type in input particles for this process" + if (index > in_particles(processDescription)[type]) + index -= in_particles(processDescription)[type] + @assert index <= out_particles(processDescription)[type] "Too few particles of type $type in input particles for this process" - p = "$(functionInputSymbol)[2][$(index)]" + p = "filter(x -> typeof(x) <: $type, out_particles($(processInputSymbol)))[$(index)]" else - p = "$(functionInputSymbol)[1][$(index)]" + p = "filter(x -> typeof(x) <: $type, in_particles($(processInputSymbol)))[$(index)]" end for symbol in symbols - push!( - assignInputs, - Meta.parse("$(symbol) = ParticleValue($p, 1.0)"), - ) + push!(assignInputs, Meta.parse("$(symbol) = ParticleValue($p, 1.0)")) end end return Expr(:block, assignInputs...) end +""" + get_compute_function(graph::DAG, process::AbstractProcessDescription) -function get_compute_function( - graph::DAG, - input::Tuple{Vector{Particle}, Vector{Particle}}, -) +Return a function of signature `compute_<id>(input::AbstractProcessInput)`, which will return the result of the DAG computation on the given input. +""" +function get_compute_function(graph::DAG, process::AbstractProcessDescription) (code, inputSymbols, outputSymbol) = gen_code(graph) - assignInputs = gen_input_assignment_code(inputSymbols, input, :input) + assignInputs = gen_input_assignment_code(inputSymbols, process, :input) function_id = to_var_name(UUIDs.uuid1(rng[1])) func = eval( Meta.parse( - "function compute_$(function_id)(input::Tuple{Vector{Particle}, Vector{Particle}}) $assignInputs; $code; return $outputSymbol; end", + "function compute_$(function_id)(input::AbstractProcessInput) $assignInputs; $code; return $outputSymbol; end", ), ) @@ -133,23 +103,20 @@ function get_compute_function( end """ - execute(graph::DAG, input::Dict{ParticleType, Vector{Particle}}) + execute(graph::DAG, process::AbstractProcessDescription, input::AbstractProcessInput) Execute the code of the given `graph` on the given input particles. -The input particles should be sorted correctly into the dictionary to their according [`ParticleType`](@ref)s. This is essentially shorthand for ```julia - graph = parse_abc(input_file) - particles = gen_particles(...) - compute_graph = get_compute_function(graph, particles) + compute_graph = get_compute_function(graph, process) result = compute_graph(particles) ``` -See also: [`gen_particles`](@ref) +See also: [`parse_dag`](@ref), [`parse_process`](@ref), [`gen_process_input`](@ref) """ -function execute(graph::DAG, input::Tuple{Vector{Particle}, Vector{Particle}}) - func = get_compute_function(graph, input) +function execute(graph::DAG, process::AbstractProcessDescription, input::AbstractProcessInput) + func = get_compute_function(graph, process) result = 0 try diff --git a/src/devices/detect.jl b/src/devices/detect.jl index 65d17ed..4b2de4f 100644 --- a/src/devices/detect.jl +++ b/src/devices/detect.jl @@ -26,10 +26,7 @@ function get_machine_info(verbose::Bool = Base.is_interactive()) noDevices = length(devices) @assert noDevices > 0 "No devices were found, but at least one NUMA node should always be available!" - return Machine( - devices, - transferRates::Matrix{Float64}(-1, noDevices, noDevices), - ) + return Machine(devices, transferRates::Matrix{Float64}(-1, noDevices, noDevices)) end """ diff --git a/src/devices/measure.jl b/src/devices/measure.jl index 3c90d61..d1b13e1 100644 --- a/src/devices/measure.jl +++ b/src/devices/measure.jl @@ -3,10 +3,7 @@ Measure FLOPS, RAM, cache sizes and what other properties can be extracted for the devices in the given machine. """ -function measure_devices!( - machine::Machine; - verbose::Bool = Base.is_interactive(), -) +function measure_devices!(machine::Machine; verbose::Bool = Base.is_interactive()) for device in machine.devices measure_device!(device; verbose = verbose) end @@ -19,10 +16,7 @@ end Measure the transfer rates between devices in the machine. """ -function measure_transfer_rates!( - machine::Machine; - verbose::Bool = Base.is_interactive(), -) +function measure_transfer_rates!(machine::Machine; verbose::Bool = Base.is_interactive()) return nothing end diff --git a/src/diff/type.jl b/src/diff/type.jl index 160df83..a12db7d 100644 --- a/src/diff/type.jl +++ b/src/diff/type.jl @@ -5,13 +5,7 @@ A named tuple representing a difference of added and removed nodes and edges on """ const Diff = NamedTuple{ (:addedNodes, :removedNodes, :addedEdges, :removedEdges, :updatedChildren), - Tuple{ - Vector{Node}, - Vector{Node}, - Vector{Edge}, - Vector{Edge}, - Vector{Tuple{Node, String, String}}, - }, + Tuple{Vector{Node}, Vector{Node}, Vector{Edge}, Vector{Edge}, Vector{Tuple{Node, String, String}}}, } function Diff() diff --git a/src/graph/interface.jl b/src/graph/interface.jl index 450419c..0fa74cc 100644 --- a/src/graph/interface.jl +++ b/src/graph/interface.jl @@ -38,8 +38,7 @@ end Return `true` if [`pop_operation!`](@ref) is possible, `false` otherwise. """ -can_pop(graph::DAG) = - !isempty(graph.operationsToApply) || !isempty(graph.appliedOperations) +can_pop(graph::DAG) = !isempty(graph.operationsToApply) || !isempty(graph.appliedOperations) """ reset_graph!(graph::DAG) diff --git a/src/graph/mute.jl b/src/graph/mute.jl index 388bdae..b5af362 100644 --- a/src/graph/mute.jl +++ b/src/graph/mute.jl @@ -15,12 +15,7 @@ Insert the node into the graph. See also: [`remove_node!`](@ref), [`insert_edge!`](@ref), [`remove_edge!`](@ref) """ -function insert_node!( - graph::DAG, - node::Node; - track = true, - invalidate_cache = true, -) +function insert_node!(graph::DAG, node::Node; track = true, invalidate_cache = true) # 1: mute push!(graph.nodes, node) @@ -50,13 +45,7 @@ Insert the edge between node1 (child) and node2 (parent) into the graph. See also: [`insert_node!`](@ref), [`remove_node!`](@ref), [`remove_edge!`](@ref) """ -function insert_edge!( - graph::DAG, - node1::Node, - node2::Node; - track = true, - invalidate_cache = true, -) +function insert_edge!(graph::DAG, node1::Node, node2::Node; track = true, invalidate_cache = true) @assert (node2 ∉ node1.parents) && (node1 ∉ node2.children) "Edge to insert already exists" # 1: mute @@ -95,12 +84,7 @@ Remove the node from the graph. See also: [`insert_node!`](@ref), [`insert_edge!`](@ref), [`remove_edge!`](@ref) """ -function remove_node!( - graph::DAG, - node::Node; - track = true, - invalidate_cache = true, -) +function remove_node!(graph::DAG, node::Node; track = true, invalidate_cache = true) @assert node in graph.nodes "Trying to remove a node that's not in the graph" # 1: mute @@ -134,13 +118,7 @@ Remove the edge between node1 (child) and node2 (parent) into the graph. See also: [`insert_node!`](@ref), [`remove_node!`](@ref), [`insert_edge!`](@ref) """ -function remove_edge!( - graph::DAG, - node1::Node, - node2::Node; - track = true, - invalidate_cache = true, -) +function remove_edge!(graph::DAG, node1::Node, node2::Node; track = true, invalidate_cache = true) # 1: mute pre_length1 = length(node1.parents) pre_length2 = length(node2.children) @@ -197,13 +175,7 @@ function replace_children!(task::AbstractTask, before, after) return nothing end -function update_child!( - graph::DAG, - n::Node, - child_before::String, - child_after::String; - track = true, -) +function update_child!(graph::DAG, n::Node, child_before::String, child_after::String; track = true) # only need to update fused compute tasks if !(typeof(n.task) <: FusedComputeTask) return nothing @@ -212,16 +184,12 @@ function update_child!( replace_children!(n.task, child_before, child_after) if !((child_after in n.task.t1_inputs) || (child_after in n.task.t2_inputs)) - println( - "------------------ Did not replace anything!! ------------------", - ) + println("------------------ Did not replace anything!! ------------------") child_ids = Vector{String}() for child in n.children push!(child_ids, "$(child.id)") end - println( - "From $(child_before) to $(child_after) in $n with children $(child_ids)", - ) + println("From $(child_before) to $(child_after) in $n with children $(child_ids)") @assert false end diff --git a/src/graph/print.jl b/src/graph/print.jl index c7e66e4..5b130e7 100644 --- a/src/graph/print.jl +++ b/src/graph/print.jl @@ -62,9 +62,5 @@ function show(io::IO, graph::DAG) properties = get_properties(graph) println(io, " Total Compute Effort: ", properties.computeEffort) println(io, " Total Data Transfer: ", properties.data) - return println( - io, - " Total Compute Intensity: ", - properties.computeIntensity, - ) + return println(io, " Total Compute Intensity: ", properties.computeIntensity) end diff --git a/src/graph/type.jl b/src/graph/type.jl index 64ef860..6aa8585 100644 --- a/src/graph/type.jl +++ b/src/graph/type.jl @@ -17,7 +17,7 @@ end The representation of the graph as a set of [`Node`](@ref)s. -A DAG can be loaded using the appropriate parse function, e.g. [`parse_abc`](@ref). +A DAG can be loaded using the appropriate parse_dag function, e.g. [`parse_dag`](@ref). [`Operation`](@ref)s can be applied on it using [`push_operation!`](@ref) and reverted using [`pop_operation!`](@ref) like a stack. To get the set of possible operations, use [`get_operations`](@ref). @@ -52,11 +52,7 @@ end Construct and return an empty [`PossibleOperations`](@ref) object. """ function PossibleOperations() - return PossibleOperations( - Set{NodeFusion}(), - Set{NodeReduction}(), - Set{NodeSplit}(), - ) + return PossibleOperations(Set{NodeFusion}(), Set{NodeReduction}(), Set{NodeSplit}()) end """ diff --git a/src/models/abc/compute.jl b/src/models/abc/compute.jl index 62ab319..b92c03d 100644 --- a/src/models/abc/compute.jl +++ b/src/models/abc/compute.jl @@ -45,14 +45,12 @@ For valid inputs, both input particles should have the same momenta at this poin 12 FLOP. """ function compute(::ComputeTaskS2, data1::ParticleValue, data2::ParticleValue) - @assert isapprox( - abs(data1.p.momentum.E), - abs(data2.p.momentum.E), - rtol = 0.001, - ) "E: $(data1.p.momentum.E) vs. $(data2.p.momentum.E)" - @assert isapprox(data1.p.momentum.px, -data2.p.momentum.px, rtol = 0.001) "px: $(data1.p.momentum.px) vs. $(data2.p.momentum.px)" - @assert isapprox(data1.p.momentum.py, -data2.p.momentum.py, rtol = 0.001) "py: $(data1.p.momentum.py) vs. $(data2.p.momentum.py)" - @assert isapprox(data1.p.momentum.pz, -data2.p.momentum.pz, rtol = 0.001) "pz: $(data1.p.momentum.pz) vs. $(data2.p.momentum.pz)" + #= + @assert isapprox(abs(data1.p.momentum.E), abs(data2.p.momentum.E), rtol = 0.001, atol = sqrt(eps())) "E: $(data1.p.momentum.E) vs. $(data2.p.momentum.E)" + @assert isapprox(data1.p.momentum.px, -data2.p.momentum.px, rtol = 0.001, atol = sqrt(eps())) "px: $(data1.p.momentum.px) vs. $(data2.p.momentum.px)" + @assert isapprox(data1.p.momentum.py, -data2.p.momentum.py, rtol = 0.001, atol = sqrt(eps())) "py: $(data1.p.momentum.py) vs. $(data2.p.momentum.py)" + @assert isapprox(data1.p.momentum.pz, -data2.p.momentum.pz, rtol = 0.001, atol = sqrt(eps())) "pz: $(data1.p.momentum.pz) vs. $(data2.p.momentum.pz)" + =# return data1.v * inner_edge(data1.p) * data2.v end @@ -92,11 +90,7 @@ end Generate and return code evaluating [`ComputeTaskP`](@ref) on `inExpr`, providing the output on `outExpr`. """ -function get_expression( - ::ComputeTaskP, - inExprs::Vector{String}, - outExpr::String, -) +function get_expression(::ComputeTaskP, inExprs::Vector{String}, outExpr::String) return Meta.parse("$outExpr = compute(ComputeTaskP(), $(inExprs[1]))") end @@ -106,11 +100,7 @@ end Generate code evaluating [`ComputeTaskU`](@ref) on `inExpr`, providing the output on `outExpr`. `inExpr` should be of type [`ParticleValue`](@ref), `outExpr` will be of type [`ParticleValue`](@ref). """ -function get_expression( - ::ComputeTaskU, - inExprs::Vector{String}, - outExpr::String, -) +function get_expression(::ComputeTaskU, inExprs::Vector{String}, outExpr::String) return Meta.parse("$outExpr = compute(ComputeTaskU(), $(inExprs[1]))") end @@ -120,14 +110,8 @@ end Generate code evaluating [`ComputeTaskV`](@ref) on `inExpr1` and `inExpr2`, providing the output on `outExpr`. `inExpr1` and `inExpr2` should be of type [`ParticleValue`](@ref), `outExpr` will be of type [`ParticleValue`](@ref). """ -function get_expression( - ::ComputeTaskV, - inExprs::Vector{String}, - outExpr::String, -) - return Meta.parse( - "$outExpr = compute(ComputeTaskV(), $(inExprs[1]), $(inExprs[2]))", - ) +function get_expression(::ComputeTaskV, inExprs::Vector{String}, outExpr::String) + return Meta.parse("$outExpr = compute(ComputeTaskV(), $(inExprs[1]), $(inExprs[2]))") end """ @@ -136,14 +120,8 @@ end Generate code evaluating [`ComputeTaskS2`](@ref) on `inExpr1` and `inExpr2`, providing the output on `outExpr`. `inExpr1` and `inExpr2` should be of type [`ParticleValue`](@ref), `outExpr` will be of type `Float64`. """ -function get_expression( - ::ComputeTaskS2, - inExprs::Vector{String}, - outExpr::String, -) - return Meta.parse( - "$outExpr = compute(ComputeTaskS2(), $(inExprs[1]), $(inExprs[2]))", - ) +function get_expression(::ComputeTaskS2, inExprs::Vector{String}, outExpr::String) + return Meta.parse("$outExpr = compute(ComputeTaskS2(), $(inExprs[1]), $(inExprs[2]))") end """ @@ -152,11 +130,7 @@ end Generate code evaluating [`ComputeTaskS1`](@ref) on `inExpr`, providing the output on `outExpr`. `inExpr` should be of type [`ParticleValue`](@ref), `outExpr` will be of type [`ParticleValue`](@ref). """ -function get_expression( - ::ComputeTaskS1, - inExprs::Vector{String}, - outExpr::String, -) +function get_expression(::ComputeTaskS1, inExprs::Vector{String}, outExpr::String) return Meta.parse("$outExpr = compute(ComputeTaskS1(), $(inExprs[1]))") end @@ -166,14 +140,8 @@ end Generate code evaluating [`ComputeTaskSum`](@ref) on `inExprs`, providing the output on `outExpr`. `inExprs` should be of type [`Float64`], `outExpr` will be of type [`Float64`]. """ -function get_expression( - ::ComputeTaskSum, - inExprs::Vector{String}, - outExpr::String, -) - return Meta.parse( - "$outExpr = compute(ComputeTaskSum(), [$(unroll_string_vector(inExprs))])", - ) +function get_expression(::ComputeTaskSum, inExprs::Vector{String}, outExpr::String) + return Meta.parse("$outExpr = compute(ComputeTaskSum(), [$(unroll_string_vector(inExprs))])") end """ @@ -182,19 +150,14 @@ end Generate code evaluating a [`FusedComputeTask`](@ref) on `inExprs`, providing the output on `outExpr`. `inExprs` should be of the correct types and may be heterogeneous. `outExpr` will be of the type of the output of `T2` of t. """ -function get_expression( - t::FusedComputeTask, - inExprs::Vector{String}, - outExpr::String, -) +function get_expression(t::FusedComputeTask, inExprs::Vector{String}, outExpr::String) c1 = length(t.t1_inputs) c2 = length(t.t2_inputs) + 1 expr1 = nothing expr2 = nothing expr1 = get_expression(t.first_task, t.t1_inputs, t.t1_output) - expr2 = - get_expression(t.second_task, [t.t2_inputs..., t.t1_output], outExpr) + expr2 = get_expression(t.second_task, [t.t2_inputs..., t.t1_output], outExpr) full_expr = Expr(:block, expr1, expr2) @@ -208,7 +171,7 @@ Generate and return code for a given [`ComputeTaskNode`](@ref). """ function get_expression(node::ComputeTaskNode) t = typeof(node.task) - @assert length(node.children) == children(node.task) "Node $(node) has inconsistent number of children" + @assert length(node.children) >= children(node.task) "Node $(node) has too few children for its task: node has $(length(node.children)) versus task has $(children(node.task))\nNode's children: $(getfield.(node.children, :children))" if (t <: ComputeTaskU || t <: ComputeTaskP || t <: ComputeTaskS1) # single input symbolIn = "data_$(to_var_name(node.children[1].id))" diff --git a/src/models/abc/create.jl b/src/models/abc/create.jl index 90b2da3..9dc2ca1 100644 --- a/src/models/abc/create.jl +++ b/src/models/abc/create.jl @@ -6,51 +6,61 @@ using ForwardDiff ComputeTaskSum() = ComputeTaskSum(0) """ - gen_particles(in::Vector{ParticleType}, out::Vector{ParticleType}) + gen_process_input(in::Vector{ParticleType}, out::Vector{ParticleType}) -Return a Vector of randomly generated [`Particle`](@ref)s. `in` is the list of particles that enter the process, `out` the list of particles that exit it. Their added momenta will be equal. +Return a ProcessInput of randomly generated [`ABCParticle`](@ref)s from a [`ABCProcessDescription`](@ref). The process description can be created manually or parsed from a string using [`parse_process`](@ref). -Note: This does not take into account the preservation of momenta required for an actual valid process! +Note: This uses RAMBO to create a valid process with conservation of momentum and energy. """ -function gen_particles( - in_particles::Vector{ParticleType}, - out_particles::Vector{ParticleType}, -) - particles = Dict{ParticleType, Vector{Particle}}() - rng = MersenneTwister(0) +function gen_process_input(processDescription::ABCProcessDescription) + inParticleTypes = keys(processDescription.inParticles) + outParticleTypes = keys(processDescription.outParticles) - mass_sum = 0 - input_masses = Vector{Float64}() - for particle in in_particles - mass_sum += mass(particle) - push!(input_masses, mass(particle)) + massSum = 0 + inputMasses = Vector{Float64}() + for (particle, n) in processDescription.inParticles + for _ in 1:n + massSum += mass(particle) + push!(inputMasses, mass(particle)) + end end - output_masses = Vector{Float64}() - for particle in out_particles - mass_sum += mass(particle) - push!(output_masses, mass(particle)) + outputMasses = Vector{Float64}() + for (particle, n) in processDescription.outParticles + for _ in 1:n + massSum += mass(particle) + push!(outputMasses, mass(particle)) + end end # add some extra random mass to allow for some momentum - mass_sum += rand(rng) * (length(in_particles) + length(out_particles)) + massSum += rand(rng[threadid()]) * (length(inputMasses) + length(outputMasses)) - input_particles = Vector{Particle}() - initial_momenta = generate_initial_moms(mass_sum, input_masses) - for (mom, type) in zip(initial_momenta, in_particles) - push!(input_particles, Particle(mom, type)) + inputParticles = Vector{ABCParticle}() + initialMomenta = generate_initial_moms(massSum, inputMasses) + index = 1 + for (particle, n) in processDescription.inParticles + for _ in 1:n + mom = initialMomenta[index] + push!(inputParticles, particle(mom)) + index += 1 + end end - output_particles = Vector{Particle}() - final_momenta = generate_physical_massive_moms(rng, mass_sum, output_masses) - for (mom, type) in zip(final_momenta, out_particles) - push!( - output_particles, - Particle(SFourMomentum(-mom.E, mom.px, mom.py, mom.pz), type), - ) + outputParticles = Vector{ABCParticle}() + final_momenta = generate_physical_massive_moms(rng[threadid()], massSum, outputMasses) + index = 1 + for (particle, n) in processDescription.outParticles + for _ in 1:n + mom = final_momenta[index] + push!(outputParticles, particle(SFourMomentum(-mom.E, mom.px, mom.py, mom.pz))) + index += 1 + end end - return (input_particles, output_particles) + processInput = ABCProcessInput(processDescription, inputParticles, outputParticles) + + return return processInput end #################### @@ -75,12 +85,8 @@ function generate_initial_moms(ss, masses) end -Random.rand(rng::AbstractRNG, ::Random.SamplerType{SFourMomentum}) = - SFourMomentum(rand(rng, 4)) -Random.rand( - rng::AbstractRNG, - ::Random.SamplerType{NTuple{N, Float64}}, -) where {N} = Tuple(rand(rng, N)) +Random.rand(rng::AbstractRNG, ::Random.SamplerType{SFourMomentum}) = SFourMomentum(rand(rng, 4)) +Random.rand(rng::AbstractRNG, ::Random.SamplerType{NTuple{N, Float64}}) where {N} = Tuple(rand(rng, N)) function _transform_uni_to_mom(u1, u2, u3, u4) @@ -109,8 +115,7 @@ function _transform_uni_to_mom!(uni_mom, dest) end _transform_uni_to_mom(u1234::Tuple) = _transform_uni_to_mom(u1234...) -_transform_uni_to_mom(u1234::SFourMomentum) = - _transform_uni_to_mom(Tuple(u1234)) +_transform_uni_to_mom(u1234::SFourMomentum) = _transform_uni_to_mom(Tuple(u1234)) function generate_massless_moms(rng, n::Int) a = Vector{SFourMomentum}(undef, n) diff --git a/src/models/abc/parse.jl b/src/models/abc/parse.jl index 1416115..eeb313a 100644 --- a/src/models/abc/parse.jl +++ b/src/models/abc/parse.jl @@ -32,13 +32,13 @@ function parse_edges(input::AbstractString) end """ - parse_abc(filename::String; verbose::Bool = false) + parse_dag(filename::String, model::ABCModel; verbose::Bool = false) Read an abc-model process from the given file. If `verbose` is set to true, print some progress information to stdout. Returns a valid [`DAG`](@ref). """ -function parse_abc(filename::String, verbose::Bool = false) +function parse_dag(filename::AbstractString, model::ABCModel, verbose::Bool = false) file = open(filename, "r") if (verbose) @@ -63,25 +63,9 @@ function parse_abc(filename::String, verbose::Bool = false) end sizehint!(graph.nodes, estimate_no_nodes) - sum_node = insert_node!( - graph, - make_node(ComputeTaskSum(0)), - track = false, - invalidate_cache = false, - ) - global_data_out = insert_node!( - graph, - make_node(DataTask(FLOAT_SIZE)), - track = false, - invalidate_cache = false, - ) - insert_edge!( - graph, - sum_node, - global_data_out, - track = false, - invalidate_cache = false, - ) + sum_node = insert_node!(graph, make_node(ComputeTaskSum(0)), track = false, invalidate_cache = false) + global_data_out = insert_node!(graph, make_node(DataTask(FLOAT_SIZE)), track = false, invalidate_cache = false) + insert_edge!(graph, sum_node, global_data_out, track = false, invalidate_cache = false) # remember the data out nodes for connection dataOutNodes = Dict() @@ -96,10 +80,7 @@ function parse_abc(filename::String, verbose::Bool = false) noNodes += 1 if (noNodes % 100 == 0) if (verbose) - percent = string( - round(100.0 * noNodes / nodesToRead, digits = 2), - "%", - ) + percent = string(round(100.0 * noNodes / nodesToRead, digits = 2), "%") print("\rReading Nodes... $percent") end end @@ -111,59 +92,17 @@ function parse_abc(filename::String, verbose::Bool = false) track = false, invalidate_cache = false, ) # read particle data node - compute_P = insert_node!( - graph, - make_node(ComputeTaskP()), - track = false, - invalidate_cache = false, - ) # compute P node - data_Pu = insert_node!( - graph, - make_node(DataTask(PARTICLE_VALUE_SIZE)), - track = false, - invalidate_cache = false, - ) # transfer data from P to u (one ParticleValue object) - compute_u = insert_node!( - graph, - make_node(ComputeTaskU()), - track = false, - invalidate_cache = false, - ) # compute U node - data_out = insert_node!( - graph, - make_node(DataTask(PARTICLE_VALUE_SIZE)), - track = false, - invalidate_cache = false, - ) # transfer data out from u (one ParticleValue object) + compute_P = insert_node!(graph, make_node(ComputeTaskP()), track = false, invalidate_cache = false) # compute P node + data_Pu = + insert_node!(graph, make_node(DataTask(PARTICLE_VALUE_SIZE)), track = false, invalidate_cache = false) # transfer data from P to u (one ParticleValue object) + compute_u = insert_node!(graph, make_node(ComputeTaskU()), track = false, invalidate_cache = false) # compute U node + data_out = + insert_node!(graph, make_node(DataTask(PARTICLE_VALUE_SIZE)), track = false, invalidate_cache = false) # transfer data out from u (one ParticleValue object) - insert_edge!( - graph, - data_in, - compute_P, - track = false, - invalidate_cache = false, - ) - insert_edge!( - graph, - compute_P, - data_Pu, - track = false, - invalidate_cache = false, - ) - insert_edge!( - graph, - data_Pu, - compute_u, - track = false, - invalidate_cache = false, - ) - insert_edge!( - graph, - compute_u, - data_out, - track = false, - invalidate_cache = false, - ) + insert_edge!(graph, data_in, compute_P, track = false, invalidate_cache = false) + insert_edge!(graph, compute_P, data_Pu, track = false, invalidate_cache = false) + insert_edge!(graph, data_Pu, compute_u, track = false, invalidate_cache = false) + insert_edge!(graph, compute_u, data_out, track = false, invalidate_cache = false) # remember the data_out node for future edges dataOutNodes[node] = data_out @@ -173,27 +112,13 @@ function parse_abc(filename::String, verbose::Bool = false) in1 = capt.captures[1] in2 = capt.captures[2] - compute_v = insert_node!( - graph, - make_node(ComputeTaskV()), - track = false, - invalidate_cache = false, - ) - data_out = insert_node!( - graph, - make_node(DataTask(PARTICLE_VALUE_SIZE)), - track = false, - invalidate_cache = false, - ) + compute_v = insert_node!(graph, make_node(ComputeTaskV()), track = false, invalidate_cache = false) + data_out = + insert_node!(graph, make_node(DataTask(PARTICLE_VALUE_SIZE)), track = false, invalidate_cache = false) if (occursin(regex_c, in1)) # put an S node after this input - compute_S = insert_node!( - graph, - make_node(ComputeTaskS1()), - track = false, - invalidate_cache = false, - ) + compute_S = insert_node!(graph, make_node(ComputeTaskS1()), track = false, invalidate_cache = false) data_S_v = insert_node!( graph, make_node(DataTask(PARTICLE_VALUE_SIZE)), @@ -201,47 +126,18 @@ function parse_abc(filename::String, verbose::Bool = false) invalidate_cache = false, ) - insert_edge!( - graph, - dataOutNodes[in1], - compute_S, - track = false, - invalidate_cache = false, - ) - insert_edge!( - graph, - compute_S, - data_S_v, - track = false, - invalidate_cache = false, - ) + insert_edge!(graph, dataOutNodes[in1], compute_S, track = false, invalidate_cache = false) + insert_edge!(graph, compute_S, data_S_v, track = false, invalidate_cache = false) - insert_edge!( - graph, - data_S_v, - compute_v, - track = false, - invalidate_cache = false, - ) + insert_edge!(graph, data_S_v, compute_v, track = false, invalidate_cache = false) else - insert_edge!( - graph, - dataOutNodes[in1], - compute_v, - track = false, - invalidate_cache = false, - ) + insert_edge!(graph, dataOutNodes[in1], compute_v, track = false, invalidate_cache = false) end if (occursin(regex_c, in2)) # i think the current generator only puts the combined particles in the first space, so this case might never be entered # put an S node after this input - compute_S = insert_node!( - graph, - make_node(ComputeTaskS1()), - track = false, - invalidate_cache = false, - ) + compute_S = insert_node!(graph, make_node(ComputeTaskS1()), track = false, invalidate_cache = false) data_S_v = insert_node!( graph, make_node(DataTask(PARTICLE_VALUE_SIZE)), @@ -249,45 +145,15 @@ function parse_abc(filename::String, verbose::Bool = false) invalidate_cache = false, ) - insert_edge!( - graph, - dataOutNodes[in2], - compute_S, - track = false, - invalidate_cache = false, - ) - insert_edge!( - graph, - compute_S, - data_S_v, - track = false, - invalidate_cache = false, - ) + insert_edge!(graph, dataOutNodes[in2], compute_S, track = false, invalidate_cache = false) + insert_edge!(graph, compute_S, data_S_v, track = false, invalidate_cache = false) - insert_edge!( - graph, - data_S_v, - compute_v, - track = false, - invalidate_cache = false, - ) + insert_edge!(graph, data_S_v, compute_v, track = false, invalidate_cache = false) else - insert_edge!( - graph, - dataOutNodes[in2], - compute_v, - track = false, - invalidate_cache = false, - ) + insert_edge!(graph, dataOutNodes[in2], compute_v, track = false, invalidate_cache = false) end - insert_edge!( - graph, - compute_v, - data_out, - track = false, - invalidate_cache = false, - ) + insert_edge!(graph, compute_v, data_out, track = false, invalidate_cache = false) dataOutNodes[node] = data_out elseif occursin(regex_m, node) @@ -298,84 +164,23 @@ function parse_abc(filename::String, verbose::Bool = false) in3 = capt.captures[3] # in2 + in3 with a v - compute_v = insert_node!( - graph, - make_node(ComputeTaskV()), - track = false, - invalidate_cache = false, - ) - data_v = insert_node!( - graph, - make_node(DataTask(PARTICLE_VALUE_SIZE)), - track = false, - invalidate_cache = false, - ) + compute_v = insert_node!(graph, make_node(ComputeTaskV()), track = false, invalidate_cache = false) + data_v = + insert_node!(graph, make_node(DataTask(PARTICLE_VALUE_SIZE)), track = false, invalidate_cache = false) - insert_edge!( - graph, - dataOutNodes[in2], - compute_v, - track = false, - invalidate_cache = false, - ) - insert_edge!( - graph, - dataOutNodes[in3], - compute_v, - track = false, - invalidate_cache = false, - ) - insert_edge!( - graph, - compute_v, - data_v, - track = false, - invalidate_cache = false, - ) + insert_edge!(graph, dataOutNodes[in2], compute_v, track = false, invalidate_cache = false) + insert_edge!(graph, dataOutNodes[in3], compute_v, track = false, invalidate_cache = false) + insert_edge!(graph, compute_v, data_v, track = false, invalidate_cache = false) # combine with the v of the combined other input - compute_S2 = insert_node!( - graph, - make_node(ComputeTaskS2()), - track = false, - invalidate_cache = false, - ) - data_out = insert_node!( - graph, - make_node(DataTask(FLOAT_SIZE)), - track = false, - invalidate_cache = false, - ) # output of a S2 task is only a float + compute_S2 = insert_node!(graph, make_node(ComputeTaskS2()), track = false, invalidate_cache = false) + data_out = insert_node!(graph, make_node(DataTask(FLOAT_SIZE)), track = false, invalidate_cache = false) # output of a S2 task is only a float - insert_edge!( - graph, - data_v, - compute_S2, - track = false, - invalidate_cache = false, - ) - insert_edge!( - graph, - dataOutNodes[in1], - compute_S2, - track = false, - invalidate_cache = false, - ) - insert_edge!( - graph, - compute_S2, - data_out, - track = false, - invalidate_cache = false, - ) + insert_edge!(graph, data_v, compute_S2, track = false, invalidate_cache = false) + insert_edge!(graph, dataOutNodes[in1], compute_S2, track = false, invalidate_cache = false) + insert_edge!(graph, compute_S2, data_out, track = false, invalidate_cache = false) - insert_edge!( - graph, - data_out, - sum_node, - track = false, - invalidate_cache = false, - ) + insert_edge!(graph, data_out, sum_node, track = false, invalidate_cache = false) add_child!(sum_node.task) elseif occursin(regex_plus, node) if (verbose) @@ -383,9 +188,7 @@ function parse_abc(filename::String, verbose::Bool = false) println("Added ", length(graph.nodes), " nodes") end else - @assert false ( - "Unknown node '$node' while reading from file $filename" - ) + @assert false ("Unknown node '$node' while reading from file $filename") end end @@ -404,3 +207,36 @@ function parse_abc(filename::String, verbose::Bool = false) # don't actually need to read the edges return graph end + +""" + parse_process(string::AbstractString, model::ABCModel) + +Parse a string representation of a process, such as "AB->ABBB" into the corresponding [`ABCProcessDescription`](@ref). +""" +function parse_process(str::AbstractString, model::ABCModel) + inParticles = Dict{Type, Int}() + outParticles = Dict{Type, Int}() + + if !(contains(str, "->")) + throw("Did not find -> while parsing process \"$str\"") + end + + (inStr, outStr) = split(str, "->") + + if (isempty(inStr) || isempty(outStr)) + throw("Process (\"$str\") input or output part is empty!") + end + + for t in types(model) + inParticles[t] = count(x -> x == String(t)[1], inStr) + outParticles[t] = count(x -> x == String(t)[1], outStr) + end + + if length(inStr) != sum(values(inParticles)) + throw("Encountered unknown characters in the input part of process \"$str\"") + elseif length(outStr) != sum(values(outParticles)) + throw("Encountered unknown characters in the output part of process \"$str\"") + end + + return ABCProcessDescription(inParticles, outParticles) +end diff --git a/src/models/abc/particle.jl b/src/models/abc/particle.jl index 99a7dc4..0527124 100644 --- a/src/models/abc/particle.jl +++ b/src/models/abc/particle.jl @@ -1,108 +1,106 @@ using QEDbase -""" - ParticleType +abstract type ABCParticle <: AbstractParticle end + +struct ABCModel <: AbstractPhysicsModel end + +struct ABCProcessDescription <: AbstractProcessDescription + inParticles::Dict{Type, Int} + outParticles::Dict{Type, Int} +end + +struct ABCProcessInput <: AbstractProcessInput + process::ABCProcessDescription + inParticles::Vector{ABCParticle} + outParticles::Vector{ABCParticle} +end -A Particle Type in the ABC Model as an enum, with types `A`, `B` and `C`. """ -@enum ParticleType A = 1 B = 2 C = 3 + ParticleA <: ABCParticle + +An 'A' particle in the ABC Model. +""" +struct ParticleA <: ABCParticle + momentum::SFourMomentum +end + +struct ParticleB <: ABCParticle + momentum::SFourMomentum +end + +struct ParticleC <: ABCParticle + momentum::SFourMomentum +end """ PARTICLE_MASSES A constant dictionary containing the masses of the different [`ParticleType`](@ref)s. """ -const PARTICLE_MASSES = - Dict{ParticleType, Float64}(A => 1.0, B => 1.0, C => 0.0) +const PARTICLE_MASSES = Dict{Type, Float64}(ParticleA => 1.0, ParticleB => 1.0, ParticleC => 0.0) """ - Particle - -A struct describing a particle of the ABC-Model. It has the 4 momentum of the particle and a [`ParticleType`](@ref). - -`sizeof(Particle())` = 40 Byte -""" -struct Particle - # SFourMomentum - momentum::SFourMomentum - - type::ParticleType -end - -""" - ParticleValue - -A struct describing a particle during a calculation of a Feynman Diagram, together with the value that's being calculated. - -`sizeof(ParticleValue())` = 48 Byte -""" -struct ParticleValue - p::Particle - v::Float64 -end - -""" - mass(t::ParticleType) + mass(t::Type{T}) where {T <: ABCParticle} Return the mass (at rest) of the given particle type. """ -mass(t::ParticleType) = PARTICLE_MASSES[t] +mass(t::Type{T}) where {T <: ABCParticle} = PARTICLE_MASSES[t] """ - remaining_type(t1::ParticleType, t2::ParticleType) + interaction_result(t1::Type{T1}, t2::Type{T2}) where {T1 <: ABCParticle, T2 <: ABCParticle} For 2 given (non-equal) particle types, return the third of ABC. """ -function remaining_type(t1::ParticleType, t2::ParticleType) +function interaction_result(t1::Type{T1}, t2::Type{T2}) where {T1 <: ABCParticle, T2 <: ABCParticle} @assert t1 != t2 - if t1 != A && t2 != A - return A - elseif t1 != B && t2 != B - return B + if t1 != Type{ParticleA} && t2 != Type{ParticleA} + return ParticleA + elseif t1 != Type{ParticleB} && t2 != Type{ParticleB} + return ParticleB else - return C + return ParticleC end end """ - types(::Particle) + types(::ABCModel) -Return a Vector of the possible [`ParticleType`](@ref)s of this [`Particle`](@ref). +Return a Vector of the possible types of particle in the [`ABCModel`](@ref). """ -function types(::Particle) - return [A, B, C] +function types(::ABCModel) + return [ParticleA, ParticleB, ParticleC] end """ - square(p::Particle) + square(p::ABCParticle) Return the square of the particle's momentum as a `Float` value. Takes 7 effective FLOP. """ -function square(p::Particle) +function square(p::ABCParticle) return getMass2(p.momentum) end """ - inner_edge(p::Particle) + inner_edge(p::ABCParticle) Return the factor of the inner edge with the given (virtual) particle. Takes 10 effective FLOP. (3 here + 7 in square(p)) """ -function inner_edge(p::Particle) - return 1.0 / (square(p) - mass(p.type) * mass(p.type)) +function inner_edge(p::ABCParticle) + return 1.0 / (square(p) - mass(typeof(p)) * mass(typeof(p))) end """ - outer_edge(p::Particle) + outer_edge(p::ABCParticle) Return the factor of the outer edge with the given (real) particle. Takes 0 effective FLOP. """ -function outer_edge(p::Particle) +function outer_edge(p::ABCParticle) return 1.0 end @@ -120,14 +118,15 @@ function vertex() end """ - preserve_momentum(p1::Particle, p2::Particle) + preserve_momentum(p1::ABCParticle, p2::ABCParticle) Calculate and return a new particle from two given interacting ones at a vertex. Takes 4 effective FLOP. """ -function preserve_momentum(p1::Particle, p2::Particle) - p3 = Particle(p1.momentum + p2.momentum, remaining_type(p1.type, p2.type)) +function preserve_momentum(p1::ABCParticle, p2::ABCParticle) + t3 = interaction_result(typeof(p1), typeof(p2)) + p3 = t3(p1.momentum + p2.momentum) return p3 end @@ -135,16 +134,42 @@ end """ type_from_name(name::String) -For a name of a particle, return the [`ParticleType`]. +For a name of a particle, return the particle's [`Type`]. """ function type_from_name(name::String) if startswith(name, "A") - return A + return ParticleA elseif startswith(name, "B") - return B + return ParticleB elseif startswith(name, "C") - return C + return ParticleC else throw("Invalid name for a particle in the ABC model") end end + +function String(::Type{ParticleA}) + return "A" +end +function String(::Type{ParticleB}) + return "B" +end +function String(::Type{ParticleC}) + return "C" +end + +function in_particles(process::ABCProcessDescription) + return process.inParticles +end + +function in_particles(input::ABCProcessInput) + return input.inParticles +end + +function out_particles(process::ABCProcessDescription) + return process.outParticles +end + +function out_particles(input::ABCProcessInput) + return input.outParticles +end diff --git a/src/models/abc/types.jl b/src/models/abc/types.jl index 2f917cb..e9e6ee9 100644 --- a/src/models/abc/types.jl +++ b/src/models/abc/types.jl @@ -56,12 +56,4 @@ end Constant vector of all tasks of the ABC-Model. """ -ABC_TASKS = [ - DataTask, - ComputeTaskS1, - ComputeTaskS2, - ComputeTaskP, - ComputeTaskV, - ComputeTaskU, - ComputeTaskSum, -] +ABC_TASKS = [DataTask, ComputeTaskS1, ComputeTaskS2, ComputeTaskP, ComputeTaskV, ComputeTaskU, ComputeTaskSum] diff --git a/src/models/interface.jl b/src/models/interface.jl new file mode 100644 index 0000000..3297f4c --- /dev/null +++ b/src/models/interface.jl @@ -0,0 +1,109 @@ + +""" + AbstractPhysicsModel + +Base type for a model, e.g. ABC-Model or QED. This is used to dispatch many functions. +""" +abstract type AbstractPhysicsModel end + +""" + AbstractParticle + +Base type for particles belonging to a certain [`AbstractPhysicsModel`](@ref). +""" +abstract type AbstractParticle end + +""" + ParticleValue{ParticleType <: AbstractParticle} + +A struct describing a particle during a calculation of a Feynman Diagram, together with the value that's being calculated. + +`sizeof(ParticleValue())` = 48 Byte +""" +struct ParticleValue{ParticleType <: AbstractParticle} + p::ParticleType + v::Float64 +end + +""" + AbstractProcessDescription + +Base type for process descriptions. An object of this type of a corresponding [`AbstractPhysicsModel`](@ref) should uniquely identify a process in that model. + +See also: [`parse_process`](@ref) +""" +abstract type AbstractProcessDescription end + +""" + AbstractProcessInput + +Base type for process inputs. An object of this type contains the input values (e.g. momenta) of the particles in a process. + +See also: [`gen_process_input`](@ref) +""" +abstract type AbstractProcessInput end + +""" + mass(t::Type{T}) where {T <: AbstractParticle} + +Interface function that must be implemented for every subtype of [`AbstractParticle`](@ref), returning the particles mass at rest. +""" +function mass end + +""" + interaction_result(t1::Type{T1}, t2::Type{T2}) where {T1 <: AbstractParticle, T2 <: AbstractParticle} + +Interface function that must be implemented for every subtype of [`AbstractParticle`](@ref), returning the result particle type when the two given particles interact. +""" +function interaction_result end + +""" + types(::AbstractPhysicsModel) + +Interface function that must be implemented for every subtype of [`AbstractPhysicsModel`](@ref), returning a `Vector` of the available particle types in the model. +""" +function types end + +""" + in_particles(::AbstractProcessDescription) + +Interface function that must be implemented for every subtype of [`AbstractProcessDescription`](@ref). +Returns a `<: Dict{Type{AbstractParticle}, Int}` object, representing the number of ingoing particles for the process per particle type. + + + in_particles(::AbstractProcessInput) + +Interface function that must be implemented for every subtype of [`AbstractProcessInput`](@ref). +Returns a `<: Vector{AbstractParticle}` object with the values of all ingoing particles for the corresponding `ProcessDescription`. +""" +function in_particles end + +""" + out_particles(::AbstractProcessDescription) + +Interface function that must be implemented for every subtype of [`AbstractProcessDescription`](@ref). +Returns a `<: Dict{Type{AbstractParticle}, Int}` object, representing the number of outgoing particles for the process per particle type. + + + out_particles(::AbstractProcessInput) + +Interface function that must be implemented for every subtype of [`AbstractProcessInput`](@ref). +Returns a `<: Vector{AbstractParticle}` object with the values of all outgoing particles for the corresponding `ProcessDescription`. +""" +function out_particles end + +""" + parse_process(::AbstractString, ::AbstractPhysicsModel) + +Interface function that must be implemented for every subtype of [`AbstractPhysicsModel`](@ref). +Returns a `ProcessDescription` object. +""" +function parse_process end + +""" + gen_process_input(::AbstractProcessDescription) + +Interface function that must be implemented for every specific [`AbstractProcessDescription`](@ref). +Returns a randomly generated and valid corresponding `ProcessInput`. +""" +function gen_process_input end diff --git a/src/node/create.jl b/src/node/create.jl index 524acaf..ee8682e 100644 --- a/src/node/create.jl +++ b/src/node/create.jl @@ -1,14 +1,6 @@ -DataTaskNode(t::AbstractDataTask, name = "") = DataTaskNode( - t, - Vector{Node}(), - Vector{Node}(), - UUIDs.uuid1(rng[threadid()]), - missing, - missing, - missing, - name, -) +DataTaskNode(t::AbstractDataTask, name = "") = + DataTaskNode(t, Vector{Node}(), Vector{Node}(), UUIDs.uuid1(rng[threadid()]), missing, missing, missing, name) ComputeTaskNode(t::AbstractComputeTask) = ComputeTaskNode( t, Vector{Node}(), diff --git a/src/node/type.jl b/src/node/type.jl index 06bf308..2fe028a 100644 --- a/src/node/type.jl +++ b/src/node/type.jl @@ -95,8 +95,5 @@ The child is the prerequisite node of the parent. """ struct Edge # edge points from child to parent - edge::Union{ - Tuple{DataTaskNode, ComputeTaskNode}, - Tuple{ComputeTaskNode, DataTaskNode}, - } + edge::Union{Tuple{DataTaskNode, ComputeTaskNode}, Tuple{ComputeTaskNode, DataTaskNode}} end diff --git a/src/operation/apply.jl b/src/operation/apply.jl index 1df19fd..87bea22 100644 --- a/src/operation/apply.jl +++ b/src/operation/apply.jl @@ -34,12 +34,7 @@ Apply the given [`NodeFusion`](@ref) to the graph. Generic wrapper around [`node Return an [`AppliedNodeFusion`](@ref) object generated from the graph's [`Diff`](@ref). """ function apply_operation!(graph::DAG, operation::NodeFusion) - diff = node_fusion!( - graph, - operation.input[1], - operation.input[2], - operation.input[3], - ) + diff = node_fusion!(graph, operation.input[1], operation.input[2], operation.input[3]) graph.properties += GraphProperties(diff) @@ -156,12 +151,7 @@ Fuse nodes n1 -> n2 -> n3 together into one node, return the applied difference For details see [`NodeFusion`](@ref). """ -function node_fusion!( - graph::DAG, - n1::ComputeTaskNode, - n2::DataTaskNode, - n3::ComputeTaskNode, -) +function node_fusion!(graph::DAG, n1::ComputeTaskNode, n2::DataTaskNode, n3::ComputeTaskNode) @assert is_valid_node_fusion_input(graph, n1, n2, n3) # clear snapshot @@ -193,15 +183,7 @@ function node_fusion!( end # create new node with the fused compute task - new_node = ComputeTaskNode( - FusedComputeTask( - n1.task, - n3.task, - n1_inputs, - "data_$(to_var_name(n2.id))", - n3_inputs, - ), - ) + new_node = ComputeTaskNode(FusedComputeTask(n1.task, n3.task, n1_inputs, "data_$(to_var_name(n2.id))", n3_inputs)) insert_node!(graph, new_node) for child in n1_children @@ -222,12 +204,7 @@ function node_fusion!( # important! update the parent node's child names in case they are fused compute tasks # needed for compute generation so the fused compute task can correctly match inputs to its component tasks - update_child!( - graph, - parent, - "data_$(to_var_name(n3.id))", - "data_$(to_var_name(new_node.id))", - ) + update_child!(graph, parent, "data_$(to_var_name(n3.id))", "data_$(to_var_name(new_node.id))") end return get_snapshot_diff(graph) @@ -327,12 +304,7 @@ function node_split!(graph::DAG, n1::Node) insert_edge!(graph, child, n_copy) end - update_child!( - graph, - parent, - "data_$(to_var_name(n1.id))", - "data_$(to_var_name(n_copy.id))", - ) + update_child!(graph, parent, "data_$(to_var_name(n1.id))", "data_$(to_var_name(n_copy.id))") end return get_snapshot_diff(graph) diff --git a/src/operation/find.jl b/src/operation/find.jl index 89acc3a..f6d6218 100644 --- a/src/operation/find.jl +++ b/src/operation/find.jl @@ -7,10 +7,7 @@ using Base.Threads Insert the given node fusion into its input nodes' operation caches. For the compute nodes, locking via the given `locks` is employed to have safe multi-threading. For a large set of nodes, contention on the locks should be very small. """ -function insert_operation!( - nf::NodeFusion, - locks::Dict{ComputeTaskNode, SpinLock}, -) +function insert_operation!(nf::NodeFusion, locks::Dict{ComputeTaskNode, SpinLock}) n1 = nf.input[1] n2 = nf.input[2] n3 = nf.input[3] @@ -52,10 +49,7 @@ end Insert the node reductions into the graph and the nodes' caches. Employs multithreading for speedup. """ -function nr_insertion!( - operations::PossibleOperations, - nodeReductions::Vector{Vector{NodeReduction}}, -) +function nr_insertion!(operations::PossibleOperations, nodeReductions::Vector{Vector{NodeReduction}}) total_len = 0 for vec in nodeReductions total_len += length(vec) @@ -83,11 +77,7 @@ end Insert the node fusions into the graph and the nodes' caches. Employs multithreading for speedup. """ -function nf_insertion!( - graph::DAG, - operations::PossibleOperations, - nodeFusions::Vector{Vector{NodeFusion}}, -) +function nf_insertion!(graph::DAG, operations::PossibleOperations, nodeFusions::Vector{Vector{NodeFusion}}) total_len = 0 for vec in nodeFusions total_len += length(vec) @@ -122,10 +112,7 @@ end Insert the node splits into the graph and the nodes' caches. Employs multithreading for speedup. """ -function ns_insertion!( - operations::PossibleOperations, - nodeSplits::Vector{Vector{NodeSplit}}, -) +function ns_insertion!(operations::PossibleOperations, nodeSplits::Vector{Vector{NodeSplit}}) total_len = 0 for vec in nodeSplits total_len += length(vec) @@ -231,16 +218,12 @@ function generate_operations(graph::DAG) continue end - push!( - generatedFusions[threadid()], - NodeFusion((child_node, node, parent_node)), - ) + push!(generatedFusions[threadid()], NodeFusion((child_node, node, parent_node))) end end # launch thread for node fusion insertion - nf_task = - @task nf_insertion!(graph, graph.possibleOperations, generatedFusions) + nf_task = @task nf_insertion!(graph, graph.possibleOperations, generatedFusions) schedule(nf_task) # find possible node splits diff --git a/src/operation/utility.jl b/src/operation/utility.jl index 2c1bae5..b7f874a 100644 --- a/src/operation/utility.jl +++ b/src/operation/utility.jl @@ -4,9 +4,7 @@ Return whether `operations` is empty, i.e. all of its fields are empty. """ function isempty(operations::PossibleOperations) - return isempty(operations.nodeFusions) && - isempty(operations.nodeReductions) && - isempty(operations.nodeSplits) + return isempty(operations.nodeFusions) && isempty(operations.nodeReductions) && isempty(operations.nodeSplits) end """ @@ -63,9 +61,7 @@ function can_fuse(n1::ComputeTaskNode, n2::DataTaskNode, n3::ComputeTaskNode) return false end - if length(n2.parents) != 1 || - length(n2.children) != 1 || - length(n1.parents) != 1 + if length(n2.parents) != 1 || length(n2.children) != 1 || length(n1.parents) != 1 return false end diff --git a/src/operation/validate.jl b/src/operation/validate.jl index 528d8be..a065032 100644 --- a/src/operation/validate.jl +++ b/src/operation/validate.jl @@ -9,24 +9,12 @@ Assert for a gven node fusion input whether the nodes can be fused. For the requ Intended for use with `@assert` or `@test`. """ -function is_valid_node_fusion_input( - graph::DAG, - n1::ComputeTaskNode, - n2::DataTaskNode, - n3::ComputeTaskNode, -) +function is_valid_node_fusion_input(graph::DAG, n1::ComputeTaskNode, n2::DataTaskNode, n3::ComputeTaskNode) if !(n1 in graph) || !(n2 in graph) || !(n3 in graph) - throw( - AssertionError( - "[Node Fusion] The given nodes are not part of the given graph", - ), - ) + throw(AssertionError("[Node Fusion] The given nodes are not part of the given graph")) end - if !is_child(n1, n2) || - !is_child(n2, n3) || - !is_parent(n3, n2) || - !is_parent(n2, n1) + if !is_child(n1, n2) || !is_child(n2, n3) || !is_parent(n3, n2) || !is_parent(n2, n1) throw( AssertionError( "[Node Fusion] The given nodes are not connected by edges which is required for node fusion", @@ -35,25 +23,13 @@ function is_valid_node_fusion_input( end if length(n2.parents) > 1 - throw( - AssertionError( - "[Node Fusion] The given data node has more than one parent", - ), - ) + throw(AssertionError("[Node Fusion] The given data node has more than one parent")) end if length(n2.children) > 1 - throw( - AssertionError( - "[Node Fusion] The given data node has more than one child", - ), - ) + throw(AssertionError("[Node Fusion] The given data node has more than one child")) end if length(n1.parents) > 1 - throw( - AssertionError( - "[Node Fusion] The given n1 has more than one parent", - ), - ) + throw(AssertionError("[Node Fusion] The given n1 has more than one parent")) end return true @@ -69,31 +45,19 @@ Intended for use with `@assert` or `@test`. function is_valid_node_reduction_input(graph::DAG, nodes::Vector{Node}) for n in nodes if n ∉ graph - throw( - AssertionError( - "[Node Reduction] The given nodes are not part of the given graph", - ), - ) + throw(AssertionError("[Node Reduction] The given nodes are not part of the given graph")) end end t = typeof(nodes[1].task) for n in nodes if typeof(n.task) != t - throw( - AssertionError( - "[Node Reduction] The given nodes are not of the same type", - ), - ) + throw(AssertionError("[Node Reduction] The given nodes are not of the same type")) end if (typeof(n) <: DataTaskNode) if (n.name != nodes[1].name) - throw( - AssertionError( - "[Node Reduction] The given nodes do not have the same name", - ), - ) + throw(AssertionError("[Node Reduction] The given nodes do not have the same name")) end end end @@ -121,11 +85,7 @@ Intended for use with `@assert` or `@test`. """ function is_valid_node_split_input(graph::DAG, n1::Node) if n1 ∉ graph - throw( - AssertionError( - "[Node Split] The given node is not part of the given graph", - ), - ) + throw(AssertionError("[Node Split] The given node is not part of the given graph")) end if length(n1.parents) <= 1 @@ -173,12 +133,7 @@ Assert for a given [`NodeFusion`](@ref) whether it is a valid operation in the g Intended for use with `@assert` or `@test`. """ function is_valid(graph::DAG, nf::NodeFusion) - @assert is_valid_node_fusion_input( - graph, - nf.input[1], - nf.input[2], - nf.input[3], - ) + @assert is_valid_node_fusion_input(graph, nf.input[1], nf.input[2], nf.input[3]) @assert nf in graph.possibleOperations.nodeFusions "NodeFusion is not part of the graph's possible operations!" return true end diff --git a/src/properties/utility.jl b/src/properties/utility.jl index bf936db..3aa9def 100644 --- a/src/properties/utility.jl +++ b/src/properties/utility.jl @@ -11,8 +11,7 @@ function -(prop1::GraphProperties, prop2::GraphProperties) computeIntensity = if (prop1.data - prop2.data == 0) 0.0 else - (prop1.computeEffort - prop2.computeEffort) / - (prop1.data - prop2.data) + (prop1.computeEffort - prop2.computeEffort) / (prop1.data - prop2.data) end, cost = prop1.cost - prop2.cost, noNodes = prop1.noNodes - prop2.noNodes, @@ -33,8 +32,7 @@ function +(prop1::GraphProperties, prop2::GraphProperties) computeIntensity = if (prop1.data + prop2.data == 0) 0.0 else - (prop1.computeEffort + prop2.computeEffort) / - (prop1.data + prop2.data) + (prop1.computeEffort + prop2.computeEffort) / (prop1.data + prop2.data) end, cost = prop1.cost + prop2.cost, noNodes = prop1.noNodes + prop2.noNodes, diff --git a/src/task/create.jl b/src/task/create.jl index acbd128..81dc564 100644 --- a/src/task/create.jl +++ b/src/task/create.jl @@ -3,8 +3,7 @@ Fallback implementation of the copy of an abstract data task, throwing an error. """ -copy(t::AbstractDataTask) = - error("Need to implement copying for your data tasks!") +copy(t::AbstractDataTask) = error("Need to implement copying for your data tasks!") """ copy(t::AbstractComputeTask) @@ -28,9 +27,5 @@ function copy(t::FusedComputeTask{T1, T2}) where {T1, T2} ) end -FusedComputeTask{T1, T2}( - t1_inputs::Vector{String}, - t1_output::String, - t2_inputs::Vector{String}, -) where {T1, T2} = +FusedComputeTask{T1, T2}(t1_inputs::Vector{String}, t1_output::String, t2_inputs::Vector{String}) where {T1, T2} = FusedComputeTask{T1, T2}(T1(), T2(), t1_inputs, t1_output, t2_inputs) diff --git a/src/task/type.jl b/src/task/type.jl index 3b922c0..1bde12c 100644 --- a/src/task/type.jl +++ b/src/task/type.jl @@ -26,8 +26,7 @@ A fused compute task made up of the computation of first `T1` and then `T2`. Also see: [`get_types`](@ref). """ -struct FusedComputeTask{T1 <: AbstractComputeTask, T2 <: AbstractComputeTask} <: - AbstractComputeTask +struct FusedComputeTask{T1 <: AbstractComputeTask, T2 <: AbstractComputeTask} <: AbstractComputeTask first_task::T1 second_task::T2 # the names of the inputs for T1 diff --git a/test/known_graphs.jl b/test/known_graphs.jl index de81c12..6afbf9f 100644 --- a/test/known_graphs.jl +++ b/test/known_graphs.jl @@ -2,7 +2,7 @@ using Random function test_known_graph(name::String, n, fusion_test = true) @testset "Test $name Graph ($n)" begin - graph = parse_abc(joinpath(@__DIR__, "..", "input", "$name.txt")) + graph = parse_dag(joinpath(@__DIR__, "..", "input", "$name.txt"), ABCModel()) props = get_properties(graph) if (fusion_test) diff --git a/test/unit_tests_execution.jl b/test/unit_tests_execution.jl index 71ebeaf..9fa5cd5 100644 --- a/test/unit_tests_execution.jl +++ b/test/unit_tests_execution.jl @@ -1,93 +1,73 @@ -import MetagraphOptimization.A -import MetagraphOptimization.B -import MetagraphOptimization.ParticleType +import MetagraphOptimization.ABCParticle using QEDbase include("../examples/profiling_utilities.jl") @testset "Unit Tests Execution" begin - particles_2_2 = Tuple{Vector{Particle}, Vector{Particle}}(( - [ - Particle(SFourMomentum(0.823648, 0.0, 0.0, 0.823648), A), - Particle(SFourMomentum(0.823648, 0.0, 0.0, -0.823648), B), - ], - [ - Particle( - SFourMomentum(0.823648, -0.835061, -0.474802, 0.277915), - A, - ), - Particle(SFourMomentum(0.823648, 0.835061, 0.474802, -0.277915), B), - ], - )) + process_2_2 = ABCProcessDescription( + Dict{Type, Int64}(ParticleA => 1, ParticleB => 1), + Dict{Type, Int64}(ParticleA => 1, ParticleB => 1), + ) - expected_result = 5.5320505145845555e-5 + particles_2_2 = ABCProcessInput( + process_2_2, + ABCParticle[ + ParticleA(SFourMomentum(0.823648, 0.0, 0.0, 0.823648)), + ParticleB(SFourMomentum(0.823648, 0.0, 0.0, -0.823648)), + ], + ABCParticle[ + ParticleA(SFourMomentum(0.823648, -0.835061, -0.474802, 0.277915)), + ParticleB(SFourMomentum(0.823648, 0.835061, 0.474802, -0.277915)), + ], + ) + expected_result = 0.00013916495566048735 @testset "AB->AB no optimization" begin for _ in 1:10 # test in a loop because graph layout should not change the result - graph = parse_abc(joinpath(@__DIR__, "..", "input", "AB->AB.txt")) - @test isapprox( - execute(graph, particles_2_2), - expected_result; - rtol = 0.001, - ) + graph = parse_dag(joinpath(@__DIR__, "..", "input", "AB->AB.txt"), ABCModel()) + @test isapprox(execute(graph, process_2_2, particles_2_2), expected_result; rtol = 0.001) - #=code = MetagraphOptimization.gen_code(graph) - @test isapprox( - execute(code, particles_2_2), - expected_result; - rtol = 0.001, - )=# + func = get_compute_function(graph, process_2_2) + @test isapprox(func(particles_2_2), expected_result; rtol = 0.001) end end @testset "AB->AB after random walk" begin for i in 1:100 - graph = parse_abc(joinpath(@__DIR__, "..", "input", "AB->AB.txt")) + graph = parse_dag(joinpath(@__DIR__, "..", "input", "AB->AB.txt"), ABCModel()) random_walk!(graph, 50) @test is_valid(graph) - @test isapprox( - execute(graph, particles_2_2), - expected_result; - rtol = 0.001, - ) + @test isapprox(execute(graph, process_2_2, particles_2_2), expected_result; rtol = 0.001) end end - particles_2_4 = gen_particles([A, B], [A, B, B, B]) - graph = parse_abc(joinpath(@__DIR__, "..", "input", "AB->ABBB.txt")) - expected_result = execute(graph, particles_2_4) + process_2_4 = ABCProcessDescription( + Dict{Type, Int64}(ParticleA => 1, ParticleB => 1), + Dict{Type, Int64}(ParticleA => 1, ParticleB => 3), + ) + particles_2_4 = gen_process_input(process_2_4) + graph = parse_dag(joinpath(@__DIR__, "..", "input", "AB->ABBB.txt"), ABCModel()) + expected_result = execute(graph, process_2_4, particles_2_4) @testset "AB->ABBB no optimization" begin for _ in 1:5 # test in a loop because graph layout should not change the result - graph = parse_abc(joinpath(@__DIR__, "..", "input", "AB->ABBB.txt")) - @test isapprox( - execute(graph, particles_2_4), - expected_result; - rtol = 0.001, - ) + graph = parse_dag(joinpath(@__DIR__, "..", "input", "AB->ABBB.txt"), ABCModel()) + @test isapprox(execute(graph, process_2_4, particles_2_4), expected_result; rtol = 0.001) - #=code = MetagraphOptimization.gen_code(graph) - @test isapprox( - execute(code, particles_2_4), - expected_result; - rtol = 0.001, - )=# + func = get_compute_function(graph, process_2_4) + @test isapprox(func(particles_2_4), expected_result; rtol = 0.001) end end @testset "AB->ABBB after random walk" begin for i in 1:20 - graph = parse_abc(joinpath(@__DIR__, "..", "input", "AB->ABBB.txt")) + graph = parse_dag(joinpath(@__DIR__, "..", "input", "AB->ABBB.txt"), ABCModel()) random_walk!(graph, 100) @test is_valid(graph) - @test isapprox( - execute(graph, particles_2_4), - expected_result; - rtol = 0.001, - ) + @test isapprox(execute(graph, process_2_4, particles_2_4), expected_result; rtol = 0.001) end end diff --git a/test/unit_tests_graph.jl b/test/unit_tests_graph.jl index cab3305..bab3155 100644 --- a/test/unit_tests_graph.jl +++ b/test/unit_tests_graph.jl @@ -11,10 +11,8 @@ import MetagraphOptimization.partners @test length(graph.appliedOperations) == 0 @test length(graph.operationsToApply) == 0 @test length(graph.dirtyNodes) == 0 - @test length(graph.diff) == - (addedNodes = 0, removedNodes = 0, addedEdges = 0, removedEdges = 0) - @test length(get_operations(graph)) == - (nodeFusions = 0, nodeReductions = 0, nodeSplits = 0) + @test length(graph.diff) == (addedNodes = 0, removedNodes = 0, addedEdges = 0, removedEdges = 0) + @test length(get_operations(graph)) == (nodeFusions = 0, nodeReductions = 0, nodeSplits = 0) # s to output (exit node) d_exit = insert_node!(graph, make_node(DataTask(10)), track = false) @@ -107,8 +105,7 @@ import MetagraphOptimization.partners @test length(graph.appliedOperations) == 0 @test length(graph.operationsToApply) == 0 @test length(graph.dirtyNodes) == 26 - @test length(graph.diff) == - (addedNodes = 0, removedNodes = 0, addedEdges = 0, removedEdges = 0) + @test length(graph.diff) == (addedNodes = 0, removedNodes = 0, addedEdges = 0, removedEdges = 0) @test is_valid(graph) @@ -135,8 +132,7 @@ import MetagraphOptimization.partners @test length(siblings(s0)) == 1 operations = get_operations(graph) - @test length(operations) == - (nodeFusions = 10, nodeReductions = 0, nodeSplits = 0) + @test length(operations) == (nodeFusions = 10, nodeReductions = 0, nodeSplits = 0) @test length(graph.dirtyNodes) == 0 @test operations == get_operations(graph) @@ -157,8 +153,7 @@ import MetagraphOptimization.partners @test length(graph.operationsToApply) == 1 @test first(graph.operationsToApply) == nf @test length(graph.dirtyNodes) == 0 - @test length(graph.diff) == - (addedNodes = 0, removedNodes = 0, addedEdges = 0, removedEdges = 0) + @test length(graph.diff) == (addedNodes = 0, removedNodes = 0, addedEdges = 0, removedEdges = 0) # this applies pending operations properties = get_properties(graph) @@ -176,8 +171,7 @@ import MetagraphOptimization.partners operations = get_operations(graph) @test length(graph.dirtyNodes) == 0 - @test length(operations) == - (nodeFusions = 9, nodeReductions = 0, nodeSplits = 0) + @test length(operations) == (nodeFusions = 9, nodeReductions = 0, nodeSplits = 0) @test !isempty(operations) possibleNF = 9 @@ -185,14 +179,12 @@ import MetagraphOptimization.partners push_operation!(graph, first(operations.nodeFusions)) operations = get_operations(graph) possibleNF = possibleNF - 1 - @test length(operations) == - (nodeFusions = possibleNF, nodeReductions = 0, nodeSplits = 0) + @test length(operations) == (nodeFusions = possibleNF, nodeReductions = 0, nodeSplits = 0) end @test isempty(operations) - @test length(operations) == - (nodeFusions = 0, nodeReductions = 0, nodeSplits = 0) + @test length(operations) == (nodeFusions = 0, nodeReductions = 0, nodeSplits = 0) @test length(graph.dirtyNodes) == 0 @test length(graph.nodes) == 6 @test length(graph.appliedOperations) == 10 @@ -213,8 +205,7 @@ import MetagraphOptimization.partners @test properties.computeIntensity ≈ 28 / 62 operations = get_operations(graph) - @test length(operations) == - (nodeFusions = 10, nodeReductions = 0, nodeSplits = 0) + @test length(operations) == (nodeFusions = 10, nodeReductions = 0, nodeSplits = 0) @test is_valid(graph) end diff --git a/test/unit_tests_nodes.jl b/test/unit_tests_nodes.jl index 74be0e8..7a274d0 100644 --- a/test/unit_tests_nodes.jl +++ b/test/unit_tests_nodes.jl @@ -3,8 +3,7 @@ nC1 = MetagraphOptimization.make_node(MetagraphOptimization.ComputeTaskU()) nC2 = MetagraphOptimization.make_node(MetagraphOptimization.ComputeTaskV()) nC3 = MetagraphOptimization.make_node(MetagraphOptimization.ComputeTaskP()) - nC4 = - MetagraphOptimization.make_node(MetagraphOptimization.ComputeTaskSum()) + nC4 = MetagraphOptimization.make_node(MetagraphOptimization.ComputeTaskSum()) nD1 = MetagraphOptimization.make_node(MetagraphOptimization.DataTask(10)) nD2 = MetagraphOptimization.make_node(MetagraphOptimization.DataTask(20)) diff --git a/test/unit_tests_utility.jl b/test/unit_tests_utility.jl index 169023e..db04d80 100644 --- a/test/unit_tests_utility.jl +++ b/test/unit_tests_utility.jl @@ -5,9 +5,7 @@ @test MetagraphOptimization.bytes_to_human_readable(1025) == "1.001 KiB" @test MetagraphOptimization.bytes_to_human_readable(684235) == "668.2 KiB" @test MetagraphOptimization.bytes_to_human_readable(86214576) == "82.22 MiB" - @test MetagraphOptimization.bytes_to_human_readable(9241457698) == - "8.607 GiB" - @test MetagraphOptimization.bytes_to_human_readable(3218598654367) == - "2.927 TiB" + @test MetagraphOptimization.bytes_to_human_readable(9241457698) == "8.607 GiB" + @test MetagraphOptimization.bytes_to_human_readable(3218598654367) == "2.927 TiB" end println("Utility Unit Tests Complete!")