diff --git a/Project.toml b/Project.toml index 48119e0..b0736e5 100644 --- a/Project.toml +++ b/Project.toml @@ -6,6 +6,7 @@ version = "0.1.0" [deps] BenchmarkTools = "6e4b80f9-dd63-53aa-95a3-0cdb28fa8baf" DataStructures = "864edb3b-99cc-5e75-8d2d-829cb0a9cfe8" +Plots = "91a5bcdd-55d7-5caf-9e0b-520d859cae80" Printf = "de0858da-6303-5e67-8744-51eddeeeb8d7" Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c" UUIDs = "cf7118a7-6976-5b1a-9a39-7adc72f591a4" diff --git a/examples/plot_chain.jl b/examples/plot_chain.jl new file mode 100644 index 0000000..ea47528 --- /dev/null +++ b/examples/plot_chain.jl @@ -0,0 +1,60 @@ +using MetagraphOptimization +using Plots +using Random + +function gen_plot(filepath) + name = basename(filepath) + name, _ = splitext(name) + + filepath = joinpath(@__DIR__, filepath) + if !isfile(filepath) + println("File ", filepath, " does not exist, skipping") + return + end + + g = import_txt(filepath) + + Random.seed!(1) + + println("Random Walking... ") + + x = Vector{Float64}() + y = Vector{Float64}() + + for i = 1:30 + print("\r", i) + # push + opt = get_operations(g) + + # choose one of fuse/split/reduce + option = rand(1:3) + if option == 1 && !isempty(opt.nodeFusions) + push_operation!(g, rand(collect(opt.nodeFusions))) + println("NF") + elseif option == 2 && !isempty(opt.nodeReductions) + push_operation!(g, rand(collect(opt.nodeReductions))) + println("NR") + elseif option == 3 && !isempty(opt.nodeSplits) + push_operation!(g, rand(collect(opt.nodeSplits))) + println("NS") + else + i = i-1 + end + + props = graph_properties(g) + push!(x, props.data) + push!(y, props.compute_effort) + end + + println("\rDone.") + + 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) + end + + gui() +end + +gen_plot("AB->ABBB.txt") diff --git a/examples/plot_star.jl b/examples/plot_star.jl new file mode 100644 index 0000000..0bf249b --- /dev/null +++ b/examples/plot_star.jl @@ -0,0 +1,96 @@ +using MetagraphOptimization +using Plots +using Random + +function gen_plot(filepath) + name = basename(filepath) + name, _ = splitext(name) + + filepath = joinpath(@__DIR__, filepath) + if !isfile(filepath) + println("File ", filepath, " does not exist, skipping") + return + end + + g = import_txt(filepath) + + Random.seed!(1) + + println("Random Walking... ") + + for i = 1:30 + print("\r", i) + # push + opt = get_operations(g) + + # choose one of fuse/split/reduce + option = rand(1:3) + if option == 1 && !isempty(opt.nodeFusions) + push_operation!(g, rand(collect(opt.nodeFusions))) + println("NF") + elseif option == 2 && !isempty(opt.nodeReductions) + push_operation!(g, rand(collect(opt.nodeReductions))) + println("NR") + elseif option == 3 && !isempty(opt.nodeSplits) + push_operation!(g, rand(collect(opt.nodeSplits))) + println("NS") + else + i = i-1 + end + end + + println("\rDone.") + + + + + props = graph_properties(g) + x0 = props.data + y0 = props.compute_effort + + x = Vector{Float64}() + y = Vector{Float64}() + names = Vector{String}() + + opt = get_operations(g) + for op in opt.nodeFusions + push_operation!(g, op) + props = graph_properties(g) + push!(x, props.data) + push!(y, props.compute_effort) + pop_operation!(g) + + push!(names, "NF: (" * string(props.data) * ", " * string(props.compute_effort) * ")") + end + for op in opt.nodeReductions + push_operation!(g, op) + props = graph_properties(g) + push!(x, props.data) + push!(y, props.compute_effort) + pop_operation!(g) + + push!(names, "NR: (" * string(props.data) * ", " * string(props.compute_effort) * ")") + end + for op in opt.nodeSplits + push_operation!(g, op) + props = graph_properties(g) + push!(x, props.data) + push!(y, props.compute_effort) + pop_operation!(g) + + push!(names, "NS: (" * string(props.data) * ", " * string(props.compute_effort) * ")") + end + + 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) + end + #scatter!(x, y, label=names) + + print(names) + + gui() +end + +gen_plot("AB->ABBB.txt") diff --git a/images/OperationChain.png b/images/OperationChain.png new file mode 100644 index 0000000..7808938 Binary files /dev/null and b/images/OperationChain.png differ diff --git a/images/OperationEffects.png b/images/OperationEffects.png new file mode 100644 index 0000000..2642fc5 Binary files /dev/null and b/images/OperationEffects.png differ diff --git a/src/graph_functions.jl b/src/graph_functions.jl index 70515cf..f8ddd44 100644 --- a/src/graph_functions.jl +++ b/src/graph_functions.jl @@ -50,7 +50,7 @@ end function partners(node::Node) result = Set{Node}() for child in children(node) - for partner in parents(node) + for partner in parents(child) if (partner != node) push!(result, partner) end @@ -111,7 +111,7 @@ function graph_properties(graph::DAG) ce = 0 ed = 0 for node in graph.nodes - d += data(node.task) + d += data(node.task) * length(node.parents) ce += compute_effort(node.task) ed += length(node.parents) end @@ -136,10 +136,9 @@ end function can_reduce(n1::Node, n2::Node) if (n1.task != n2.task) - return false + return false end - - return parents(n1) == parents(n2) + return Set(children(n1)) == Set(children(n2)) end function can_split(n::Node) diff --git a/src/graph_operations.jl b/src/graph_operations.jl index 3c8bd59..bac0285 100644 --- a/src/graph_operations.jl +++ b/src/graph_operations.jl @@ -10,6 +10,7 @@ function push_operation!(graph::DAG, operation::Operation) # 3.: Regenerate properties, possible operations from here + graph.possibleOperations.dirty = true end # reverts the latest applied operation, essentially like a ctrl+z for @@ -29,6 +30,7 @@ function pop_operation!(graph::DAG) # 3.: Regenerate properties, possible operations from here + graph.possibleOperations.dirty = true end can_pop(graph::DAG) = !isempty(graph.operationsToApply) || !isempty(graph.appliedOperations) @@ -192,7 +194,7 @@ function node_reduction!(graph::DAG, n1::Node, n2::Node) n2_children = children(n2) n2_parents = parents(n2) - if n2_children != children(n1) + if Set(n2_children) != Set(children(n1)) error("[Node Reduction] The given nodes do not have equal prerequisite nodes which is required for node reduction") end @@ -226,11 +228,14 @@ function node_split!(graph::DAG, n1::Node) error("[Node Split] The given node does not have multiple parents which is required for node split") end + for parent in n1_parents + remove_edge!(graph, make_edge(n1, parent)) + end + for parent in n1_parents n_copy = copy(n1) insert_node!(graph, n_copy) insert_edge!(graph, make_edge(n_copy, parent)) - remove_edge!(graph, make_edge(n1, parent)) for child in n1_children insert_edge!(graph, make_edge(child, n_copy)) @@ -288,7 +293,7 @@ function generate_options(graph::DAG) if can_reduce(node, partner) if reductionVector === nothing # only when there's at least one reduction partner, insert the vector - reductionVector = Vector{Node} + reductionVector = Vector{Node}() push!(reductionVector, node) end diff --git a/test/known_graphs.jl b/test/known_graphs.jl index cac8fb2..bf71d9e 100644 --- a/test/known_graphs.jl +++ b/test/known_graphs.jl @@ -10,7 +10,7 @@ function test_known_graphs() @test length(g_ABAB.nodes) == 34 @test props.compute_effort == 185 - @test props.data == 102 + @test props.data == 0x68 @test length(get_operations(g_ABAB).nodeFusions) == 10 @@ -23,7 +23,7 @@ function test_known_graphs() @test length(g_ABAB3.nodes) == 280 @test props.compute_effort == 2007 - @test props.data == 828 + @test props.data == 0x498 test_node_fusion(g_ABAB3) test_random_walk(g_ABAB3, 1000) @@ -39,7 +39,7 @@ function test_node_fusion(g::DAG) compute_effort = props.compute_effort while !isempty(options.nodeFusions) - fusion = options.nodeFusions[1] + fusion = pop!(options.nodeFusions) @test typeof(fusion) <: NodeFusion @@ -75,11 +75,11 @@ function test_random_walk(g::DAG, n::Int64) # choose one of fuse/split/reduce option = rand(1:3) if option == 1 && !isempty(opt.nodeFusions) - push_operation!(g, opt.nodeFusions[rand(1 : length(opt.nodeFusions))]) + push_operation!(g, rand(collect(opt.nodeFusions))) elseif option == 2 && !isempty(opt.nodeReductions) - push_operation!(g, opt.nodeReductions[rand(1 : length(opt.nodeReductions))]) + push_operation!(g, rand(collect(opt.nodeReductions))) elseif option == 3 && !isempty(opt.nodeSplits) - push_operation!(g, opt.nodeSplits[rand(1 : length(opt.nodeSplits))]) + push_operation!(g, rand(collect(opt.nodeSplits))) else i = i-1 end