From 9bc86bfcd7d3749379602b1257b5ea5034a06338 Mon Sep 17 00:00:00 2001 From: Minh-Thi Nguyen Date: Fri, 17 Dec 2021 16:57:21 -0500 Subject: [PATCH 1/7] add shrinking --- src/shrinking/shrinking.jl | 245 ++++++++++++++++++++++++++++++++++++ test/shrinking/shrinking.jl | 0 2 files changed, 245 insertions(+) create mode 100644 src/shrinking/shrinking.jl create mode 100644 test/shrinking/shrinking.jl diff --git a/src/shrinking/shrinking.jl b/src/shrinking/shrinking.jl new file mode 100644 index 0000000..0be774a --- /dev/null +++ b/src/shrinking/shrinking.jl @@ -0,0 +1,245 @@ +module CompressUDG +using Graphs + +export UNode, contract_graph, CompressUDGMethod + +struct UNode + vertex::Int # vertex index in original graph + pos::Tuple{Int, Int} + neighbors::Vector{Int} +end +function Base.:(==)(x::UNode, y::UNode) + x.vertex == y.vertex && x.neighbors == y.neighbors +end + +# get surrounding neighbor points on UDG +function get_udg_neighbors(pos::Tuple{Int, Int}) + p_x, p_y = pos + pos_udg_neighbors = Vector{Tuple{Int, Int}}() + + for i = -1:1, j = -1:1 + !(i == 0 && j == 0) && push!(pos_udg_neighbors, (p_x + i, p_y + j)) + end + return pos_udg_neighbors +end + + +# find UDNode given a position; return nothing if no node at that position +function get_UNode_from_pos(pos::Tuple{Int, Int}, node_list::Vector{UNode}) + for u in node_list + (u.pos == pos) && return u + end + return nothing +end + +# find boundaries of grid graph given list of UNodes +function find_boundaries(node_list::Vector{UNode}) + min_x = typemax(Int) + min_y = typemax(Int) + max_x = 0 + max_y = 0 + + for u in node_list + p_x, p_y = u.pos + (p_x > max_x) && (max_x = p_x) + (p_x < min_x) && (min_x = p_x) + (p_y > max_y) && (max_y = p_y) + (p_y < min_y) && (min_y = p_y) + end + return min_x, min_y, max_x, max_y +end + +# find points on the boundary that can be moved +# divide region into 4 and move nodes greedily closer to center +function find_boundary_points(node_list::Vector{UNode}, x_min, x_max, y_min, y_max) + half_x = (x_max - x_min)/2 + x_min + half_y = (y_max - y_min)/2 + y_min + + pts_xmin_upper = UNode[] + pts_xmax_upper = Vector{UNode}() + pts_xmin_lower = Vector{UNode}() + pts_xmax_lower = Vector{UNode}() + + pts_ymin_left = Vector{UNode}() + pts_ymax_left = Vector{UNode}() + pts_ymin_right = Vector{UNode}() + pts_ymax_right = Vector{UNode}() + + for u in node_list + p_x, p_y = u.pos + + (p_x == x_min && p_y >= half_y) && push!(pts_xmin_upper, u) + (p_x == x_min && p_y < half_y) && push!(pts_xmin_lower, u) + (p_x == x_max && p_y >= half_y) && push!(pts_xmax_upper, u) + (p_x == x_max && p_y < half_y) && push!(pts_xmax_lower, u) + (p_x >= half_x && p_y == y_min) && push!(pts_ymin_right, u) + (p_x < half_x && p_y == y_min) && push!(pts_ymin_left, u) + (p_x >= half_x && p_y == y_max) && push!(pts_ymax_right, u) + (p_x < half_x && p_y == y_max) && push!(pts_ymax_left, u) + end + + return pts_xmin_upper, pts_xmin_lower, pts_xmax_upper, pts_xmax_lower, + pts_ymin_right, pts_ymin_left, pts_ymax_right, pts_ymax_left +end + + +# check that the new position of node n satisfies UDG requirements +function check_UDG_criteria(n::UNode, new_pos::Tuple{Int, Int}, + node_list::Vector{UNode}) + # check if new_pos is already occupied + (get_UNode_from_pos(new_pos, node_list) != nothing) && return false + + p_x, p_y = new_pos + new_neighbors = Vector{Int}() + + for p in get_udg_neighbors(new_pos) + unode = get_UNode_from_pos(p, node_list) + + if (unode !== nothing) && (unode.vertex != n.vertex) + push!(new_neighbors, unode.vertex) + end + end + + (issetequal(new_neighbors, n.neighbors) == true) & return true + return false +end + +# move node n to a new position new_pos +function move_node(n::UNode, node_list::Vector{UNode}, candidates::Vector{Tuple{Int, Int}}) + for p in candidates + if check_UDG_criteria(n, p, node_list) + node_list[n.vertex] = UNode(n.vertex, p, n.neighbors) + return node_list + end + end + return node_list +end + +# determine candidates +function candidates_xmin_upper(pos::Tuple{Int, Int}) + p_x, p_y = pos + return [(p_x + 1, p_y), (p_x + 1, p_y - 1), (p_x, p_y - 1)] +end + +function candidates_xmin_lower(pos::Tuple{Int, Int}) + p_x, p_y = pos + return [(p_x + 1, p_y), (p_x + 1, p_y + 1), (p_x, p_y + 1)] +end + + +function candidates_xmax_upper(pos::Tuple{Int, Int}) + p_x, p_y = pos + return [(p_x - 1, p_y), (p_x - 1, p_y - 1), (p_x, p_y - 1)] +end + + +function candidates_xmax_lower(pos::Tuple{Int, Int}) + p_x, p_y = pos + return [(p_x - 1, p_y), (p_x - 1, p_y + 1), (p_x, p_y + 1)] +end + + +function candidates_ymin_left(pos::Tuple{Int, Int}) + p_x, p_y = pos + return [(p_x, p_y + 1), (p_x + 1, p_y + 1), (p_x + 1, p_y)] +end + +function candidates_ymin_right(pos::Tuple{Int, Int}) + p_x, p_y = pos + return [(p_x, p_y + 1), (p_x - 1, p_y + 1), (p_x - 1, p_y)] +end + +function candidates_ymax_left(pos::Tuple{Int, Int}) + p_x, p_y = pos + return [(p_x, p_y - 1), (p_x + 1, p_y - 1), (p_x + 1, p_y)] +end + +function candidates_ymax_right(pos::Tuple{Int, Int}) + p_x, p_y = pos + return [(p_x, p_y - 1), (p_x - 1, p_y - 1), (p_x - 1, p_y)] +end + +# one shrinking step +function greedy_step(node_list::Vector{UNode}, min_x::Int, max_x::Int, + min_y::Int, max_y::Int) + + xmin_upper, xmin_lower, xmax_upper, xmax_lower, ymin_right, ymin_left, + ymax_right, ymax_left = find_boundary_points(node_list, min_x, max_x, + min_y, max_y) + + for p in xmin_upper + node_list = move_node(p, node_list, candidates_xmin_upper(p.pos)) + end + for p in xmin_lower + node_list = move_node(p, node_list, candidates_xmin_lower(p.pos)) + end + for p in xmax_upper + node_list = move_node(p, node_list, candidates_xmax_upper(p.pos)) + end + for p in xmax_lower + node_list = move_node(p, node_list, candidates_xmax_lower(p.pos)) + end + + for p in ymin_left + node_list = move_node(p, node_list, candidates_ymin_left(p.pos)) + end + for p in ymin_right + node_list = move_node(p, node_list, candidates_ymin_right(p.pos)) + end + for p in ymax_left + node_list = move_node(p, node_list, candidates_ymax_left(p.pos)) + end + for p in ymax_right + node_list = move_node(p, node_list, candidates_ymax_right(p.pos)) + end + + return node_list +end + +# interfaces +abstract type CompressUDGMethod end + +""" + contract_graph(locs::Vector{Tuple{Int, Int}}) +Compute a contracted version of input graph node positions and returns a +corresponding layout of new condensed graph +""" +function contract_graph(node_positions::Vector{Tuple{Int, Int}}) + # initiate UNodes + + n_list = Vector{UNode}(undef, size(node_positions)[1]) + g = unitdisk_graph(node_positions, 1.5) + + for (ind, n_pos) in enumerate(node_positions) + n_list[ind] = UNode(ind, n_pos, neighbors(g, ind)) + end + + xmin, ymin, xmax, ymax = find_boundaries(n_list) + + while (xmax - xmin > 1) && (ymax - ymin > 1) + n_list = greedy_step(n_list, xmin, xmax, ymin, ymax) + + if xmin < xmax + xmin += 1 + xmax -= 1 + end + + if ymin < ymax + ymin += 1 + ymax -= 1 + end + end + + locs_new = Vector{Tuple{Int, Int}}(undef, size(node_positions)[1]) + for (ind, un) in enumerate(n_list) + locs_new[ind] = un.pos + end + + return locs_new +end + +end + + +using .CompressUDG +export UNode, contract_graph, CompressUDGMethod diff --git a/test/shrinking/shrinking.jl b/test/shrinking/shrinking.jl new file mode 100644 index 0000000..e69de29 From 2a7b08c1a4898a2afe9b44c97cec6cdb07a80f38 Mon Sep 17 00:00:00 2001 From: Minh-Thi Nguyen Date: Fri, 17 Dec 2021 17:06:43 -0500 Subject: [PATCH 2/7] add tests --- test/shrinking/shrinking.jl | 120 ++++++++++++++++++++++++++++++++++++ 1 file changed, 120 insertions(+) diff --git a/test/shrinking/shrinking.jl b/test/shrinking/shrinking.jl index e69de29..8543044 100644 --- a/test/shrinking/shrinking.jl +++ b/test/shrinking/shrinking.jl @@ -0,0 +1,120 @@ +using UnitDiskMapping, Test +using Graphs + +# test method "get_udg_neighbors" +# test "get_UNode_from_pos" +@testset "test neighbors" begin + # test on gadgets + g = smallgraph(:house) + # map to udg + pos = coordinates(map_graph(g).grid_graph) + ud_g = unitdisk_graph(pos, 1.5) + + # list of UNodes + n_list = Vector{UNode}(undef, size(pos)[1]) + # check that all neighbors of udg map in "get_udg_neighbors" + for (i, v) in enumerate(vertices(ud_g)) + for j in neighbors(ud_g, v) + @test(pos[j] in get_udg_neighbors(pos[i])) + end + # initiate unodes + unode = UNode(v, pos[i], neighbors(ud_g, v)) + n_list[i] = unode + end + + # find the boundaries given n_list + x_min, y_min, x_max, y_max = find_boundaries(n_list) + for p in pos + p_x, p_y = p + @test(x_max >= p_x >= x_min) + @test(y_max >= p_y >= y_min) + end + + # test 'get_UNode_from_pos' + for (i, p) in enumerate(pos) + @test n_list[i] == get_UNode_from_pos(p, n_list) + end + + pts_xmin_upper, pts_xmin_lower, pts_xmax_upper, pts_xmax_lower, + pts_ymin_right, pts_ymin_left, pts_ymax_right, pts_ymax_left = + find_boundary_points(n_list, x_min, x_max, y_min, y_max) + + + for v in pts_xmin_upper + # make sure that there are no points to the left of this point + px, py = v.pos + for i = -1:1 + @ get_UNode_from_pos((px - 1, py + i), n_list) == nothing + end + @test py >= (y_max - y_min)/2 + y_min + end + + + for v in pts_xmin_lower + # make sure that there are no points to the left of this point + px, py = v.pos + for i = -1:1 + @test get_UNode_from_pos((px - 1, py + i), n_list) == nothing + end + @test py <= (y_max - y_min)/2 + y_min + end + + for v in pts_xmax_upper + # make sure that there are no points to the left of this point + px, py = v.pos + for i = -1:1 + @test get_UNode_from_pos((px + 1, py + i), n_list) == nothing + end + @test py >= (y_max - y_min)/2 + y_min + end + + for v in pts_xmax_lower + # make sure that there are no points to the left of this point + px, py = v.pos + for i = -1:1 + @test get_UNode_from_pos((px + 1, py + i), n_list) == nothing + end + @test py <= (y_max - y_min)/2 + y_min + end + + for v in pts_ymin_right + # make sure that there are no points to the left of this point + px, py = v.pos + for i = -1:1 + @test get_UNode_from_pos((px + i, py - 1), n_list) == nothing + end + @test px >= (x_max - x_min)/2 + x_min + end + + for v in pts_ymin_left + # make sure that there are no points to the left of this point + px, py = v.pos + for i = -1:1 + @test get_UNode_from_pos((px + i , py- 1), n_list) == nothing + end + @test px <= (x_max - x_min)/2 + x_min + end + + for v in pts_ymax_right + # make sure that there are no points to the left of this point + px, py = v.pos + for i = -1:1 + @test get_UNode_from_pos((px +i, py + 1), n_list) == nothing + end + @test px >= (x_max - x_min)/2 + x_min + end + + for v in pts_ymax_left + # make sure that there are no points to the left of this point + px, py = v.pos + for i = -1:1 + @test get_UNode_from_pos((px +i, py + 1), n_list) == nothing + end + @test px <= (x_max - x_min)/2 + x_min + end + + for (i, n) in enumerate(n_list) + @assert(check_UDG_criteria(n, pos[i], n_list) == false) + end + +end From 36a5c925e54080c1c074acfe20c40733497c8cd2 Mon Sep 17 00:00:00 2001 From: Minh-Thi Nguyen Date: Mon, 20 Dec 2021 23:17:41 -0500 Subject: [PATCH 3/7] update simplifier gadgets + shrinking (still WIP) --- src/UnitDiskMapping.jl | 2 + src/extracting_results.jl | 56 ++++++++++++++-- src/mapping.jl | 8 ++- src/shrinking/shrinking.jl | 124 ++++++++++-------------------------- src/simplifiers.jl | 76 +++++++++++++++++++--- test/shrinking/shrinking.jl | 79 +---------------------- 6 files changed, 160 insertions(+), 185 deletions(-) diff --git a/src/UnitDiskMapping.jl b/src/UnitDiskMapping.jl index e757af8..9f87b38 100644 --- a/src/UnitDiskMapping.jl +++ b/src/UnitDiskMapping.jl @@ -9,6 +9,7 @@ export unapply_gadgets!, unmatch export Pattern, Corner, Turn, Cross, source_graph, mapped_graph, TruncatedTurn, EndTurn export mapped_entry_to_compact, source_entry_to_configs, map_config_back, mis_overhead export UNode, contract_graph, compress_graph +export unitdisk_graph include("utils.jl") include("gadgets.jl") @@ -18,5 +19,6 @@ include("simplifiers.jl") include("extracting_results.jl") include("pathdecomposition/pathdecomposition.jl") include("tikz/tikz.jl") +include("shrinking/shrinking.jl") end diff --git a/src/extracting_results.jl b/src/extracting_results.jl index 90822aa..236739f 100644 --- a/src/extracting_results.jl +++ b/src/extracting_results.jl @@ -5,7 +5,7 @@ function mapped_entry_to_compact(::Cross{false}) end function source_entry_to_configs(::Cross{false}) - return Dict(Pair{Int64, Vector{BitVector}}[5 => [[1, 0, 1, 0, 0, 0, 1, 0, 1], [1, 0, 0, 1, 0, 0, 1, 0, 1]], 12 => [[0, 0, 1, 0, 1, 0, 1, 0, 1], [0, 1, 0, 0, 1, 0, 1, 0, 1]], 8 => [[0, 0, 1, 0, 1, 0, 0, 1, 0], [0, 1, 0, 0, 1, 0, 0, 1, 0], [0, 0, 1, 0, 1, 0, 1, 0, 0], [0, 1, 0, 0, 1, 0, 1, 0, 0]], 1 => [[1, 0, 1, 0, 0, 0, 0, 1, 0], [1, 0, 0, 1, 0, 0, 0, 1, 0], [1, 0, 1, 0, 0, 0, 1, 0, 0], [1, 0, 0, 1, 0, 0, 1, 0, 0]], 0 => [[0, 1, 0, 1, 0, 0, 0, 1, 0], [0, 1, 0, 1, 0, 0, 1, 0, 0]], 6 => [[0, 1, 0, 1, 0, 1, 0, 0, 1]], 11 => [[1, 0, 1, 0, 1, 1, 0, 1, 0]], 9 => [[1, 0, 1, 0, 1, 0, 0, 1, 0], [1, 0, 1, 0, 1, 0, 1, 0, 0]], 14 => [[0, 0, 1, 0, 1, 1, 0, 0, 1], [0, 1, 0, 0, 1, 1, 0, 0, 1]], 3 => [[1, 0, 1, 0, 0, 1, 0, 1, 0], [1, 0, 0, 1, 0, 1, 0, 1, 0]], 7 => [[1, 0, 1, 0, 0, 1, 0, 0, 1], [1, 0, 0, 1, 0, 1, 0, 0, 1]], 4 => [[0, 1, 0, 1, 0, 0, 1, 0, 1]], 13 => [[1, 0, 1, 0, 1, 0, 1, 0, 1]], 15 => [[1, 0, 1, 0, 1, 1, 0, 0, 1]], 2 => [[0, 1, 0, 1, 0, 1, 0, 1, 0]], 10 => [[0, 0, 1, 0, 1, 1, 0, 1, 0], [0, 1, 0, 0, 1, 1, 0, 1, 0]]]) + return Dict(Pair{Int64, Vector{BitVector}}[5 => [[1, 0, 0, 1, 0, 0, 1, 0, 1], [1, 0, 1, 0, 0, 0, 1, 0, 1]], 12 => [[0, 1, 0, 0, 1, 0, 1, 0, 1], [0, 0, 1, 0, 1, 0, 1, 0, 1]], 8 => [[0, 1, 0, 0, 1, 0, 0, 1, 0], [0, 0, 1, 0, 1, 0, 0, 1, 0], [0, 1, 0, 0, 1, 0, 1, 0, 0], [0, 0, 1, 0, 1, 0, 1, 0, 0]], 1 => [[1, 0, 0, 1, 0, 0, 0, 1, 0], [1, 0, 1, 0, 0, 0, 0, 1, 0], [1, 0, 0, 1, 0, 0, 1, 0, 0], [1, 0, 1, 0, 0, 0, 1, 0, 0]], 0 => [[0, 1, 0, 1, 0, 0, 0, 1, 0], [0, 1, 0, 1, 0, 0, 1, 0, 0]], 6 => [[0, 1, 0, 1, 0, 1, 0, 0, 1]], 11 => [[1, 0, 1, 0, 1, 1, 0, 1, 0]], 9 => [[1, 0, 1, 0, 1, 0, 0, 1, 0], [1, 0, 1, 0, 1, 0, 1, 0, 0]], 14 => [[0, 1, 0, 0, 1, 1, 0, 0, 1], [0, 0, 1, 0, 1, 1, 0, 0, 1]], 3 => [[1, 0, 0, 1, 0, 1, 0, 1, 0], [1, 0, 1, 0, 0, 1, 0, 1, 0]], 7 => [[1, 0, 0, 1, 0, 1, 0, 0, 1], [1, 0, 1, 0, 0, 1, 0, 0, 1]], 4 => [[0, 1, 0, 1, 0, 0, 1, 0, 1]], 13 => [[1, 0, 1, 0, 1, 0, 1, 0, 1]], 15 => [[1, 0, 1, 0, 1, 1, 0, 0, 1]], 2 => [[0, 1, 0, 1, 0, 1, 0, 1, 0]], 10 => [[0, 1, 0, 0, 1, 1, 0, 1, 0], [0, 0, 1, 0, 1, 1, 0, 1, 0]]]) end mis_overhead(::Cross{false}) = -1 @@ -27,7 +27,7 @@ function mapped_entry_to_compact(::Turn) end function source_entry_to_configs(::Turn) - return Dict(Pair{Int64, Vector{BitVector}}[0 => [[0, 1, 0, 1, 0]], 2 => [[0, 0, 1, 0, 1], [0, 1, 0, 0, 1]], 3 => [[1, 0, 1, 0, 1]], 1 => [[1, 0, 1, 0, 0], [1, 0, 0, 1, 0]]]) + return Dict(Pair{Int64, Vector{BitVector}}[0 => [[0, 1, 0, 1, 0]], 2 => [[0, 1, 0, 0, 1], [0, 0, 1, 0, 1]], 3 => [[1, 0, 1, 0, 1]], 1 => [[1, 0, 0, 1, 0], [1, 0, 1, 0, 0]]]) end mis_overhead(::Turn) = -1 @@ -38,7 +38,7 @@ function mapped_entry_to_compact(::WTurn) end function source_entry_to_configs(::WTurn) - return Dict(Pair{Int64, Vector{BitVector}}[0 => [[1, 0, 1, 0, 0]], 2 => [[0, 0, 0, 1, 1], [1, 0, 0, 0, 1]], 3 => [[0, 1, 0, 1, 1]], 1 => [[0, 1, 1, 0, 0], [0, 1, 0, 1, 0]]]) + return Dict(Pair{Int64, Vector{BitVector}}[0 => [[1, 0, 1, 0, 0]], 2 => [[1, 0, 0, 0, 1], [0, 0, 0, 1, 1]], 3 => [[0, 1, 0, 1, 1]], 1 => [[0, 1, 0, 1, 0], [0, 1, 1, 0, 0]]]) end mis_overhead(::WTurn) = -1 @@ -49,7 +49,7 @@ function mapped_entry_to_compact(::Branch) end function source_entry_to_configs(::Branch) - return Dict(Pair{Int64, Vector{BitVector}}[0 => [[0, 1, 0, 1, 0, 0, 1, 0]], 4 => [[0, 0, 1, 0, 0, 1, 0, 1], [0, 1, 0, 0, 0, 1, 0, 1], [0, 1, 0, 1, 0, 0, 0, 1]], 5 => [[1, 0, 1, 0, 0, 1, 0, 1]], 6 => [[0, 0, 1, 0, 1, 1, 0, 1], [0, 1, 0, 0, 1, 1, 0, 1]], 2 => [[0, 0, 1, 0, 1, 0, 1, 0], [0, 1, 0, 0, 1, 0, 1, 0], [0, 0, 1, 0, 1, 1, 0, 0], [0, 1, 0, 0, 1, 1, 0, 0]], 7 => [[1, 0, 1, 0, 1, 1, 0, 1]], 3 => [[1, 0, 1, 0, 1, 0, 1, 0], [1, 0, 1, 0, 1, 1, 0, 0]], 1 => [[1, 0, 1, 0, 0, 0, 1, 0], [1, 0, 1, 0, 0, 1, 0, 0], [1, 0, 0, 1, 0, 0, 1, 0]]]) + return Dict(Pair{Int64, Vector{BitVector}}[0 => [[0, 1, 0, 1, 0, 0, 1, 0]], 4 => [[0, 1, 0, 0, 0, 1, 0, 1], [0, 0, 1, 0, 0, 1, 0, 1], [0, 1, 0, 1, 0, 0, 0, 1]], 5 => [[1, 0, 1, 0, 0, 1, 0, 1]], 6 => [[0, 1, 0, 0, 1, 1, 0, 1], [0, 0, 1, 0, 1, 1, 0, 1]], 2 => [[0, 1, 0, 0, 1, 1, 0, 0], [0, 0, 1, 0, 1, 1, 0, 0], [0, 1, 0, 0, 1, 0, 1, 0], [0, 0, 1, 0, 1, 0, 1, 0]], 7 => [[1, 0, 1, 0, 1, 1, 0, 1]], 3 => [[1, 0, 1, 0, 1, 1, 0, 0], [1, 0, 1, 0, 1, 0, 1, 0]], 1 => [[1, 0, 1, 0, 0, 1, 0, 0], [1, 0, 1, 0, 0, 0, 1, 0], [1, 0, 0, 1, 0, 0, 1, 0]]]) end mis_overhead(::Branch) = -1 @@ -60,7 +60,7 @@ function mapped_entry_to_compact(::BranchFix) end function source_entry_to_configs(::BranchFix) - return Dict(Pair{Int64, Vector{BitVector}}[0 => [[0, 0, 1, 0, 1, 0], [0, 1, 0, 0, 1, 0], [0, 1, 0, 1, 0, 0]], 2 => [[0, 1, 0, 1, 0, 1]], 3 => [[1, 0, 1, 0, 0, 1], [1, 0, 0, 1, 0, 1]], 1 => [[1, 0, 1, 0, 1, 0]]]) + return Dict(Pair{Int64, Vector{BitVector}}[0 => [[0, 1, 0, 0, 1, 0], [0, 1, 0, 1, 0, 0], [0, 0, 1, 0, 1, 0]], 2 => [[0, 1, 0, 1, 0, 1]], 3 => [[1, 0, 0, 1, 0, 1], [1, 0, 1, 0, 0, 1]], 1 => [[1, 0, 1, 0, 1, 0]]]) end mis_overhead(::BranchFix) = -1 @@ -93,7 +93,7 @@ function mapped_entry_to_compact(::BranchFixB) end function source_entry_to_configs(::BranchFixB) - return Dict(Pair{Int64, Vector{BitVector}}[0 => [[0, 0, 1, 0], [0, 1, 0, 0]], 2 => [[0, 0, 1, 1]], 3 => [[1, 0, 0, 1]], 1 => [[1, 1, 0, 0]]]) + return Dict(Pair{Int64, Vector{BitVector}}[0 => [[0, 1, 0, 0], [0, 0, 1, 0]], 2 => [[0, 0, 1, 1]], 3 => [[1, 0, 0, 1]], 1 => [[1, 1, 0, 0]]]) end mis_overhead(::BranchFixB) = -1 @@ -119,3 +119,47 @@ function source_entry_to_configs(::UnitDiskMapping.DanglingLeg) end mis_overhead(::UnitDiskMapping.DanglingLeg) = -1 + + +function mapped_entry_to_compact(::UnitDiskMapping.Square) + return Dict([0 => 0, 2 => 2, 3 => 3, 1 => 1]) +end + +function source_entry_to_configs(::UnitDiskMapping.Square) + return Dict(Pair{Int64, Vector{BitVector}}[0 => [[0, 0, 1, 0], [0, 0, 0, 1]], 2 => [[0, 1, 1, 0]], 3 => [], 1 => [[1, 0, 0, 1]]]) +end + +mis_overhead(::UnitDiskMapping.Square) = -1 + + +function mapped_entry_to_compact(::UnitDiskMapping.EndCrossing_with_Edge) + return Dict([0 => 0, 4 => 4, 5 => 1, 6 => 6, 2 => 2, 7 => 7, 3 => 3, 1 => 1]) +end + +function source_entry_to_configs(::UnitDiskMapping.EndCrossing_with_Edge) + return Dict(Pair{Int64, Vector{BitVector}}[0 => [[0, 0, 0, 1, 0, 0], [0, 0, 1, 0, 0, 0], [0, 0, 0, 0, 1, 0]], 4 => [[0, 0, 0, 1, 0, 1], [0, 0, 1, 0, 0, 1]], 5 => [[1, 0, 0, 0, 0, 1]], 6 => [[0, 1, 0, 1, 0, 1]], 2 => [[0, 1, 0, 1, 0, 0]], 7 => [], 3 => [], 1 => [[1, 0, 0, 0, 1, 0]]]) +end + +mis_overhead(::UnitDiskMapping.EndCrossing_with_Edge) = 0 + + +function mapped_entry_to_compact(::UnitDiskMapping.Cane) + return Dict([0 => 0, 2 => 0, 3 => 3, 1 => 0]) +end + +function source_entry_to_configs(::UnitDiskMapping.Cane) + return Dict(Pair{Int64, Vector{BitVector}}[0 => [[0, 1, 0, 1, 0]], 2 => [[0, 0, 1, 0, 1], [0, 1, 0, 0, 1]], 3 => [[1, 0, 1, 0, 1]], 1 => [[1, 0, 0, 1, 0], [1, 0, 1, 0, 0]]]) +end + +mis_overhead(::UnitDiskMapping.Cane) = -1 + + +function mapped_entry_to_compact(::UnitDiskMapping.CLoop) + return Dict([0 => 0, 2 => 0, 3 => 3, 1 => 0]) +end + +function source_entry_to_configs(::UnitDiskMapping.CLoop) + return Dict(Pair{Int64, Vector{BitVector}}[0 => [[0, 1, 1, 0, 0]], 2 => [[0, 1, 0, 0, 1], [1, 0, 0, 0, 1]], 3 => [[1, 0, 0, 1, 1]], 1 => [[1, 0, 0, 1, 0], [0, 0, 1, 1, 0]]]) +end + +mis_overhead(::UnitDiskMapping.CLoop) = -1 diff --git a/src/mapping.jl b/src/mapping.jl index b6e1383..f07130b 100644 --- a/src/mapping.jl +++ b/src/mapping.jl @@ -347,7 +347,7 @@ function mis_overhead_copylines(ug::UGrid{WC,W}) where {WC,W} end ##### Interfaces ###### -export MappingResult, map_graph, map_configs_back +export MappingResult, map_graph, map_configs_back, apply_simplifiers_unweighted struct MappingResult{CT,WT} grid_graph::UGrid{CT,WT} @@ -386,6 +386,10 @@ function map_graph(mode, g::SimpleGraph; vertex_order=Greedy(), ruleset=default_ return MappingResult(ug, vcat(tape, tape2) , mis_overhead0 + mis_overhead1 + mis_overhead2) end +function apply_simplifiers_unweighted(ug::UGrid) + return apply_simplifier_gadgets!(ug; ruleset=default_simplifier_ruleset(UnWeighted())) +end + map_configs_back(r::MappingResult{<:Cell}, configs::AbstractVector) = unapply_gadgets!(copy(r.grid_graph), r.mapping_history, copy.(configs))[2] default_simplifier_ruleset(::UnWeighted) = vcat([rotated_and_reflected(rule) for rule in simplifier_ruleset]...) -default_simplifier_ruleset(::Weighted) = weighted.(default_simplifier_ruleset(UnWeighted())) \ No newline at end of file +default_simplifier_ruleset(::Weighted) = weighted.(default_simplifier_ruleset(UnWeighted())) diff --git a/src/shrinking/shrinking.jl b/src/shrinking/shrinking.jl index 0be774a..ef492f9 100644 --- a/src/shrinking/shrinking.jl +++ b/src/shrinking/shrinking.jl @@ -27,7 +27,7 @@ end # find UDNode given a position; return nothing if no node at that position function get_UNode_from_pos(pos::Tuple{Int, Int}, node_list::Vector{UNode}) for u in node_list - (u.pos == pos) && return u + (u.pos == pos) && return u end return nothing end @@ -50,36 +50,15 @@ function find_boundaries(node_list::Vector{UNode}) end # find points on the boundary that can be moved -# divide region into 4 and move nodes greedily closer to center function find_boundary_points(node_list::Vector{UNode}, x_min, x_max, y_min, y_max) - half_x = (x_max - x_min)/2 + x_min - half_y = (y_max - y_min)/2 + y_min - - pts_xmin_upper = UNode[] - pts_xmax_upper = Vector{UNode}() - pts_xmin_lower = Vector{UNode}() - pts_xmax_lower = Vector{UNode}() - - pts_ymin_left = Vector{UNode}() - pts_ymax_left = Vector{UNode}() - pts_ymin_right = Vector{UNode}() - pts_ymax_right = Vector{UNode}() + pts_boundary = Vector{UNode}() for u in node_list p_x, p_y = u.pos - - (p_x == x_min && p_y >= half_y) && push!(pts_xmin_upper, u) - (p_x == x_min && p_y < half_y) && push!(pts_xmin_lower, u) - (p_x == x_max && p_y >= half_y) && push!(pts_xmax_upper, u) - (p_x == x_max && p_y < half_y) && push!(pts_xmax_lower, u) - (p_x >= half_x && p_y == y_min) && push!(pts_ymin_right, u) - (p_x < half_x && p_y == y_min) && push!(pts_ymin_left, u) - (p_x >= half_x && p_y == y_max) && push!(pts_ymax_right, u) - (p_x < half_x && p_y == y_max) && push!(pts_ymax_left, u) + (p_x == x_min || p_x == x_max || p_y == y_min || p_y == y_max) && push!(pts_boundary, u) end - return pts_xmin_upper, pts_xmin_lower, pts_xmax_upper, pts_xmax_lower, - pts_ymin_right, pts_ymin_left, pts_ymax_right, pts_ymax_left + return pts_boundary end @@ -100,7 +79,7 @@ function check_UDG_criteria(n::UNode, new_pos::Tuple{Int, Int}, end end - (issetequal(new_neighbors, n.neighbors) == true) & return true + (issetequal(new_neighbors, n.neighbors) == true) && return true return false end @@ -115,87 +94,53 @@ function move_node(n::UNode, node_list::Vector{UNode}, candidates::Vector{Tuple{ return node_list end -# determine candidates -function candidates_xmin_upper(pos::Tuple{Int, Int}) - p_x, p_y = pos - return [(p_x + 1, p_y), (p_x + 1, p_y - 1), (p_x, p_y - 1)] -end - -function candidates_xmin_lower(pos::Tuple{Int, Int}) +# determine candidates to move +function determine_candidates(pos::Tuple{Int, Int}, x_min, x_max, y_min, y_max) p_x, p_y = pos - return [(p_x + 1, p_y), (p_x + 1, p_y + 1), (p_x, p_y + 1)] -end + halfx = (x_max - x_min)/2 + x_min + halfy = (y_max - y_min)/2 + y_min -function candidates_xmax_upper(pos::Tuple{Int, Int}) - p_x, p_y = pos - return [(p_x - 1, p_y), (p_x - 1, p_y - 1), (p_x, p_y - 1)] -end + # move boundary vertices such that we can shrink graph from four quadrants + (p_x == x_min && p_y >= halfy) && return [(p_x + 1, p_y), (p_x + 1, p_y - 1), (p_x, p_y - 1)] + (p_x == x_min && p_y < halfy) && return [(p_x + 1, p_y), (p_x + 1, p_y + 1), (p_x, p_y + 1)] + (p_x == x_max && p_y >= halfy) && return [(p_x - 1, p_y), (p_x - 1, p_y - 1), (p_x, p_y - 1)] + (p_x == x_max && p_y < halfy) && return [(p_x - 1, p_y), (p_x - 1, p_y + 1), (p_x, p_y + 1)] + (p_x < halfx && p_y == y_min) && return [(p_x, p_y + 1), (p_x + 1, p_y + 1), (p_x + 1, p_y)] + (p_x >= halfx && p_y == y_min) && return [(p_x, p_y + 1), (p_x - 1, p_y + 1), (p_x - 1, p_y)] + (p_x < halfx && p_y == y_max) && return [(p_x, p_y - 1), (p_x + 1, p_y - 1), (p_x + 1, p_y)] + (p_x >= halfx && p_y == y_max) && return [(p_x, p_y - 1), (p_x - 1, p_y - 1), (p_x - 1, p_y)] -function candidates_xmax_lower(pos::Tuple{Int, Int}) - p_x, p_y = pos - return [(p_x - 1, p_y), (p_x - 1, p_y + 1), (p_x, p_y + 1)] end -function candidates_ymin_left(pos::Tuple{Int, Int}) - p_x, p_y = pos - return [(p_x, p_y + 1), (p_x + 1, p_y + 1), (p_x + 1, p_y)] -end - -function candidates_ymin_right(pos::Tuple{Int, Int}) - p_x, p_y = pos - return [(p_x, p_y + 1), (p_x - 1, p_y + 1), (p_x - 1, p_y)] -end - -function candidates_ymax_left(pos::Tuple{Int, Int}) - p_x, p_y = pos - return [(p_x, p_y - 1), (p_x + 1, p_y - 1), (p_x + 1, p_y)] -end - -function candidates_ymax_right(pos::Tuple{Int, Int}) - p_x, p_y = pos - return [(p_x, p_y - 1), (p_x - 1, p_y - 1), (p_x - 1, p_y)] -end - # one shrinking step function greedy_step(node_list::Vector{UNode}, min_x::Int, max_x::Int, min_y::Int, max_y::Int) - xmin_upper, xmin_lower, xmax_upper, xmax_lower, ymin_right, ymin_left, - ymax_right, ymax_left = find_boundary_points(node_list, min_x, max_x, + boundary_pts = find_boundary_points(node_list, min_x, max_x, min_y, max_y) - for p in xmin_upper - node_list = move_node(p, node_list, candidates_xmin_upper(p.pos)) - end - for p in xmin_lower - node_list = move_node(p, node_list, candidates_xmin_lower(p.pos)) - end - for p in xmax_upper - node_list = move_node(p, node_list, candidates_xmax_upper(p.pos)) - end - for p in xmax_lower - node_list = move_node(p, node_list, candidates_xmax_lower(p.pos)) - end - - for p in ymin_left - node_list = move_node(p, node_list, candidates_ymin_left(p.pos)) - end - for p in ymin_right - node_list = move_node(p, node_list, candidates_ymin_right(p.pos)) - end - for p in ymax_left - node_list = move_node(p, node_list, candidates_ymax_left(p.pos)) - end - for p in ymax_right - node_list = move_node(p, node_list, candidates_ymax_right(p.pos)) + for p in boundary_pts + node_list = move_node(p, node_list, determine_candidates(p.pos, min_x, max_x, + min_y, max_y)) end return node_list end +function unitdisk_graph(locs::AbstractVector, unit::Real) + n = length(locs) + g = SimpleGraph(n) + for i=1:n, j=i+1:n + if sum(abs2, locs[i] .- locs[j]) < unit ^ 2 + add_edge!(g, i, j) + end + end + return g +end + # interfaces abstract type CompressUDGMethod end @@ -216,6 +161,7 @@ function contract_graph(node_positions::Vector{Tuple{Int, Int}}) xmin, ymin, xmax, ymax = find_boundaries(n_list) + while (xmax - xmin > 1) && (ymax - ymin > 1) n_list = greedy_step(n_list, xmin, xmax, ymin, ymax) @@ -228,6 +174,7 @@ function contract_graph(node_positions::Vector{Tuple{Int, Int}}) ymin += 1 ymax -= 1 end + end locs_new = Vector{Tuple{Int, Int}}(undef, size(node_positions)[1]) @@ -240,6 +187,5 @@ end end - using .CompressUDG export UNode, contract_graph, CompressUDGMethod diff --git a/src/simplifiers.jl b/src/simplifiers.jl index d68c21e..f128fa0 100644 --- a/src/simplifiers.jl +++ b/src/simplifiers.jl @@ -81,23 +81,79 @@ end # 1. specify a gadget like the following. Use either `o` and `●` to specify a vertex, # either `.` or `⋅` to specify a placeholder. @gg DanglingLeg = - """ - ⋅ ⋅ ⋅ - ⋅ ● ⋅ - ⋅ ● ⋅ - ⋅ ● ⋅ + """ + ⋅ ⋅ ⋅ + ⋅ ● ⋅ + ⋅ ● ⋅ + ⋅ ● ⋅ """=>""" - ⋅ ⋅ ⋅ - ⋅ ⋅ ⋅ - ⋅ ⋅ ⋅ + ⋅ ⋅ ⋅ + ⋅ ⋅ ⋅ + ⋅ ⋅ ⋅ ⋅ ● ⋅ """ +@gg Square = + """ + ⋅ ● ⋅ ⋅ + ● ⋅ ● ⋅ + ⋅ ● ⋅ ⋅ + ⋅ ⋅ ⋅ ⋅ + """=>""" + ⋅ ● ⋅ ⋅ + ● ⋅ ⋅ ⋅ + ⋅ ⋅ ⋅ ⋅ + ⋅ ⋅ ⋅ ⋅ + """ + +@gg EndCrossing_with_Edge = + """ + ⋅ ● ⋅ ⋅ + ● ● ● ● + ⋅ ● ⋅ ⋅ + ⋅ ⋅ ⋅ ⋅ + """=>""" + ⋅ ● ⋅ ⋅ + ● ⋅ ⋅ ● + ⋅ ● ● ⋅ + ⋅ ⋅ ⋅ ⋅ + """ + +@gg Cane = + """ + ⋅ ⋅ ⋅ ⋅ + ⋅ ● ⋅ ⋅ + ● ⋅ ● ⋅ + ⋅ ⋅ ● ⋅ + ⋅ ⋅ ● ⋅ + """=>""" + ⋅ ⋅ ⋅ ⋅ + ⋅ ⋅ ⋅ ⋅ + ● ⋅ ⋅ ⋅ + ⋅ ● ⋅ ⋅ + ⋅ ⋅ ● ⋅ + """ + +@gg CLoop = + """ + ⋅ ⋅ ⋅ ⋅ + ⋅ ⋅ ● ⋅ + ⋅ ● ⋅ ● + ⋅ ● ⋅ ⋅ + ⋅ ⋅ ● ⋅ + """=>""" + ⋅ ⋅ ⋅ ⋅ + ⋅ ⋅ ⋅ ⋅ + ⋅ ⋅ ⋅ ● + ⋅ ⋅ ● ⋅ + ⋅ ⋅ ● ⋅ + """ + # 2. add your gadget to simplifier ruleset. -const simplifier_ruleset = SimplifyPattern[DanglingLeg()] +const simplifier_ruleset = SimplifyPattern[DanglingLeg(), Square(), EndCrossing_with_Edge(), Cane(), CLoop()] # set centers (vertices with weight 1) for the weighted version source_centers(::WeightedGadget{DanglingLeg}) = [(2,2)] mapped_centers(::WeightedGadget{DanglingLeg}) = [(4,2)] # 3. run the script `project/createmap` to generate `mis_overhead` and other informations required -# for mapping back. (Note: will overwrite the source file `src/extracting_results.jl`) \ No newline at end of file +# for mapping back. (Note: will overwrite the source file `src/extracting_results.jl`) diff --git a/test/shrinking/shrinking.jl b/test/shrinking/shrinking.jl index 8543044..30d039d 100644 --- a/test/shrinking/shrinking.jl +++ b/test/shrinking/shrinking.jl @@ -35,84 +35,7 @@ using Graphs @test n_list[i] == get_UNode_from_pos(p, n_list) end - pts_xmin_upper, pts_xmin_lower, pts_xmax_upper, pts_xmax_lower, - pts_ymin_right, pts_ymin_left, pts_ymax_right, pts_ymax_left = - find_boundary_points(n_list, x_min, x_max, y_min, y_max) - - - for v in pts_xmin_upper - # make sure that there are no points to the left of this point - px, py = v.pos - for i = -1:1 - @ get_UNode_from_pos((px - 1, py + i), n_list) == nothing - end - @test py >= (y_max - y_min)/2 + y_min - end - - - for v in pts_xmin_lower - # make sure that there are no points to the left of this point - px, py = v.pos - for i = -1:1 - @test get_UNode_from_pos((px - 1, py + i), n_list) == nothing - end - @test py <= (y_max - y_min)/2 + y_min - end - - for v in pts_xmax_upper - # make sure that there are no points to the left of this point - px, py = v.pos - for i = -1:1 - @test get_UNode_from_pos((px + 1, py + i), n_list) == nothing - end - @test py >= (y_max - y_min)/2 + y_min - end - - for v in pts_xmax_lower - # make sure that there are no points to the left of this point - px, py = v.pos - for i = -1:1 - @test get_UNode_from_pos((px + 1, py + i), n_list) == nothing - end - @test py <= (y_max - y_min)/2 + y_min - end - - for v in pts_ymin_right - # make sure that there are no points to the left of this point - px, py = v.pos - for i = -1:1 - @test get_UNode_from_pos((px + i, py - 1), n_list) == nothing - end - @test px >= (x_max - x_min)/2 + x_min - end - - for v in pts_ymin_left - # make sure that there are no points to the left of this point - px, py = v.pos - for i = -1:1 - @test get_UNode_from_pos((px + i , py- 1), n_list) == nothing - end - @test px <= (x_max - x_min)/2 + x_min - end - - for v in pts_ymax_right - # make sure that there are no points to the left of this point - px, py = v.pos - for i = -1:1 - @test get_UNode_from_pos((px +i, py + 1), n_list) == nothing - end - @test px >= (x_max - x_min)/2 + x_min - end - - for v in pts_ymax_left - # make sure that there are no points to the left of this point - px, py = v.pos - for i = -1:1 - @test get_UNode_from_pos((px +i, py + 1), n_list) == nothing - end - @test px <= (x_max - x_min)/2 + x_min - end - + boundary_pts = find_boundary_points(n_list, x_min, x_max, y_min, y_max) for (i, n) in enumerate(n_list) @assert(check_UDG_criteria(n, pos[i], n_list) == false) end From 56eabdf2e829a1567956a28ad14471485b3287a6 Mon Sep 17 00:00:00 2001 From: Minh-Thi Nguyen Date: Mon, 20 Dec 2021 23:39:46 -0500 Subject: [PATCH 4/7] add simplifying ends --- src/extracting_results.jl | 38 ++++++++++++++++++++++++++++++-------- src/simplifiers.jl | 28 +++++++++++++++++++++++++++- 2 files changed, 57 insertions(+), 9 deletions(-) diff --git a/src/extracting_results.jl b/src/extracting_results.jl index 236739f..421b86c 100644 --- a/src/extracting_results.jl +++ b/src/extracting_results.jl @@ -5,7 +5,7 @@ function mapped_entry_to_compact(::Cross{false}) end function source_entry_to_configs(::Cross{false}) - return Dict(Pair{Int64, Vector{BitVector}}[5 => [[1, 0, 0, 1, 0, 0, 1, 0, 1], [1, 0, 1, 0, 0, 0, 1, 0, 1]], 12 => [[0, 1, 0, 0, 1, 0, 1, 0, 1], [0, 0, 1, 0, 1, 0, 1, 0, 1]], 8 => [[0, 1, 0, 0, 1, 0, 0, 1, 0], [0, 0, 1, 0, 1, 0, 0, 1, 0], [0, 1, 0, 0, 1, 0, 1, 0, 0], [0, 0, 1, 0, 1, 0, 1, 0, 0]], 1 => [[1, 0, 0, 1, 0, 0, 0, 1, 0], [1, 0, 1, 0, 0, 0, 0, 1, 0], [1, 0, 0, 1, 0, 0, 1, 0, 0], [1, 0, 1, 0, 0, 0, 1, 0, 0]], 0 => [[0, 1, 0, 1, 0, 0, 0, 1, 0], [0, 1, 0, 1, 0, 0, 1, 0, 0]], 6 => [[0, 1, 0, 1, 0, 1, 0, 0, 1]], 11 => [[1, 0, 1, 0, 1, 1, 0, 1, 0]], 9 => [[1, 0, 1, 0, 1, 0, 0, 1, 0], [1, 0, 1, 0, 1, 0, 1, 0, 0]], 14 => [[0, 1, 0, 0, 1, 1, 0, 0, 1], [0, 0, 1, 0, 1, 1, 0, 0, 1]], 3 => [[1, 0, 0, 1, 0, 1, 0, 1, 0], [1, 0, 1, 0, 0, 1, 0, 1, 0]], 7 => [[1, 0, 0, 1, 0, 1, 0, 0, 1], [1, 0, 1, 0, 0, 1, 0, 0, 1]], 4 => [[0, 1, 0, 1, 0, 0, 1, 0, 1]], 13 => [[1, 0, 1, 0, 1, 0, 1, 0, 1]], 15 => [[1, 0, 1, 0, 1, 1, 0, 0, 1]], 2 => [[0, 1, 0, 1, 0, 1, 0, 1, 0]], 10 => [[0, 1, 0, 0, 1, 1, 0, 1, 0], [0, 0, 1, 0, 1, 1, 0, 1, 0]]]) + return Dict(Pair{Int64, Vector{BitVector}}[5 => [[1, 0, 1, 0, 0, 0, 1, 0, 1], [1, 0, 0, 1, 0, 0, 1, 0, 1]], 12 => [[0, 0, 1, 0, 1, 0, 1, 0, 1], [0, 1, 0, 0, 1, 0, 1, 0, 1]], 8 => [[0, 0, 1, 0, 1, 0, 1, 0, 0], [0, 1, 0, 0, 1, 0, 1, 0, 0], [0, 0, 1, 0, 1, 0, 0, 1, 0], [0, 1, 0, 0, 1, 0, 0, 1, 0]], 1 => [[1, 0, 1, 0, 0, 0, 1, 0, 0], [1, 0, 0, 1, 0, 0, 1, 0, 0], [1, 0, 1, 0, 0, 0, 0, 1, 0], [1, 0, 0, 1, 0, 0, 0, 1, 0]], 0 => [[0, 1, 0, 1, 0, 0, 1, 0, 0], [0, 1, 0, 1, 0, 0, 0, 1, 0]], 6 => [[0, 1, 0, 1, 0, 1, 0, 0, 1]], 11 => [[1, 0, 1, 0, 1, 1, 0, 1, 0]], 9 => [[1, 0, 1, 0, 1, 0, 1, 0, 0], [1, 0, 1, 0, 1, 0, 0, 1, 0]], 14 => [[0, 0, 1, 0, 1, 1, 0, 0, 1], [0, 1, 0, 0, 1, 1, 0, 0, 1]], 3 => [[1, 0, 1, 0, 0, 1, 0, 1, 0], [1, 0, 0, 1, 0, 1, 0, 1, 0]], 7 => [[1, 0, 1, 0, 0, 1, 0, 0, 1], [1, 0, 0, 1, 0, 1, 0, 0, 1]], 4 => [[0, 1, 0, 1, 0, 0, 1, 0, 1]], 13 => [[1, 0, 1, 0, 1, 0, 1, 0, 1]], 15 => [[1, 0, 1, 0, 1, 1, 0, 0, 1]], 2 => [[0, 1, 0, 1, 0, 1, 0, 1, 0]], 10 => [[0, 0, 1, 0, 1, 1, 0, 1, 0], [0, 1, 0, 0, 1, 1, 0, 1, 0]]]) end mis_overhead(::Cross{false}) = -1 @@ -27,7 +27,7 @@ function mapped_entry_to_compact(::Turn) end function source_entry_to_configs(::Turn) - return Dict(Pair{Int64, Vector{BitVector}}[0 => [[0, 1, 0, 1, 0]], 2 => [[0, 1, 0, 0, 1], [0, 0, 1, 0, 1]], 3 => [[1, 0, 1, 0, 1]], 1 => [[1, 0, 0, 1, 0], [1, 0, 1, 0, 0]]]) + return Dict(Pair{Int64, Vector{BitVector}}[0 => [[0, 1, 0, 1, 0]], 2 => [[0, 0, 1, 0, 1], [0, 1, 0, 0, 1]], 3 => [[1, 0, 1, 0, 1]], 1 => [[1, 0, 1, 0, 0], [1, 0, 0, 1, 0]]]) end mis_overhead(::Turn) = -1 @@ -49,7 +49,7 @@ function mapped_entry_to_compact(::Branch) end function source_entry_to_configs(::Branch) - return Dict(Pair{Int64, Vector{BitVector}}[0 => [[0, 1, 0, 1, 0, 0, 1, 0]], 4 => [[0, 1, 0, 0, 0, 1, 0, 1], [0, 0, 1, 0, 0, 1, 0, 1], [0, 1, 0, 1, 0, 0, 0, 1]], 5 => [[1, 0, 1, 0, 0, 1, 0, 1]], 6 => [[0, 1, 0, 0, 1, 1, 0, 1], [0, 0, 1, 0, 1, 1, 0, 1]], 2 => [[0, 1, 0, 0, 1, 1, 0, 0], [0, 0, 1, 0, 1, 1, 0, 0], [0, 1, 0, 0, 1, 0, 1, 0], [0, 0, 1, 0, 1, 0, 1, 0]], 7 => [[1, 0, 1, 0, 1, 1, 0, 1]], 3 => [[1, 0, 1, 0, 1, 1, 0, 0], [1, 0, 1, 0, 1, 0, 1, 0]], 1 => [[1, 0, 1, 0, 0, 1, 0, 0], [1, 0, 1, 0, 0, 0, 1, 0], [1, 0, 0, 1, 0, 0, 1, 0]]]) + return Dict(Pair{Int64, Vector{BitVector}}[0 => [[0, 1, 0, 1, 0, 0, 1, 0]], 4 => [[0, 1, 0, 0, 0, 1, 0, 1], [0, 0, 1, 0, 0, 1, 0, 1], [0, 1, 0, 1, 0, 0, 0, 1]], 5 => [[1, 0, 1, 0, 0, 1, 0, 1]], 6 => [[0, 1, 0, 0, 1, 1, 0, 1], [0, 0, 1, 0, 1, 1, 0, 1]], 2 => [[0, 1, 0, 0, 1, 0, 1, 0], [0, 0, 1, 0, 1, 0, 1, 0], [0, 1, 0, 0, 1, 1, 0, 0], [0, 0, 1, 0, 1, 1, 0, 0]], 7 => [[1, 0, 1, 0, 1, 1, 0, 1]], 3 => [[1, 0, 1, 0, 1, 0, 1, 0], [1, 0, 1, 0, 1, 1, 0, 0]], 1 => [[1, 0, 1, 0, 0, 0, 1, 0], [1, 0, 1, 0, 0, 1, 0, 0], [1, 0, 0, 1, 0, 0, 1, 0]]]) end mis_overhead(::Branch) = -1 @@ -60,7 +60,7 @@ function mapped_entry_to_compact(::BranchFix) end function source_entry_to_configs(::BranchFix) - return Dict(Pair{Int64, Vector{BitVector}}[0 => [[0, 1, 0, 0, 1, 0], [0, 1, 0, 1, 0, 0], [0, 0, 1, 0, 1, 0]], 2 => [[0, 1, 0, 1, 0, 1]], 3 => [[1, 0, 0, 1, 0, 1], [1, 0, 1, 0, 0, 1]], 1 => [[1, 0, 1, 0, 1, 0]]]) + return Dict(Pair{Int64, Vector{BitVector}}[0 => [[0, 1, 0, 1, 0, 0], [0, 1, 0, 0, 1, 0], [0, 0, 1, 0, 1, 0]], 2 => [[0, 1, 0, 1, 0, 1]], 3 => [[1, 0, 1, 0, 0, 1], [1, 0, 0, 1, 0, 1]], 1 => [[1, 0, 1, 0, 1, 0]]]) end mis_overhead(::BranchFix) = -1 @@ -93,7 +93,7 @@ function mapped_entry_to_compact(::BranchFixB) end function source_entry_to_configs(::BranchFixB) - return Dict(Pair{Int64, Vector{BitVector}}[0 => [[0, 1, 0, 0], [0, 0, 1, 0]], 2 => [[0, 0, 1, 1]], 3 => [[1, 0, 0, 1]], 1 => [[1, 1, 0, 0]]]) + return Dict(Pair{Int64, Vector{BitVector}}[0 => [[0, 0, 1, 0], [0, 1, 0, 0]], 2 => [[0, 0, 1, 1]], 3 => [[1, 0, 0, 1]], 1 => [[1, 1, 0, 0]]]) end mis_overhead(::BranchFixB) = -1 @@ -126,7 +126,7 @@ function mapped_entry_to_compact(::UnitDiskMapping.Square) end function source_entry_to_configs(::UnitDiskMapping.Square) - return Dict(Pair{Int64, Vector{BitVector}}[0 => [[0, 0, 1, 0], [0, 0, 0, 1]], 2 => [[0, 1, 1, 0]], 3 => [], 1 => [[1, 0, 0, 1]]]) + return Dict(Pair{Int64, Vector{BitVector}}[0 => [[0, 0, 0, 1], [0, 0, 1, 0]], 2 => [[0, 1, 1, 0]], 3 => [], 1 => [[1, 0, 0, 1]]]) end mis_overhead(::UnitDiskMapping.Square) = -1 @@ -148,7 +148,7 @@ function mapped_entry_to_compact(::UnitDiskMapping.Cane) end function source_entry_to_configs(::UnitDiskMapping.Cane) - return Dict(Pair{Int64, Vector{BitVector}}[0 => [[0, 1, 0, 1, 0]], 2 => [[0, 0, 1, 0, 1], [0, 1, 0, 0, 1]], 3 => [[1, 0, 1, 0, 1]], 1 => [[1, 0, 0, 1, 0], [1, 0, 1, 0, 0]]]) + return Dict(Pair{Int64, Vector{BitVector}}[0 => [[0, 1, 0, 1, 0]], 2 => [[0, 1, 0, 0, 1], [0, 0, 1, 0, 1]], 3 => [[1, 0, 1, 0, 1]], 1 => [[1, 0, 0, 1, 0], [1, 0, 1, 0, 0]]]) end mis_overhead(::UnitDiskMapping.Cane) = -1 @@ -159,7 +159,29 @@ function mapped_entry_to_compact(::UnitDiskMapping.CLoop) end function source_entry_to_configs(::UnitDiskMapping.CLoop) - return Dict(Pair{Int64, Vector{BitVector}}[0 => [[0, 1, 1, 0, 0]], 2 => [[0, 1, 0, 0, 1], [1, 0, 0, 0, 1]], 3 => [[1, 0, 0, 1, 1]], 1 => [[1, 0, 0, 1, 0], [0, 0, 1, 1, 0]]]) + return Dict(Pair{Int64, Vector{BitVector}}[0 => [[0, 1, 1, 0, 0]], 2 => [[1, 0, 0, 0, 1], [0, 1, 0, 0, 1]], 3 => [[1, 0, 0, 1, 1]], 1 => [[1, 0, 0, 1, 0], [0, 0, 1, 1, 0]]]) end mis_overhead(::UnitDiskMapping.CLoop) = -1 + + +function mapped_entry_to_compact(::UnitDiskMapping.CurveEnd) + return Dict([0 => 0, 1 => 1]) +end + +function source_entry_to_configs(::UnitDiskMapping.CurveEnd) + return Dict(Pair{Int64, Vector{BitVector}}[0 => [[1, 0, 0], [0, 1, 0]], 1 => [[1, 0, 1]]]) +end + +mis_overhead(::UnitDiskMapping.CurveEnd) = -1 + + +function mapped_entry_to_compact(::UnitDiskMapping.DiagonalEnd) + return Dict([0 => 0, 1 => 1]) +end + +function source_entry_to_configs(::UnitDiskMapping.DiagonalEnd) + return Dict(Pair{Int64, Vector{BitVector}}[0 => [[1, 0, 0], [0, 1, 0]], 1 => [[1, 0, 1]]]) +end + +mis_overhead(::UnitDiskMapping.DiagonalEnd) = -1 diff --git a/src/simplifiers.jl b/src/simplifiers.jl index f128fa0..eec1584 100644 --- a/src/simplifiers.jl +++ b/src/simplifiers.jl @@ -149,8 +149,34 @@ end ⋅ ⋅ ● ⋅ """ +@gg CurveEnd = + """ + ⋅ ⋅ ⋅ ⋅ + ⋅ ● ⋅ ⋅ + ⋅ ⋅ ● ⋅ + ⋅ ⋅ ● ⋅ + """=>""" + ⋅ ⋅ ⋅ ⋅ + ⋅ ⋅ ⋅ ⋅ + ⋅ ⋅ ⋅ ⋅ + ⋅ ⋅ ● ⋅ + """ + +@gg DiagonalEnd = + """ + ⋅ ⋅ ⋅ ⋅ + ⋅ ● ⋅ ⋅ + ⋅ ⋅ ● ⋅ + ⋅ ⋅ ⋅ ● + """=>""" + ⋅ ⋅ ⋅ ⋅ + ⋅ ⋅ ⋅ ⋅ + ⋅ ⋅ ⋅ ⋅ + ⋅ ⋅ ⋅ ● + """ + # 2. add your gadget to simplifier ruleset. -const simplifier_ruleset = SimplifyPattern[DanglingLeg(), Square(), EndCrossing_with_Edge(), Cane(), CLoop()] +const simplifier_ruleset = SimplifyPattern[DanglingLeg(), Square(), EndCrossing_with_Edge(), Cane(), CLoop(), CurveEnd(), DiagonalEnd()] # set centers (vertices with weight 1) for the weighted version source_centers(::WeightedGadget{DanglingLeg}) = [(2,2)] mapped_centers(::WeightedGadget{DanglingLeg}) = [(4,2)] From cc8a333e278a57ce62af58058fb31b74868b71bf Mon Sep 17 00:00:00 2001 From: Minh-Thi Nguyen Date: Tue, 21 Dec 2021 09:30:56 -0500 Subject: [PATCH 5/7] update unit tests --- test/shrinking/shrinking.jl | 27 ++++++++++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/test/shrinking/shrinking.jl b/test/shrinking/shrinking.jl index 30d039d..06114c5 100644 --- a/test/shrinking/shrinking.jl +++ b/test/shrinking/shrinking.jl @@ -36,8 +36,33 @@ using Graphs end boundary_pts = find_boundary_points(n_list, x_min, x_max, y_min, y_max) + # check the boundary points + for p in boundary_pts + p_x, p_y = p + + for i = -1:1 + (p_x == x_min) && (@test(get_UNode_from_pos((p_x - 1, p_y + i), n_list) == nothing)) + (p_x == x_max) && (@test(get_UNode_from_pos((p_x + 1, p_y + i), n_list) == nothing)) + + (p_y == y_min) && (@test(get_UNode_from_pos((p_x + i, p_y - 1), n_list) == nothing)) + (p_x == y_max) && (@test(get_UNode_from_pos((p_x + i, p_y + 1), n_list) == nothing)) + end + end + + # check greedy_step: check that still unit disk graph + n_list2 = greedy_step(n_list, x_min, x_max, y_min, y_max) + + for (i, n) in enumerate(n_list2) + @test(check_UDG_criteria(n, n.pos, n_list) == false) + @test(n.vertices == n_list[i].vertices) + end + + + for (i, n) in enumerate(n_list) - @assert(check_UDG_criteria(n, pos[i], n_list) == false) + @test(check_UDG_criteria(n, pos[i], n_list) == false) end + + end From 1239a9f2392f4ec566037b632ca2b17ff7ba2103 Mon Sep 17 00:00:00 2001 From: Minh-Thi Nguyen Date: Wed, 22 Dec 2021 15:04:26 -0500 Subject: [PATCH 6/7] update shrinking with cost function; still need to implement unit tests --- src/shrinking/shrinking.jl | 137 +++++++++++++++++++++++++++++++++---- 1 file changed, 122 insertions(+), 15 deletions(-) diff --git a/src/shrinking/shrinking.jl b/src/shrinking/shrinking.jl index ef492f9..cbb8c54 100644 --- a/src/shrinking/shrinking.jl +++ b/src/shrinking/shrinking.jl @@ -141,6 +141,122 @@ function unitdisk_graph(locs::AbstractVector, unit::Real) return g end +module CompressUDG +using Graphs +using ..UnitDiskMapping: unitdisk_graph + +export UNode, contract_graph, CompressUDGMethod + +struct UNode + vertex::Int + pos::Tuple{Int, Int} + neighbors::Vector{Int} +end +function Base.(==)(x::UNode, y::UNode) + x.vertex == y.vertex && x.neighbors == y.neighbors +end + +# get surrounding neighbor points on UDG +function get_UDG_neighbors(pos::Tuple{Int, Int}) + # udg radius = 1.5 + p_x, p_y = pos + pos_udg_neighbors = Vector{Tuple{Int, Int}} + + for i = -1:1, j = -1:1 + !(i == 0 && j == 0) && push!(pos_udg_neighbors, (p_x + i, p_y + j)) + end + return pos_udg_neighbors +end + +# find UNode from given position and return nothing if no node in that position +function get_UNode_from_pos(pos::Tuple{Int, Int}, node_list::Vector{UNode}) + for u in node_list + (u.pos == pos) && return u + end + return nothing +end + +# find the center of the graph given list of UNodes +function find_center(node_list::Vector{UNode}) + min_x = typemax(Int) + min_y = typemax(Int) + max_x = 0 + max_y = 0 + + for u in node_list + p_x, p_y = u.pos + (p_x > max_x) && (max_x = p_x) + (p_x < min_x) && (min_x = p_x) + (p_y > max_y) && (max_y = p_y) + (p_y < min_y) && (min_y = p_y) + end + + return (max_x - min_x)/2 + min_x, (max_y - min_y)/2 + min_y +end + +# filter function that checks that new position of node n satisfies UDG requirements +function check_UDG_criteria(n::UNode, new_pos::Tuple{Int, Int}, node_list::Vector{UNode}) + # check if new_pos is already occupied + (get_UNode_from_pos(new_pos, node_list) !== nothing) && return false + + p_x, p_y = new_pos + new_neighbors = Vector{Int}() + + for p in get_udg_neighbors(new_pos) + unode = get_UNode_from_pos(p, node_list) + ((unode !== nothing) && (unode.vertex != n.vertex)) && push!(new_neighbors, unode.vertex) + end + + (issetequal(new_neighbors, n.neighbors)) && return true +end + +# determine cost for a position +# defined as distance from center of graph +function node_cost(pos::Tuple{Int, Int}, node_list::Vector{UNode}) + center_x, center_y = find_center(node_list) + p_x, p_y = pos + return (center_x - p_x)^2 + (center_y - p_y)^2 +end + +# move a node n to minimize cost +function move_node(n::UNode, node_list::Vector{UNode}) + min_cost = node_cost(n.pos, node_list) + + candidates = get_UDG_neighbors(n.pos) + + for p in candidates + if check_UDG_criteria(n, p, node_list) + if node_cost(p, node_list) < min_cost + node_list[n.vertex] = UNode(n.vertex, p, n.neighbors) + return node_list + end + end + end + return node_list, min_cost +end + +function total_cost(node_list::Vector{UNode}) + total_cost = 0 + for n in node_list + total_cost += node_cost(n.pos, node_list) + end + return total_cost +end + +# move all nodes to minimize cost one by one +function greedy_step(node_list::Vector{UNode}) + for n in node_list + node_list, min_cost1 = move_node(n, node_list) + node_list, min_cost2 = move_node(n, node_list) + while min_cost2 != min_cost1 + min_cost1 = min_cost2 + node_list, min_cost2 = move_node(n, node_list) + end + end + + return node_list, total_cost(node_list) +end + # interfaces abstract type CompressUDGMethod end @@ -159,24 +275,15 @@ function contract_graph(node_positions::Vector{Tuple{Int, Int}}) n_list[ind] = UNode(ind, n_pos, neighbors(g, ind)) end - xmin, ymin, xmax, ymax = find_boundaries(n_list) - - - while (xmax - xmin > 1) && (ymax - ymin > 1) - n_list = greedy_step(n_list, xmin, xmax, ymin, ymax) - - if xmin < xmax - xmin += 1 - xmax -= 1 - end - - if ymin < ymax - ymin += 1 - ymax -= 1 - end + n_list, cost = greedy_step(n_list) + n_list, cost2 = greedy_step(n_list) + while cost != cost2 + cost = cost2 + n_list, cost2 = greedy_step(n_list) end + locs_new = Vector{Tuple{Int, Int}}(undef, size(node_positions)[1]) for (ind, un) in enumerate(n_list) locs_new[ind] = un.pos From 3429d0c6ba0c3f4b2fc2d1991db64b37821b34df Mon Sep 17 00:00:00 2001 From: Minh-Thi Nguyen Date: Wed, 22 Dec 2021 16:37:37 -0500 Subject: [PATCH 7/7] update test --- test/shrinking/shrinking.jl | 45 ++----------------------------------- 1 file changed, 2 insertions(+), 43 deletions(-) diff --git a/test/shrinking/shrinking.jl b/test/shrinking/shrinking.jl index 06114c5..2dbc429 100644 --- a/test/shrinking/shrinking.jl +++ b/test/shrinking/shrinking.jl @@ -22,47 +22,6 @@ using Graphs n_list[i] = unode end - # find the boundaries given n_list - x_min, y_min, x_max, y_max = find_boundaries(n_list) - for p in pos - p_x, p_y = p - @test(x_max >= p_x >= x_min) - @test(y_max >= p_y >= y_min) - end - - # test 'get_UNode_from_pos' - for (i, p) in enumerate(pos) - @test n_list[i] == get_UNode_from_pos(p, n_list) - end - - boundary_pts = find_boundary_points(n_list, x_min, x_max, y_min, y_max) - # check the boundary points - for p in boundary_pts - p_x, p_y = p - - for i = -1:1 - (p_x == x_min) && (@test(get_UNode_from_pos((p_x - 1, p_y + i), n_list) == nothing)) - (p_x == x_max) && (@test(get_UNode_from_pos((p_x + 1, p_y + i), n_list) == nothing)) - - (p_y == y_min) && (@test(get_UNode_from_pos((p_x + i, p_y - 1), n_list) == nothing)) - (p_x == y_max) && (@test(get_UNode_from_pos((p_x + i, p_y + 1), n_list) == nothing)) - end - end - - # check greedy_step: check that still unit disk graph - n_list2 = greedy_step(n_list, x_min, x_max, y_min, y_max) - - for (i, n) in enumerate(n_list2) - @test(check_UDG_criteria(n, n.pos, n_list) == false) - @test(n.vertices == n_list[i].vertices) - end - - - - for (i, n) in enumerate(n_list) - @test(check_UDG_criteria(n, pos[i], n_list) == false) - end - - - + # test node_cost + @test(node_cost((find_center(n_list)), n_list) == 0) end