From 7c84267fb73ab5820eb501ced069e65da776bfd1 Mon Sep 17 00:00:00 2001 From: minhthin1028 <84551256+minhthin1028@users.noreply.github.com> Date: Sun, 12 Dec 2021 16:42:08 -0500 Subject: [PATCH 1/6] Create tikz.jl --- src/tikz.jl | 1 + 1 file changed, 1 insertion(+) create mode 100644 src/tikz.jl diff --git a/src/tikz.jl b/src/tikz.jl new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/src/tikz.jl @@ -0,0 +1 @@ + From aa2dfd3ce7049d23b39bf0c4bdb26686cafc13c5 Mon Sep 17 00:00:00 2001 From: Minh-Thi Nguyen Date: Mon, 13 Dec 2021 10:32:05 -0500 Subject: [PATCH 2/6] add canvas --- src/tikz/canvas.jl | 0 src/tikz/generate_graph.jl | 0 src/tikz/graph.tex | 0 3 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 src/tikz/canvas.jl create mode 100644 src/tikz/generate_graph.jl create mode 100644 src/tikz/graph.tex diff --git a/src/tikz/canvas.jl b/src/tikz/canvas.jl new file mode 100644 index 0000000..e69de29 diff --git a/src/tikz/generate_graph.jl b/src/tikz/generate_graph.jl new file mode 100644 index 0000000..e69de29 diff --git a/src/tikz/graph.tex b/src/tikz/graph.tex new file mode 100644 index 0000000..e69de29 From cdcba61913dc398a0129416af592ad296bd5c915 Mon Sep 17 00:00:00 2001 From: minhthin1028 <84551256+minhthin1028@users.noreply.github.com> Date: Mon, 13 Dec 2021 10:48:08 -0500 Subject: [PATCH 3/6] Update canvas.jl --- src/tikz/canvas.jl | 72 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 72 insertions(+) diff --git a/src/tikz/canvas.jl b/src/tikz/canvas.jl index e69de29..cb75928 100644 --- a/src/tikz/canvas.jl +++ b/src/tikz/canvas.jl @@ -0,0 +1,72 @@ +# create canvas for graph +# parameters: width, height, margins, node_sizes +# create transparent/blank canvas +# create grid canvas + +# initiate a blank canvas +function initiate_empty_canvas(Wx=10, Wy=10, scale=1) + # clear text file + rm("tikz_graph.tex") + + # create new file + touch("tikz_graph.tex") + + # open file + io = open("tikz_graph.tex", "w") + + # preamble + init_string = """ + \documentclass[crop,tikz]{standalone} + \usepackage[utf8]{inputenc} + + \begin{document} + \begin{tikzpicture}[scale= $scale, auto = center ] + + \useasboundingbox (-1,-1) rectangle ($Wx,$Wy); + """ + + write(io, init_string) + close(io) +end + +# initiate dotted grid +function initiate_dot_grid(Wx=10, Wy=10, node_size=2) + io = open("tikz_graph.tex", "w") + + circle_preamble = """ + \tikzset{circle node/.style = {circle,inner sep=1pt,draw, fill=white}} + """ + write(circle_preamble, init_string) + + init_grid = """ + \foreach \x in {0,...,$Wx} + \foreach \y in {0,...,$Wy} + { + \fill[fill = gray] (\x,\y) circle ($node_size pt); + } + """ + + write(circle_preamble, init_grid) + close(io) +end + +# close the canvas +function close_canvas() + io = open("tikz_graph.tex", "w") + + close = """ + \end{tikzpicture} + \end{document} + """ + + write(circle_preamble, close) + close(io) +end + + + + + + + + From 0eb7729e263cc5dc625abf2de28fcce16a6c6b2d Mon Sep 17 00:00:00 2001 From: minhthin1028 <84551256+minhthin1028@users.noreply.github.com> Date: Mon, 13 Dec 2021 13:28:39 -0500 Subject: [PATCH 4/6] Update generate_graph.jl --- src/tikz/generate_graph.jl | 141 +++++++++++++++++++++++++++++++++++++ 1 file changed, 141 insertions(+) diff --git a/src/tikz/generate_graph.jl b/src/tikz/generate_graph.jl index e69de29..569d3fe 100644 --- a/src/tikz/generate_graph.jl +++ b/src/tikz/generate_graph.jl @@ -0,0 +1,141 @@ +using Graphs +# create canvas for graph +# parameters: width, height, margins, node_sizes +# create transparent/blank canvas +# create grid canvas +# initiate a blank canvas +function initiate_empty_canvas(xmin = -1, ymin = -1, xmax=10, ymax=10, scale=1) + # clear text file + rm("tikz_graph.tex") + + # create new file + touch("tikz_graph.tex") + + # open file + io = open("tikz_graph.tex", "w") + + # preamble + init_string = """ + \documentclass[crop,tikz]{standalone} + \usepackage[utf8]{inputenc} + + \begin{document} + \begin{tikzpicture}[scale= $scale, auto = center ] + + \useasboundingbox ($xmin, $ymin) rectangle ($xmax,$ymax); + """ + + write(io, init_string) + close(io) +end + +# initiate dotted grid +function initiate_dot_grid(xmin = -1, ymin = -1, xmax=10, ymax=10, node_size=2) + io = open("tikz_graph.tex", "w") + + circle_preamble = """ + \tikzset{circle node/.style = {circle,inner sep=1pt,draw, fill=white}} + """ + write(circle_preamble, init_string) + + init_grid = """ + \foreach \x in {$xmin,...,$xmax} + \foreach \y in {$ymin,...,$ymax} + { + \fill[fill = lightgray] (\x,\y) circle ($node_size pt); + } + """ + + write(circle_preamble, init_grid) + close(io) +end + +# close the canvas +function close_canvas() + io = open("tikz_graph.tex", "w") + + close = """ + \end{tikzpicture} + \end{document} + """ + + write(circle_preamble, close) + close(io) +end + +function initiate_default_node(node_size=20, node_color="black", opacity=100, text_color="white") + io = open("tikz_graph.tex", "w") + node_init = """ + \tikzset{main_node/.style={circle,fill=$node_color !$opacity,draw,minimum size=$node_size pt,inner sep=1pt, + text=$text_color}, + } + """ + write(node_init, close) + close(io) +end + +function add_main_node(p::Int, px::Real, py::Real, label::String, node_color="black", node_text="white") + io = open("tikz_graph.tex", "w") + add_node_txt = """ + \node[main_node, fill = $node_color, text = $node_text] ($p) at ($px,$py) {$label}; + """ + write(node_init, close) + close(io) +end + +function add_edge(v::Int, w::Int, edge_color = "black", edge_thickness = "thick", bend_type="") + io = open("tikz_graph.tex", "w") + add_edge_txt = """ + \draw[draw = $edge_color, $edge_thickness] ($v) to [$bend_type] ($w) + """ + write(node_init, close) + close(io) +end + + +function render_tikz(g::SimpleGraph, locs::AbstractVector, grid_graph=false) + N = nv(g) + + # find bounds of locs + min_x = typemax(Float) + min_y = typemax(Float) + max_x = 0 + max_y = 0 + + n = length(locs) + for i=1:n + px, py = locs[i] + + if px > max_x + max_x = px + end + if px < min_x + min_x = px + end + if py > max_y + max_y = py + end + if py < min_y + min_y = py + end + end + + initiate_empty_canvas(xmin=min_x, ymin = min_y, xmax = max_x, ymax = max_y, scale=1) + if grid_graph == true + initiate_dot_grid(xmin =min_x, ymin =min_y, xmax=max_x, ymax=max_y, node_size=2) + end + + initiate_default_node() + + for v in vertices(g) + add_main_node(v, locs[v][1], locs[v][2], "$v", node_color="black", node_text="white") + end + + for e in edges(g) + v1 = src(e) + v2 = dst(e) + add_edge(v1, v2, edge_color = "black", edge_thickness = "thick", bend_type="") + end + + close_canvas() +end From cbc2f94801ad679c370cd3c83f90b9b021f14ba1 Mon Sep 17 00:00:00 2001 From: Leo Date: Tue, 14 Dec 2021 03:07:17 -0500 Subject: [PATCH 5/6] Tikz graph plot (#18) * simplify weighted (#17) * simplify weighted * automatically general rotated and reflected gadgets * fix simplifier gadgets * new tikz * fix merge * fix bounding box args --- .gitignore | 1 + project/vizgadget.jl | 66 +++++------------ src/UnitDiskMapping.jl | 4 +- src/gadgets.jl | 43 +++++++---- src/mapping.jl | 8 +- src/simplifiers.jl | 40 +++++++--- src/tikz.jl | 1 - src/tikz/graph.tex | 0 src/tikz/tikz.jl | 154 +++++++++++++++++++++++++++++++++++++++ src/weighted.jl | 161 ++++++++++++----------------------------- test/gadgets.jl | 7 ++ test/runtests.jl | 4 + test/simplifiers.jl | 25 ++++++- test/tikz/tikz.jl | 30 ++++++++ 14 files changed, 350 insertions(+), 194 deletions(-) delete mode 100644 src/tikz.jl delete mode 100644 src/tikz/graph.tex create mode 100644 src/tikz/tikz.jl create mode 100644 test/tikz/tikz.jl diff --git a/.gitignore b/.gitignore index 13c6fe9..65f2d73 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ /.vscode/ /Manifest.toml .DS_Store +_local/ \ No newline at end of file diff --git a/project/vizgadget.jl b/project/vizgadget.jl index 023bef7..f8eeeed 100644 --- a/project/vizgadget.jl +++ b/project/vizgadget.jl @@ -1,38 +1,16 @@ -using UnitDiskMapping, Graphs +using UnitDiskMapping.TikzGraph, Graphs +using UnitDiskMapping: crossing_ruleset, Pattern, source_graph, mapped_graph -function command_graph(locs, graph, pins, dx, dy, r, name) - cmd = "" +function command_graph!(canvas, locs, graph, pins, dx, dy, r, name) for (i,loc) in enumerate(locs) if count(==(loc), locs) == 2 - type = 2 - else - type = 1 + Node(loc[1]+dx, loc[2]+dy, fill="none", id="ext-$name$i", minimum_size="$(1.5*r)cm") >> canvas end - cmd *= command_node(loc[1]+dx, loc[2]+dy, type, i ∈ pins, "$name$i", r) * "\n" + Node(loc[1]+dx, loc[2]+dy, fill=i∈pins ? "red" : "black", draw="none", id="$name$i", minimum_size="$(r)cm") >> canvas end for e in edges(graph) - cmd *= command_edge("$name$(e.src)", "$name$(e.dst)") * "\n" + Line("$name$(e.src)", "$name$(e.dst)"; line_width=1.0) >> canvas end - return cmd -end - -function command_node(x, y, type::Int, ispin::Bool, id, r) - if type == 2 - return "\\node[fill=black,circle,radius=$(r)cm,inner sep=0cm, minimum size=$(r)cm] at ($x, $y) () {};\n\\node[draw=black,fill=none,circle,radius=$(1.5*r)cm,minimum size=$(1.5*r)cm,inner sep=0cm] at ($x, $y) ($id) {};" - elseif abs(type) == 1 - if ispin - color = "red" - else - color = "black" - end - return "\\node[fill=$color,circle,radius=$(r)cm,inner sep=0cm, minimum size=$(r)cm] at ($x, $y) ($id) {};" - else - error("") - end -end - -function command_edge(i, j) - return "\\draw[thick] ($i) -- ($j);" end function viz_gadget(p::Pattern) @@ -45,28 +23,22 @@ function viz_gadget(p::Pattern) xmid, ymid = Wx/2-0.5, Wy/2-0.5 dx1, dy1 = xmid-Gx, 0 dx2, dy2 = xmid+1, 0 - source_nodes = command_graph(locs1, g1, pin1, dx1, dy1, 0.3, "s") - mapped_nodes = command_graph(locs2, g2, pin2, dx2, dy2, 0.3, "d") - return """ -\\documentclass[crop,tikz]{standalone}% 'crop' is the default for v1.0, before it was 'preview' -\\begin{document} -\\begin{tikzpicture}[scale=0.8] - \\useasboundingbox (-1,-1) rectangle ($Wx,$Wy); - \\draw[step=1cm,gray,very thin] ($dx1,$(dy1)) grid ($(Gx+dx1-1),$(Gy+dy1-1)); - $source_nodes - \\draw[step=1cm,gray,very thin] ($dx2,$(dy2)) grid ($(Gx+dx2-1),$(Gy+dy2-1)); - $mapped_nodes - \\node at ($xmid, $ymid) {\$\\mathbf{\\rightarrow}\$}; -\\end{tikzpicture} - -\\end{document} -""" + return canvas(; props=Dict("scale"=>"0.8")) do c + BoundingBox(-1,Wx-1,-1,Wy-1) >> c + Mesh(dx1, Gx+dx1-1, dy1, Gy+dy1-1; step="1cm", draw=rgbcolor!(c, 100,200,200), line_width=0.5) >> c + command_graph!(c, locs1, g1, pin1, dx1, dy1, 0.3, "s") + Mesh(dx2, Gx+dx2-1, dy2, Gy+dy2-1; step="1cm", draw=rgbcolor!(c, 200,100,100), line_width=0.03) >> c + command_graph!(c, locs2, g2, pin2, dx2, dy2, 0.3, "d") + PlainText(xmid, ymid, "\$\\mathbf{\\rightarrow}\$") >> c + end end function pattern2tikz(folder::String) - for (p, sub) in UnitDiskMapping.crossing_ruleset - open(joinpath(folder, sub*"-udg.tex"), "w") do f + for p in crossing_ruleset + open(joinpath(folder, string(typeof(p).name.name)*"-udg.tex"), "w") do f write(f, viz_gadget(p)) end end -end \ No newline at end of file +end + +pattern2tikz(joinpath("_local")) \ No newline at end of file diff --git a/src/UnitDiskMapping.jl b/src/UnitDiskMapping.jl index ee3a7ab..e757af8 100644 --- a/src/UnitDiskMapping.jl +++ b/src/UnitDiskMapping.jl @@ -12,11 +12,11 @@ export UNode, contract_graph, compress_graph include("utils.jl") include("gadgets.jl") -include("simplifiers.jl") include("mapping.jl") include("weighted.jl") +include("simplifiers.jl") include("extracting_results.jl") include("pathdecomposition/pathdecomposition.jl") -#include("shrinking/compressUDG.jl") +include("tikz/tikz.jl") end diff --git a/src/gadgets.jl b/src/gadgets.jl index ad6c589..63c2fd5 100644 --- a/src/gadgets.jl +++ b/src/gadgets.jl @@ -19,8 +19,8 @@ abstract type Pattern end """ abstract type CrossPattern <: Pattern end -abstract type Node end -struct SimpleNode{T} <: Node +abstract type AbstractNode end +struct SimpleNode{T} <: AbstractNode x::T y::T end @@ -28,11 +28,11 @@ SimpleNode(xy::Tuple{Int,Int}) = SimpleNode(xy...) SimpleNode(xy::Vector{Int}) = SimpleNode(xy...) getxy(p::SimpleNode) = (p.x, p.y) chxy(p::SimpleNode, loc) = SimpleNode(loc...) -Base.iterate(p::Node, i) = Base.iterate((p.x, p.y), i) -Base.iterate(p::Node) = Base.iterate((p.x, p.y)) -Base.length(p::Node) = 2 -Base.getindex(p::Node, i::Int) = i==1 ? p.x : (@assert i==2; p.y) -offset(p::Node, xy) = chxy(p, getxy(p) .+ xy) +Base.iterate(p::AbstractNode, i) = Base.iterate((p.x, p.y), i) +Base.iterate(p::AbstractNode) = Base.iterate((p.x, p.y)) +Base.length(p::AbstractNode) = 2 +Base.getindex(p::AbstractNode, i::Int) = i==1 ? p.x : (@assert i==2; p.y) +offset(p::AbstractNode, xy) = chxy(p, getxy(p) .+ xy) export source_matrix, mapped_matrix function source_matrix(p::Pattern) @@ -53,7 +53,7 @@ function mapped_matrix(p::Pattern) locs2matrix(m, n, locs) end -function locs2matrix(m, n, locs::AbstractVector{NT}) where NT <: Node +function locs2matrix(m, n, locs::AbstractVector{NT}) where NT <: AbstractNode a = fill(empty(_cell_type(NT)), m, n) for loc in locs add_cell!(a, loc) @@ -386,16 +386,17 @@ for T in [:RotatedGadget, :ReflectedGadget] @eval mis_overhead(p::$T) = mis_overhead(p.gadget) end -function _apply_transform(r::RotatedGadget, node::Node, center) - loc = getxy(node) +for T in [:RotatedGadget, :ReflectedGadget] + @eval _apply_transform(r::$T, node::AbstractNode, center) = chxy(node, _apply_transform(r, getxy(node), center)) +end +function _apply_transform(r::RotatedGadget, loc::Tuple{Int,Int}, center) for _=1:r.n loc = rotate90(loc, center) end - return chxy(node, loc) + return loc end -function _apply_transform(r::ReflectedGadget, node::Node, center) - loc = getxy(node) +function _apply_transform(r::ReflectedGadget, loc::Tuple{Int,Int}, center) loc = if r.mirror == "x" reflectx(loc, center) elseif r.mirror == "y" @@ -407,7 +408,7 @@ function _apply_transform(r::ReflectedGadget, node::Node, center) else throw(ArgumentError("reflection direction $(r.direction) is not defined!")) end - chxy(node, loc) + return loc end export vertex_overhead @@ -429,3 +430,17 @@ function _boundary_config(pins, config) end return res end + +export rotated_and_reflected +function rotated_and_reflected(p::Pattern) + patterns = Pattern[p] + source_matrices = [source_matrix(p)] + for pi in [[RotatedGadget(p, i) for i=1:3]..., [ReflectedGadget(p, axis) for axis in ["x", "y", "diag", "offdiag"]]...] + m = source_matrix(pi) + if m ∉ source_matrices + push!(patterns, pi) + push!(source_matrices, m) + end + end + return patterns +end \ No newline at end of file diff --git a/src/mapping.jl b/src/mapping.jl index 2497db4..b6e1383 100644 --- a/src/mapping.jl +++ b/src/mapping.jl @@ -373,8 +373,10 @@ It can be a vector or one of the following inputs Returns a `MappingResult` instance. """ -map_graph(g::SimpleGraph; vertex_order=Greedy(), ruleset=[RotatedGadget(DanglingLeg(), n) for n=0:3]) = map_graph(UnWeighted(), g; ruleset=ruleset, vertex_order=vertex_order) -function map_graph(mode, g::SimpleGraph; vertex_order=Greedy(), ruleset=[RotatedGadget(DanglingLeg(), n) for n=0:3]) +function map_graph(g::SimpleGraph; vertex_order=Greedy(), ruleset=default_simplifier_ruleset(UnWeighted())) + map_graph(UnWeighted(), g; ruleset=ruleset, vertex_order=vertex_order) +end +function map_graph(mode, g::SimpleGraph; vertex_order=Greedy(), ruleset=default_simplifier_ruleset(mode)) ug = embed_graph(mode, g; vertex_order=vertex_order) mis_overhead0 = mis_overhead_copylines(ug) ug, tape = apply_crossing_gadgets!(mode, ug) @@ -385,3 +387,5 @@ function map_graph(mode, g::SimpleGraph; vertex_order=Greedy(), ruleset=[Rotated 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 diff --git a/src/simplifiers.jl b/src/simplifiers.jl index 0542ade..d68c21e 100644 --- a/src/simplifiers.jl +++ b/src/simplifiers.jl @@ -26,35 +26,42 @@ function vertices_on_boundary(locs, m, n) findall(loc->loc[1]==1 || loc[1]==m || loc[2]==1 || loc[2]==n, locs) end -struct GridGraph{NT<:Node} +struct GridGraph{NT<:AbstractNode} size::Tuple{Int,Int} nodes::Vector{NT} end vertices_on_boundary(gg::GridGraph) = vertices_on_boundary(gg.nodes, gg.size...) -function gridgraphfromstring(str::String) - item_array = Vector{Bool}[] +function gridgraphfromstring(mode::Union{Weighted, UnWeighted}, str::String) + item_array = Vector{Int}[] for line in split(str, "\n") - list = [item ∈ ("o", "●") ? true : (@assert item ∈ (".", "⋅"); false) for item in split(line, " ") if !isempty(item)] + items = [item for item in split(line, " ") if !isempty(item)] + list = if mode isa Weighted # TODO: the weighted version need to be tested! Consider removing it! + @assert all(item->item ∈ (".", "⋅", "@", "●", "o", "◯"), items) + [item ∈ ("@", "●") ? 2 : (item ∈ ("o", "◯") ? 1 : 0) for item in items] + else + @assert all(item->item ∈ (".", "⋅", "@", "●"), items) + [item ∈ ("@", "●") ? 1 : 0 for item in items] + end if !isempty(list) push!(item_array, list) end end @assert all(==(length(item_array[1])), length.(item_array)) mat = hcat(item_array...)' - locs = [SimpleNode(ci.I) for ci in findall(mat)] + locs = [_to_node(mode, ci.I, mat[ci]) for ci in findall(!iszero, mat)] return GridGraph(size(mat), locs) end +_to_node(::UnWeighted, loc::Tuple{Int,Int}, w::Int) = SimpleNode(loc...) +_to_node(::Weighted, loc::Tuple{Int,Int}, w::Int) = WeightedNode(loc..., w) -const simplifier_ruleset = SimplifyPattern[] - -macro gg(expr) +function gg_func(mode, expr) @assert expr.head == :(=) name = expr.args[1] pair = expr.args[2] @assert pair.head == :(call) && pair.args[1] == :(=>) - g1 = gridgraphfromstring(pair.args[2]) - g2 = gridgraphfromstring(pair.args[3]) + g1 = gridgraphfromstring(mode, pair.args[2]) + g2 = gridgraphfromstring(mode, pair.args[3]) @assert g1.size == g2.size @assert g1.nodes[vertices_on_boundary(g1)] == g2.nodes[vertices_on_boundary(g2)] return quote @@ -62,11 +69,14 @@ macro gg(expr) Base.size(::$(esc(name))) = $(g1.size) $UnitDiskMapping.source_locations(::$(esc(name))) = $(g1.nodes) $UnitDiskMapping.mapped_locations(::$(esc(name))) = $(g2.nodes) - push!($(simplifier_ruleset), $(esc(name))()) $(esc(name)) end end +macro gg(expr) + gg_func(UnWeighted(), expr) +end + # # How to add a new simplification rule # 1. specify a gadget like the following. Use either `o` and `●` to specify a vertex, # either `.` or `⋅` to specify a placeholder. @@ -83,5 +93,11 @@ end ⋅ ● ⋅ """ -# 2. run the script `project/createmap` to generate `mis_overhead` and other informations required +# 2. add your gadget to simplifier ruleset. +const simplifier_ruleset = SimplifyPattern[DanglingLeg()] +# 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 diff --git a/src/tikz.jl b/src/tikz.jl deleted file mode 100644 index 8b13789..0000000 --- a/src/tikz.jl +++ /dev/null @@ -1 +0,0 @@ - diff --git a/src/tikz/graph.tex b/src/tikz/graph.tex deleted file mode 100644 index e69de29..0000000 diff --git a/src/tikz/tikz.jl b/src/tikz/tikz.jl new file mode 100644 index 0000000..a69ba22 --- /dev/null +++ b/src/tikz/tikz.jl @@ -0,0 +1,154 @@ +module TikzGraph +export rgbcolor!, Node, Line, BoundingBox, Mesh, Canvas, >>, command, canvas, generate_standalone, StringElement, PlainText + +const instance_counter = Ref(0) +abstract type AbstractTikzElement end + +struct Canvas + header::String + colors::Dict{String, Tuple{Int,Int,Int}} + contents::Vector{AbstractTikzElement} + props::Dict{String,String} +end + +function canvas(f; header="", colors=Dict{String,Tuple{Int,Int,Int}}(), props=Dict{String,String}()) + canvas = Canvas(header, colors, AbstractTikzElement[], props) + f(canvas) + return canvas +end + +Base.:(>>)(element::AbstractTikzElement, canvas::Canvas) = push!(canvas.contents, element) +Base.:(>>)(element::String, canvas::Canvas) = push!(canvas.contents, StringElement(element)) + +function rgbcolor!(canvas::Canvas, red::Int, green::Int, blue::Int) + instance_counter[] += 1 + colorname = "color$(instance_counter[])" + canvas.colors[colorname] = (red,green,blue) + return colorname +end +function generate_rgbcolor(name, red, green, blue) + return "\\definecolor{$name}{RGB}{$red,$green,$blue}" +end + +struct StringElement <: AbstractTikzElement + str::String +end +command(s::StringElement) = s.str + +struct BoundingBox <: AbstractTikzElement + xmin::Float64 + xmax::Float64 + ymin::Float64 + ymax::Float64 +end +function command(box::BoundingBox) + return "\\useasboundingbox ($(box.xmin),$(box.ymin)) rectangle ($(box.xmax-box.xmin),$(box.ymax-box.ymin));" +end + +struct Node <: AbstractTikzElement + x::Float64 + y::Float64 + shape::String + id::String + text::String + props::Dict{String,String} +end + +function Node(x, y; + shape::String = "circle", + id = string((instance_counter[] += 1; instance_counter[])), + text::String = "", + fill = "none", + draw = "black", + inner_sep = "0cm", + minimum_size = "0.2cm", + line_width = 0.03, + kwargs...) + props = build_props(; + fill = fill, + draw = draw, + inner_sep = inner_sep, + minimum_size = minimum_size, + line_width = line_width, + kwargs...) + return Node(x, y, shape, id, text, props) +end +function build_props(; kwargs...) + Dict([replace(string(k), "_"=>" ")=>string(v) for (k,v) in kwargs]) +end + +function command(node::Node) + return "\\node[$(node.shape), $(command(node.props))] at ($(node.x), $(node.y)) ($(node.id)) {$(node.text)};" +end + +struct Mesh <: AbstractTikzElement + xmin::Float64 + xmax::Float64 + ymin::Float64 + ymax::Float64 + props::Dict{String,String} +end + +function Mesh(xmin, xmax, ymin, ymax; step="1.0cm", draw="gray", line_width=0.03, kwargs...) + Mesh(xmin, xmax, ymin, ymax, build_props(; step=step, draw=draw, line_width=line_width, kwargs...)) +end +function command(grid::Mesh) + return "\\draw[$(command(grid.props))] ($(grid.xmin),$(grid.ymin)) grid ($(grid.xmax),$(grid.ymax));" +end + +struct Line <: AbstractTikzElement + src::String + dst::String + controls::Vector{Int} + props::Dict{String,String} +end + +function Line(src, dst; controls=Int[], line_width = "0.03", kwargs...) + Line(string(src), string(dst), controls, build_props(; line_width=line_width, kwargs...)) +end +Line(src::Node, dst::Node; kwargs...) = Line(src.id, dst.id) + +function command(edge::Line) + head = "\\draw[$(command(edge.props))]" + if isempty(edge.controls) + return "$head ($(edge.src)) -- ($(edge.dst));" + else + return "$head ($(edge.src)) .. controls $(join(["($c)" for c in edge.controls], " and ")) .. ($(edge.dst));" + end +end + +struct PlainText <: AbstractTikzElement + x::Float64 + y::Float64 + text::String + props::Dict{String,String} +end +function PlainText(x, y, text; kwargs...) + PlainText(x, y, text, build_props(; kwargs...)) +end +function command(text::PlainText) + "\\node[$(command(text.props))] at ($(text.x), $(text.y)) {$(text.text)};" +end + +function command(node::Dict) # properties + return join(["$k=$v" for (k,v) in node], ", ") +end + +function generate_standalone(header::String, props::Dict, content::String) + return """ +\\documentclass[crop,tikz]{standalone} +$(header) +\\begin{document} +\\begin{tikzpicture}[$(command(props))] +$content +\\end{tikzpicture} +\\end{document} +""" +end +generate_standalone(canvas::Canvas) = generate_standalone(canvas.header, canvas.props, join([[generate_rgbcolor(k,v...) for (k,v) in canvas.colors]..., command.(canvas.contents)...], "\n")) + +function Base.write(io::IO, canvas::Canvas) + write(io, generate_standalone(canvas)) +end + +end \ No newline at end of file diff --git a/src/weighted.jl b/src/weighted.jl index b831d3f..ca6e123 100644 --- a/src/weighted.jl +++ b/src/weighted.jl @@ -1,3 +1,4 @@ +export WeightedCell, WeightedGadget, WeightedNode # TODO: # * add path decomposition struct WeightedCell{RT} <: AbstractCell @@ -7,13 +8,10 @@ struct WeightedCell{RT} <: AbstractCell weight::RT end -abstract type WeightedCrossPattern <: Pattern end -abstract type WeightedSimplifyPattern <:Pattern end struct WeightedGadget{GT} <: Pattern gadget::GT - factor::Int end -const WeightedPattern = Union{WeightedCrossPattern, WeightedSimplifyPattern, WeightedGadget} +const WeightedGadgetTypes = Union{WeightedGadget, RotatedGadget{<:WeightedGadget}, ReflectedGadget{<:WeightedGadget}} Base.isempty(cell::WeightedCell) = !cell.occupied Base.empty(::Type{WeightedCell{RT}}) where RT = WeightedCell(false, false, false,0) @@ -34,7 +32,7 @@ function Base.show(io::IO, x::WeightedCell) end Base.show(io::IO, ::MIME"text/plain", cl::WeightedCell) = Base.show(io, cl) -struct WeightedNode{T,WT} <: Node +struct WeightedNode{T,WT} <: AbstractNode x::T y::T weight::WT @@ -62,126 +60,49 @@ _weight2(::CopyLine{Weighted}, i, j) = WeightedNode(i, j, 2) _weight1(::CopyLine{Weighted}, i, j) = WeightedNode(i, j, 1) _cell_type(::Type{<:WeightedNode}) = WeightedCell{Int} -function source_graph(r::WeightedGadget) - locs, g, pins = source_graph(r.gadget) - _mul_weight.(locs, r.factor), g, pins -end -function mapped_graph(r::WeightedGadget) - locs, g, pins = mapped_graph(r.gadget) - _mul_weight.(locs, r.factor), g, pins -end -_mul_weight(node::SimpleNode, factor) = WeightedNode(node..., factor) -mis_overhead(p::WeightedGadget) = 2*mis_overhead(p.gadget) - -# new gadgets -struct WeightedWTurn <: WeightedCrossPattern end -# ⋅ ⋅ ⋅ ⋅ -# ⋅ ⋅ ◯ ● -# ⋅ ● ● ⋅ -# ⋅ ● ⋅ ⋅ - -# ⋅ ⋅ ⋅ ⋅ -# ⋅ ⋅ ⋅ ● -# ⋅ ⋅ ◯ ⋅ -# ⋅ ● ⋅ ⋅ - -struct WeightedBranchFix <: WeightedCrossPattern end -# ⋅ ● ⋅ ⋅ -# ⋅ ● ◯ ⋅ -# ⋅ ● ● ⋅ -# ⋅ ● ⋅ ⋅ - -# ⋅ ● ⋅ ⋅ -# ⋅ ● ⋅ ⋅ -# ⋅ ◯ ⋅ ⋅ -# ⋅ ● ⋅ ⋅ - -struct WeightedTurn <: WeightedCrossPattern end -# ⋅ ● ⋅ ⋅ -# ⋅ ● ⋅ ⋅ -# ⋅ ● ◯ ● -# ⋅ ⋅ ⋅ ⋅ - -# ⋅ ● ⋅ ⋅ -# ⋅ ⋅ ◯ ⋅ -# ⋅ ⋅ ⋅ ● -# ⋅ ⋅ ⋅ ⋅ - -struct WeightedBranch <: WeightedCrossPattern end -# ⋅ ● ⋅ ⋅ -# ⋅ ● ⋅ ⋅ -# ⋅ ● ◯ ● -# ⋅ ● ● ⋅ -# ⋅ ● ⋅ ⋅ - - -# ⋅ ● ⋅ ⋅ ? -# ⋅ ⋅ ◯ ⋅ -# ⋅ ● ⋅ ● -# ⋅ ⋅ ● ⋅ -# ⋅ ● ⋅ ⋅ - -struct WeightedBranchFixB <: WeightedCrossPattern end -# ⋅ ⋅ ⋅ ⋅ -# ⋅ ⋅ ◯ ⋅ -# ⋅ ● ● ⋅ -# ⋅ ● ⋅ ⋅ - -# ⋅ ⋅ ⋅ ⋅ -# ⋅ ⋅ ⋅ ⋅ -# ⋅ ◯ ⋅ ⋅ -# ⋅ ● ⋅ ⋅ - -struct WeightedEndTurn <: WeightedCrossPattern end -# ⋅ ● ⋅ ⋅ -# ⋅ ● ◯ ⋅ -# ⋅ ⋅ ⋅ ⋅ - -# ⋅ ◯ ⋅ ⋅ -# ⋅ ⋅ ⋅ ⋅ -# ⋅ ⋅ ⋅ ⋅ - -for T in [:Cross, :TrivialTurn, :TCon] - @eval weighted(c::$T) = WeightedGadget(c, 2) -end +weighted(c::Pattern) = WeightedGadget(c) unweighted(w::WeightedGadget) = w.gadget weighted(r::RotatedGadget) = RotatedGadget(weighted(r.gadget), r.n) weighted(r::ReflectedGadget) = ReflectedGadget(weighted(r.gadget), r.mirror) unweighted(r::RotatedGadget) = RotatedGadget(unweighted(r.gadget), r.n) unweighted(r::ReflectedGadget) = ReflectedGadget(unweighted(r.gadget), r.mirror) +mis_overhead(w::WeightedGadget) = mis_overhead(w.gadget) * 2 -for T in [:Turn, :Branch, :BranchFix, :BranchFixB, :WTurn, :EndTurn] - WT = Symbol(:Weighted, T) - @eval weighted(::$T) = $WT() - @eval unweighted(::$WT) = $T() - @eval mis_overhead(::$WT) = mis_overhead($T()) * 2 +function source_graph(r::WeightedGadget) + raw = unweighted(r) + locs, g, pins = source_graph(raw) + return map(loc->_mul_weight(loc, getxy(loc) ∈ source_centers(r) ? 1 : 2), locs), g, pins +end +function mapped_graph(r::WeightedGadget) + raw = unweighted(r) + locs, g, pins = mapped_graph(raw) + return map(loc->_mul_weight(loc, getxy(loc) ∈ mapped_centers(r) ? 1 : 2), locs), g, pins end +_mul_weight(node::SimpleNode, factor) = WeightedNode(node..., factor) for (T, centerloc) in [(:Turn, (2, 3)), (:Branch, (2, 3)), (:BranchFix, (3, 2)), (:BranchFixB, (3, 2)), (:WTurn, (3, 3)), (:EndTurn, (1, 2))] - WT = Symbol(:Weighted, T) - @eval function source_graph(r::$WT) - raw = unweighted(r) - locs, g, pins = source_graph(raw) - return map(loc->_mul_weight(loc, loc == SimpleNode(cross_location(raw) .+ (0, 1)) ? 1 : 2), locs), g, pins - end - @eval function mapped_graph(r::$WT) - raw = unweighted(r) - locs, g, pins = mapped_graph(raw) - return map(loc->_mul_weight(loc, loc == SimpleNode($centerloc) ? 1 : 2), locs), g, pins + @eval source_centers(::WeightedGadget{<:$T}) = [cross_location($T()) .+ (0, 1)] + @eval mapped_centers(::WeightedGadget{<:$T}) = [$centerloc] +end +# default to having no source center! +source_centers(::WeightedGadget) = Tuple{Int,Int}[] +mapped_centers(::WeightedGadget) = Tuple{Int,Int}[] +for T in [:(RotatedGadget{<:WeightedGadget}), :(ReflectedGadget{<:WeightedGadget})] + @eval function source_centers(r::$T) + cross = cross_location(r.gadget) + return map(loc->loc .+ _get_offset(r), _apply_transform.(Ref(r), source_centers(r.gadget), Ref(cross))) end - @eval function move_center(::$WT, nodexy) - nodexy .+ $centerloc .- (cross_location($WT()) .+ (0, 1)) + @eval function mapped_centers(r::$T) + cross = cross_location(r.gadget) + return map(loc->loc .+ _get_offset(r), _apply_transform.(Ref(r), mapped_centers(r.gadget), Ref(cross))) end end -move_center(::Pattern, nodexy) = nodexy -for T in [:WeightedCrossPattern, :WeightedGadget] - @eval Base.size(r::$T) = size(unweighted(r)) - @eval cross_location(r::$T) = cross_location(unweighted(r)) - @eval iscon(r::$T) = iscon(unweighted(r)) - @eval connected_nodes(r::$T) = connected_nodes(unweighted(r)) - @eval vertex_overhead(r::$T) = vertex_overhead(unweighted(r)) -end +Base.size(r::WeightedGadget) = size(unweighted(r)) +cross_location(r::WeightedGadget) = cross_location(unweighted(r)) +iscon(r::WeightedGadget) = iscon(unweighted(r)) +connected_nodes(r::WeightedGadget) = connected_nodes(unweighted(r)) +vertex_overhead(r::WeightedGadget) = vertex_overhead(unweighted(r)) const crossing_ruleset_weighted = weighted.(crossing_ruleset) get_ruleset(::Weighted) = crossing_ruleset_weighted @@ -189,16 +110,26 @@ get_ruleset(::Weighted) = crossing_ruleset_weighted export get_weights get_weights(ug::UGrid) = [ug.content[ci...].weight for ci in coordinates(ug)] +# mapping configurations back export trace_centers +function move_center(w::WeightedGadgetTypes, nodexy, offset) + for (sc, mc) in zip(source_centers(w), mapped_centers(w)) + if offset == sc + return nodexy .+ mc .- sc # found + end + end + error("center not found, source center = $(source_centers(w)), while offset = $(offset)") +end + trace_centers(r::MappingResult) = trace_centers(r.grid_graph, r.mapping_history) function trace_centers(ug::UGrid, tape) center_locations = map(x->center_location(x; padding=ug.padding) .+ (0, 1), ug.lines) for (gadget, i, j) in tape m, n = size(gadget) for (k, centerloc) in enumerate(center_locations) - offset = centerloc .- (i,j) - if 0<=offset[1] <= m-1 && 0<=offset[2] <= n-1 - center_locations[k] = move_center(gadget, centerloc) + offset = centerloc .- (i-1,j-1) + if 1<=offset[1] <= m && 1<=offset[2] <= n + center_locations[k] = move_center(gadget, centerloc, offset) end end end diff --git a/test/gadgets.jl b/test/gadgets.jl index db965f0..a7185ff 100644 --- a/test/gadgets.jl +++ b/test/gadgets.jl @@ -16,4 +16,11 @@ using Graphs @test diff == -mis_overhead(s) @test sig end +end + +@testset "rotated_and_reflected" begin + @test length(rotated_and_reflected(UnitDiskMapping.DanglingLeg())) == 4 + @test length(rotated_and_reflected(Cross{false}())) == 4 + @test length(rotated_and_reflected(Cross{true}())) == 4 + @test length(rotated_and_reflected(BranchFixB())) == 8 end \ No newline at end of file diff --git a/test/runtests.jl b/test/runtests.jl index fbb46ae..90f0e13 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -28,3 +28,7 @@ end @testset "weighted" begin include("weighted.jl") end + +@testset "tikz" begin + include("tikz/tikz.jl") +end diff --git a/test/simplifiers.jl b/test/simplifiers.jl index d4b2751..cf56565 100644 --- a/test/simplifiers.jl +++ b/test/simplifiers.jl @@ -1,8 +1,31 @@ -using UnitDiskMapping, Test +using UnitDiskMapping, Test, Graphs @testset "constructor" begin p = UnitDiskMapping.DanglingLeg() @test size(p) == (4, 3) @test UnitDiskMapping.source_locations(p) == UnitDiskMapping.SimpleNode.([(2,2), (3,2), (4,2)]) @test UnitDiskMapping.mapped_locations(p) == UnitDiskMapping.SimpleNode.([(4,2)]) +end + +@testset "macros" begin + @gg Test1 = """ + . . . . + . . @ . + . @ . . + . @ . . + """ => """ + . . . . + . . . . + . . . . + . @ . . + """ + sl, sg, sp = source_graph(Test1()) + ml, mg, mp = mapped_graph(Test1()) + @show sg, collect(edges(sg)) + @test sl == UnitDiskMapping.SimpleNode.([(3, 2), (4,2), (2, 3)]) + @test sg == UnitDiskMapping.simplegraph([(1,2), (1,3)]) + @test sp == [2] + @test ml == [UnitDiskMapping.SimpleNode(4,2)] + @test mg == UnitDiskMapping.SimpleGraph(1) + @test mp == [1] end \ No newline at end of file diff --git a/test/tikz/tikz.jl b/test/tikz/tikz.jl new file mode 100644 index 0000000..182c203 --- /dev/null +++ b/test/tikz/tikz.jl @@ -0,0 +1,30 @@ +using UnitDiskMapping.TikzGraph, Test + +@testset "commands" begin + n = Node(0.2, 0.5) + @test command(n) isa String + m = Node(0.6, 0.5) + @test command(n) isa String + l = Line(m, n) + @test command(n) isa String + b = BoundingBox(0, 10, 0, 10) + @test command(b) isa String + g = Mesh(0, 10, 0, 10) + @test command(g) isa String + s = StringElement("jajaja") + @test command(s) == "jajaja" + s = PlainText(20.0, 3.0, "jajaja") + @test command(s) isa String +end + +@testset "canvas" begin + res = canvas() do c + Node(0.2, 0.5; draw=rgbcolor!(c, 21, 42, 36)) >> c + "jajaja" >> c + end + @test res isa Canvas + @test generate_standalone(res) isa String + write("test.tex", res) + @test isfile("test.tex") + rm("test.tex") +end \ No newline at end of file From 769fcce302f087d6c4f54f57f3f5dd2cc2993dd5 Mon Sep 17 00:00:00 2001 From: GiggleLiu Date: Tue, 14 Dec 2021 11:53:04 -0500 Subject: [PATCH 6/6] clean up --- src/tikz/canvas.jl | 72 ------------------- src/tikz/generate_graph.jl | 141 ------------------------------------- 2 files changed, 213 deletions(-) delete mode 100644 src/tikz/canvas.jl delete mode 100644 src/tikz/generate_graph.jl diff --git a/src/tikz/canvas.jl b/src/tikz/canvas.jl deleted file mode 100644 index cb75928..0000000 --- a/src/tikz/canvas.jl +++ /dev/null @@ -1,72 +0,0 @@ -# create canvas for graph -# parameters: width, height, margins, node_sizes -# create transparent/blank canvas -# create grid canvas - -# initiate a blank canvas -function initiate_empty_canvas(Wx=10, Wy=10, scale=1) - # clear text file - rm("tikz_graph.tex") - - # create new file - touch("tikz_graph.tex") - - # open file - io = open("tikz_graph.tex", "w") - - # preamble - init_string = """ - \documentclass[crop,tikz]{standalone} - \usepackage[utf8]{inputenc} - - \begin{document} - \begin{tikzpicture}[scale= $scale, auto = center ] - - \useasboundingbox (-1,-1) rectangle ($Wx,$Wy); - """ - - write(io, init_string) - close(io) -end - -# initiate dotted grid -function initiate_dot_grid(Wx=10, Wy=10, node_size=2) - io = open("tikz_graph.tex", "w") - - circle_preamble = """ - \tikzset{circle node/.style = {circle,inner sep=1pt,draw, fill=white}} - """ - write(circle_preamble, init_string) - - init_grid = """ - \foreach \x in {0,...,$Wx} - \foreach \y in {0,...,$Wy} - { - \fill[fill = gray] (\x,\y) circle ($node_size pt); - } - """ - - write(circle_preamble, init_grid) - close(io) -end - -# close the canvas -function close_canvas() - io = open("tikz_graph.tex", "w") - - close = """ - \end{tikzpicture} - \end{document} - """ - - write(circle_preamble, close) - close(io) -end - - - - - - - - diff --git a/src/tikz/generate_graph.jl b/src/tikz/generate_graph.jl deleted file mode 100644 index 569d3fe..0000000 --- a/src/tikz/generate_graph.jl +++ /dev/null @@ -1,141 +0,0 @@ -using Graphs -# create canvas for graph -# parameters: width, height, margins, node_sizes -# create transparent/blank canvas -# create grid canvas -# initiate a blank canvas -function initiate_empty_canvas(xmin = -1, ymin = -1, xmax=10, ymax=10, scale=1) - # clear text file - rm("tikz_graph.tex") - - # create new file - touch("tikz_graph.tex") - - # open file - io = open("tikz_graph.tex", "w") - - # preamble - init_string = """ - \documentclass[crop,tikz]{standalone} - \usepackage[utf8]{inputenc} - - \begin{document} - \begin{tikzpicture}[scale= $scale, auto = center ] - - \useasboundingbox ($xmin, $ymin) rectangle ($xmax,$ymax); - """ - - write(io, init_string) - close(io) -end - -# initiate dotted grid -function initiate_dot_grid(xmin = -1, ymin = -1, xmax=10, ymax=10, node_size=2) - io = open("tikz_graph.tex", "w") - - circle_preamble = """ - \tikzset{circle node/.style = {circle,inner sep=1pt,draw, fill=white}} - """ - write(circle_preamble, init_string) - - init_grid = """ - \foreach \x in {$xmin,...,$xmax} - \foreach \y in {$ymin,...,$ymax} - { - \fill[fill = lightgray] (\x,\y) circle ($node_size pt); - } - """ - - write(circle_preamble, init_grid) - close(io) -end - -# close the canvas -function close_canvas() - io = open("tikz_graph.tex", "w") - - close = """ - \end{tikzpicture} - \end{document} - """ - - write(circle_preamble, close) - close(io) -end - -function initiate_default_node(node_size=20, node_color="black", opacity=100, text_color="white") - io = open("tikz_graph.tex", "w") - node_init = """ - \tikzset{main_node/.style={circle,fill=$node_color !$opacity,draw,minimum size=$node_size pt,inner sep=1pt, - text=$text_color}, - } - """ - write(node_init, close) - close(io) -end - -function add_main_node(p::Int, px::Real, py::Real, label::String, node_color="black", node_text="white") - io = open("tikz_graph.tex", "w") - add_node_txt = """ - \node[main_node, fill = $node_color, text = $node_text] ($p) at ($px,$py) {$label}; - """ - write(node_init, close) - close(io) -end - -function add_edge(v::Int, w::Int, edge_color = "black", edge_thickness = "thick", bend_type="") - io = open("tikz_graph.tex", "w") - add_edge_txt = """ - \draw[draw = $edge_color, $edge_thickness] ($v) to [$bend_type] ($w) - """ - write(node_init, close) - close(io) -end - - -function render_tikz(g::SimpleGraph, locs::AbstractVector, grid_graph=false) - N = nv(g) - - # find bounds of locs - min_x = typemax(Float) - min_y = typemax(Float) - max_x = 0 - max_y = 0 - - n = length(locs) - for i=1:n - px, py = locs[i] - - if px > max_x - max_x = px - end - if px < min_x - min_x = px - end - if py > max_y - max_y = py - end - if py < min_y - min_y = py - end - end - - initiate_empty_canvas(xmin=min_x, ymin = min_y, xmax = max_x, ymax = max_y, scale=1) - if grid_graph == true - initiate_dot_grid(xmin =min_x, ymin =min_y, xmax=max_x, ymax=max_y, node_size=2) - end - - initiate_default_node() - - for v in vertices(g) - add_main_node(v, locs[v][1], locs[v][2], "$v", node_color="black", node_text="white") - end - - for e in edges(g) - v1 = src(e) - v2 = dst(e) - add_edge(v1, v2, edge_color = "black", edge_thickness = "thick", bend_type="") - end - - close_canvas() -end