Refactor model into an interface and remove any ABC Model specific code from src/code_gen/. Also generate functions instead of direct code evaluation in execute()
This commit is contained in:
parent
a69dd6018e
commit
7dd9fedf2e
@ -1,5 +1,5 @@
|
||||
indent = 4
|
||||
margin = 80
|
||||
margin = 120
|
||||
always_for_in = true
|
||||
for_in_replacement = "in"
|
||||
whitespace_typedefs = true
|
||||
|
@ -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
|
||||
|
@ -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: ")
|
||||
|
@ -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()
|
||||
|
@ -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)
|
||||
|
||||
|
@ -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
|
||||
|
@ -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")
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
||||
"""
|
||||
|
@ -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
|
||||
|
@ -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()
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
||||
"""
|
||||
|
@ -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))"
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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]
|
||||
|
109
src/models/interface.jl
Normal file
109
src/models/interface.jl
Normal file
@ -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
|
@ -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}(),
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
@ -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,
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
@ -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))
|
||||
|
@ -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!")
|
||||
|
Loading…
x
Reference in New Issue
Block a user