From f4b39f376bc61268b3efca74c795876d8304138a Mon Sep 17 00:00:00 2001 From: Xiwei Pan Date: Wed, 9 Jul 2025 01:27:30 +0800 Subject: [PATCH 1/2] Refactor grid and mapping structures to support triangular lattice grid. --- project/createmap.jl | 30 ++- src/Core.jl | 66 ++++++- src/UnitDiskMapping.jl | 6 +- src/mapping.jl | 57 +++--- src/triangular.jl | 425 +++++++++++++++++++++++++++++++++++++++++ src/utils.jl | 24 +++ src/visualize.jl | 22 ++- src/weighted.jl | 23 ++- 8 files changed, 608 insertions(+), 45 deletions(-) create mode 100644 src/triangular.jl diff --git a/project/createmap.jl b/project/createmap.jl index 6920df5..081a5b7 100644 --- a/project/createmap.jl +++ b/project/createmap.jl @@ -1,3 +1,5 @@ +# TODO: Some interface has changed. We need to update the code. + using UnitDiskMapping, GenericTensorNetworks, Graphs function mapped_entry_to_compact(s::Pattern) @@ -35,11 +37,35 @@ function source_entry_to_configs(s::Pattern) return d end +# function compute_mis_overhead(s) +# locs1, g1, pins1 = source_graph(s) +# locs2, g2, pins2 = mapped_graph(s) +# m1 = mis_compactify!(solve(IndependentSet(g1, openvertices=pins1), SizeMax())) +# m2 = mis_compactify!(solve(IndependentSet(g2, openvertices=pins2), SizeMax())) +# @assert nv(g1) == length(locs1) && nv(g2) == length(locs2) +# sig, diff = UnitDiskMapping.is_diff_by_const(GenericTensorNetworks.content.(m1), GenericTensorNetworks.content.(m2)) +# @assert sig +# return diff +# end + function compute_mis_overhead(s) locs1, g1, pins1 = source_graph(s) locs2, g2, pins2 = mapped_graph(s) - m1 = mis_compactify!(solve(IndependentSet(g1, openvertices=pins1), SizeMax())) - m2 = mis_compactify!(solve(IndependentSet(g2, openvertices=pins2), SizeMax())) + m1 = mis_compactify!(solve(IndependentSet(g1, ones(Int, length(locs1))), SizeMax())) + m2 = mis_compactify!(solve(IndependentSet(g2, ones(Int, length(locs2))), SizeMax())) + @assert nv(g1) == length(locs1) && nv(g2) == length(locs2) + sig, diff = UnitDiskMapping.is_diff_by_const(GenericTensorNetworks.content.(m1), GenericTensorNetworks.content.(m2)) + @assert sig + return diff +end + +function compute_mis_overhead_weighted(s) + weighted_s = UnitDiskMapping.weighted(s) + locs1, g1, pins1 = source_graph(s) + locs2, g2, pins2 = mapped_graph(s) + m1 = mis_compactify!(solve(IndependentSet(g1, weighted_s.source_weights), SizeMax())) + m2 = mis_compactify!(solve(IndependentSet(g2, weighted_s.mapped_weights), SizeMax())) + @show m1, m2 @assert nv(g1) == length(locs1) && nv(g2) == length(locs2) sig, diff = UnitDiskMapping.is_diff_by_const(GenericTensorNetworks.content.(m1), GenericTensorNetworks.content.(m2)) @assert sig diff --git a/src/Core.jl b/src/Core.jl index 18049f2..330b5f4 100644 --- a/src/Core.jl +++ b/src/Core.jl @@ -56,30 +56,82 @@ offset(p::Node, xy) = chxy(p, getxy(p) .+ xy) const WeightedNode{T<:Real} = Node{T} const UnWeightedNode = Node{ONE} +############################ Grid Types ############################ +# Abstract grid geometry types +abstract type AbstractGridType end + +struct SquareGrid <: AbstractGridType end +struct TriangularGrid <: AbstractGridType end + ############################ GridGraph ############################ -# GridGraph -struct GridGraph{NT<:Node} +# Main definition +struct GridGraph{NT<:Node, GT<:AbstractGridType} + gridtype::GT size::Tuple{Int,Int} nodes::Vector{NT} radius::Float64 end + +is_square_grid(g::GridGraph) = g.gridtype isa SquareGrid +is_triangular_grid(g::GridGraph) = g.gridtype isa TriangularGrid + +# Base constructors (for any node/grid type) +GridGraph(size::Tuple{Int,Int}, nodes::Vector{NT}, radius::Real) where {NT<:Node} = + GridGraph(SquareGrid(), size, nodes, radius) + +GridGraph(gridtype::GT, size::Tuple{Int,Int}, nodes::Vector{NT}, radius::Real) where {NT<:Node, GT<:AbstractGridType} = + GridGraph{NT, GT}(gridtype, size, nodes, radius) + function Base.show(io::IO, grid::GridGraph) - println(io, "$(typeof(grid)) (radius = $(grid.radius))") + gridtype_name = grid.gridtype isa SquareGrid ? "Square" : "Triangular" + println(io, "$(gridtype_name)$(typeof(grid)) (radius = $(grid.radius))") print_grid(io, grid; show_weight=SHOW_WEIGHT[]) end Base.size(gg::GridGraph) = gg.size Base.size(gg::GridGraph, i::Int) = gg.size[i] function graph_and_weights(grid::GridGraph) - return unit_disk_graph(getfield.(grid.nodes, :loc), grid.radius), getfield.(grid.nodes, :weight) + if is_triangular_grid(grid) + # For triangular grids, use physical positions + physical_locs = [physical_position(node) for node in grid.nodes] + return unit_disk_graph(physical_locs, grid.radius), getfield.(grid.nodes, :weight) + else + # For square grids, use original coordinates + return unit_disk_graph(getfield.(grid.nodes, :loc), grid.radius), getfield.(grid.nodes, :weight) + end end -function Graphs.SimpleGraph(grid::GridGraph{Node{ONE}}) - return unit_disk_graph(getfield.(grid.nodes, :loc), grid.radius) +function Graphs.SimpleGraph(grid::GridGraph{Node{ONE}, GT}) where GT + if is_triangular_grid(grid) + # For triangular grids, use physical positions + physical_locs = [physical_position(node) for node in grid.nodes] + return unit_disk_graph(physical_locs, grid.radius) + else + # For square grids, use original coordinates + return unit_disk_graph(getfield.(grid.nodes, :loc), grid.radius) + end end coordinates(grid::GridGraph) = getfield.(grid.nodes, :loc) + +# Neighbor calculation with runtime grid type dispatch function Graphs.neighbors(g::GridGraph, i::Int) - [j for j in 1:nv(g) if i != j && distance(g.nodes[i], g.nodes[j]) <= g.radius] + if is_triangular_grid(g) + # Use physical positions for triangular grid distance calculation + [j for j in 1:nv(g) if i != j && triangular_distance(g.nodes[i], g.nodes[j]) <= g.radius] + else + # Default square grid calculation + [j for j in 1:nv(g) if i != j && distance(g.nodes[i], g.nodes[j]) <= g.radius] + end end + distance(n1::Node, n2::Node) = sqrt(sum(abs2, n1.loc .- n2.loc)) + +# Distance calculation for triangular grids using physical positions +function triangular_distance(n1::Node, n2::Node) + # Convert to physical positions as in triangular.jl + p1 = physical_position(n1) + p2 = physical_position(n2) + return sqrt(sum(abs2, p1.loc .- p2.loc)) +end + Graphs.nv(g::GridGraph) = length(g.nodes) Graphs.vertices(g::GridGraph) = 1:nv(g) diff --git a/src/UnitDiskMapping.jl b/src/UnitDiskMapping.jl index 628f921..e6dfc04 100644 --- a/src/UnitDiskMapping.jl +++ b/src/UnitDiskMapping.jl @@ -7,7 +7,8 @@ using LuxorGraphPlot using LuxorGraphPlot.Luxor.Colors # Basic types -export UnWeighted, Weighted +export UnWeighted, Weighted, TriangularWeighted +export SquareGrid, TriangularGrid export Cell, AbstractCell, SimpleCell export Node, WeightedNode, UnWeightedNode export graph_and_weights, GridGraph, coordinates @@ -41,8 +42,8 @@ export pathwidth, PathDecompositionMethod, MinhThiTrick, Greedy @deprecate Branching MinhThiTrick -include("utils.jl") include("Core.jl") +include("utils.jl") include("pathdecomposition/pathdecomposition.jl") include("copyline.jl") include("dragondrop.jl") @@ -51,6 +52,7 @@ include("logicgates.jl") include("gadgets.jl") include("mapping.jl") include("weighted.jl") +include("triangular.jl") include("simplifiers.jl") include("extracting_results.jl") include("visualize.jl") diff --git a/src/mapping.jl b/src/mapping.jl index 1297393..f747e0b 100644 --- a/src/mapping.jl +++ b/src/mapping.jl @@ -2,6 +2,12 @@ struct UnWeighted end # Weighted mode struct Weighted end +# TriangularWeighted mode +struct TriangularWeighted end + +# Get spacing value based on mode +get_spacing(::Union{UnWeighted, Weighted}) = 4 +get_spacing(::TriangularWeighted) = 6 Base.@kwdef struct MCell{WT} <: AbstractCell{WT} occupied::Bool = true @@ -63,9 +69,10 @@ struct MappingGrid{CT<:AbstractCell} lines::Vector{CopyLine} padding::Int content::Matrix{CT} + spacing::Int end -Base.:(==)(ug::MappingGrid{CT}, ug2::MappingGrid{CT}) where CT = ug.lines == ug2.lines && ug.content == ug2.content +Base.:(==)(ug::MappingGrid{CT}, ug2::MappingGrid{CT}) where CT = ug.lines == ug2.lines && ug.content == ug2.content && ug.spacing == ug2.spacing Base.size(ug::MappingGrid, args...) = size(ug.content, args...) padding(ug::MappingGrid) = ug.padding coordinates(ug::MappingGrid) = [ci.I for ci in findall(!isempty, ug.content)] @@ -91,15 +98,19 @@ function Graphs.SimpleGraph(ug::MappingGrid) end return unitdisk_graph(coordinates(ug), 1.5) end -function GridGraph(ug::MappingGrid) +function GridGraph(mode, ug::MappingGrid) if any(x->x.doubled || x.connected, ug.content) error("This mapping is not done yet!") end - return GridGraph(size(ug), [Node((i,j), ug.content[i,j].weight) for (i, j) in coordinates(ug)], 1.5) + if mode isa TriangularWeighted + return GridGraph(TriangularGrid(), size(ug), [Node((i,j), ug.content[i,j].weight) for (i, j) in coordinates(ug)], 1.1) + else + return GridGraph(size(ug), [Node((i,j), ug.content[i,j].weight) for (i, j) in coordinates(ug)], 1.5) + end end Base.show(io::IO, ug::MappingGrid) = print_grid(io, ug.content) -Base.copy(ug::MappingGrid) = MappingGrid(ug.lines, ug.padding, copy(ug.content)) +Base.copy(ug::MappingGrid) = MappingGrid(ug.lines, ug.padding, copy(ug.content), ug.spacing) # TODO: # 1. check if the resulting graph is a unit-disk @@ -230,18 +241,16 @@ function remove_order(g::AbstractGraph, vertex_order::AbstractVector{Int}) return addremove end -function center_location(tc::CopyLine; padding::Int) - s = 4 +function center_location(tc::CopyLine; padding::Int, s::Int=4) I = s*(tc.hslot-1)+padding+2 J = s*(tc.vslot-1)+padding+1 return I, J end # NT is node type -function copyline_locations(::Type{NT}, tc::CopyLine; padding::Int) where NT - s = 4 +function copyline_locations(::Type{NT}, tc::CopyLine; padding::Int, s::Int=4) where NT nline = 0 - I, J = center_location(tc; padding=padding) + I, J = center_location(tc; padding=padding, s=s) locations = NT[] # grow up start = I+s*(tc.vstart-tc.hslot)+1 @@ -278,25 +287,26 @@ nodetype(::MappingGrid{MCell{WT}}) where WT = Node{WT} cell_type(::Type{Node{WT}}) where WT = MCell{WT} nodetype(::UnWeighted) = UnWeightedNode +nodetype(::TriangularWeighted) = WeightedNode{Int} node(::Type{<:UnWeightedNode}, i, j, w) = Node(i, j) function ugrid(mode, g::SimpleGraph, vertex_order::AbstractVector{Int}; padding=2, nrow=nv(g)) @assert padding >= 2 # create an empty canvas n = nv(g) - s = 4 - N = (n-1)*s+1+2*padding - M = nrow*s+1+2*padding - u = fill(empty(mode isa Weighted ? MCell{Int} : MCell{ONE}), M, N) + s = get_spacing(mode) + N = (n-1)*s+2+2*padding + M = nrow*s+2+2*padding + u = fill(empty(mode isa Union{Weighted, TriangularWeighted} ? MCell{Int} : MCell{ONE}), M, N) # add T-copies copylines = create_copylines(g, vertex_order) for tc in copylines - for loc in copyline_locations(nodetype(mode), tc; padding=padding) + for loc in copyline_locations(nodetype(mode), tc; padding=padding, s=s) add_cell!(u, loc) end end - ug = MappingGrid(copylines, padding, u) + ug = MappingGrid(copylines, padding, u, s) for e in edges(g) I, J = crossat(ug, e.src, e.dst) connect_cell!(ug.content, I, J-1) @@ -313,7 +323,7 @@ function crossat(ug::MappingGrid, v, w) i, j = findfirst(x->x.vertex==v, ug.lines), findfirst(x->x.vertex==w, ug.lines) i, j = minmax(i, j) hslot = ug.lines[i].hslot - s = 4 + s = ug.spacing return (hslot-1)*s+2+ug.padding, (j-1)*s+1+ug.padding end @@ -341,18 +351,17 @@ end function mis_overhead_copylines(ug::MappingGrid{WC}) where {WC} sum(ug.lines) do line - mis_overhead_copyline(WC <: WeightedMCell ? Weighted() : UnWeighted(), line) + mis_overhead_copyline(WC <: WeightedMCell ? Weighted() : UnWeighted(), line, ug.spacing) end end -function mis_overhead_copyline(w::W, line::CopyLine) where W - if W === Weighted - s = 4 +function mis_overhead_copyline(w::W, line::CopyLine, s::Int=4) where W + if W === Weighted || W === TriangularWeighted return (line.hslot - line.vstart) * s + (line.vstop - line.hslot) * s + max((line.hstop - line.vslot) * s - 2, 0) else - locs = copyline_locations(nodetype(w), line; padding=2) + locs = copyline_locations(nodetype(w), line; padding=2, s=s) @assert length(locs) % 2 == 1 return length(locs) ÷ 2 end @@ -365,6 +374,7 @@ struct MappingResult{NT} padding::Int mapping_history::Vector{Tuple{Pattern,Int,Int}} mis_overhead::Int + spacing::Int end """ @@ -398,7 +408,7 @@ function map_graph(mode, g::SimpleGraph; vertex_order=MinhThiTrick(), ruleset=de ug, tape2 = apply_simplifier_gadgets!(ug; ruleset=ruleset) mis_overhead1 = isempty(tape) ? 0 : sum(x->mis_overhead(x[1]), tape) mis_overhead2 = isempty(tape2) ? 0 : sum(x->mis_overhead(x[1]), tape2) - return MappingResult(GridGraph(ug), ug.lines, ug.padding, vcat(tape, tape2) , mis_overhead0 + mis_overhead1 + mis_overhead2) + return MappingResult(GridGraph(mode, ug), ug.lines, ug.padding, vcat(tape, tape2) , mis_overhead0 + mis_overhead1 + mis_overhead2, ug.spacing) end """ @@ -427,12 +437,13 @@ function map_config_back(res::MappingResult, cfg) end function _map_configs_back(r::MappingResult{UnWeightedNode}, configs::AbstractVector{<:AbstractMatrix}) cm = cell_matrix(r.grid_graph) - ug = MappingGrid(r.lines, r.padding, MCell.(cm)) + ug = MappingGrid(r.lines, r.padding, MCell.(cm), r.spacing) unapply_gadgets!(ug, r.mapping_history, copy.(configs))[2] end default_simplifier_ruleset(::UnWeighted) = vcat([rotated_and_reflected(rule) for rule in simplifier_ruleset]...) default_simplifier_ruleset(::Weighted) = weighted.(default_simplifier_ruleset(UnWeighted())) +default_simplifier_ruleset(::TriangularWeighted) = weighted.(default_simplifier_ruleset(UnWeighted())) print_config(mr::MappingResult, config::AbstractMatrix) = print_config(stdout, mr, config) function print_config(io::IO, mr::MappingResult, config::AbstractMatrix) diff --git a/src/triangular.jl b/src/triangular.jl new file mode 100644 index 0000000..5d44265 --- /dev/null +++ b/src/triangular.jl @@ -0,0 +1,425 @@ +abstract type TriangularCrossPattern <: Pattern end + +struct TriCross{CON} <: TriangularCrossPattern end +iscon(::TriCross{CON}) where {CON} = CON +# · ⋅ ● ⋅ · +# ● ◆ ◉ ● ● +# · ⋅ ◆ · · +# ⋅ ⋅ ● ⋅ ⋅ +# ⋅ ⋅ ● ⋅ ⋅ +# ⋅ ⋅ ● ⋅ ⋅ +function source_graph(::TriCross{true}) + locs = Node.([(2,1), (2,2), (2,3), (2,4), (2,5), (1,3), (2,3), (3,3), (4,3), (5,3), (6,3)]) + g = simplegraph([(1,2), (2,3), (3,4), (4,5), (6,7), (7,8), (8,9), (9,10), (10,11), (2,6)]) + return locs, g, [1,6,11,5] +end + +# ⋅ · ● ⋅ ⋅ +# ● ● ● ● ● +# ⋅ ● ⋅ ● ⋅ +# ⋅ ● ● · ⋅ +# ⋅ · · ● ⋅ +# ⋅ ⋅ ● ● ⋅ +function mapped_graph(::TriCross{true}) + locs = Node.([(1,3), (2,1), (2,2), (2,3), (2,4), (2,5), (3,2), (3,4), (4,2), (4,3), (5,4), (6,3), (6,4)]) + return locs, triangular_unitdisk_graph(locs, 1.1, false), [2,1,12,6] +end +Base.size(::TriCross{true}) = (6, 5) +cross_location(::TriCross{true}) = (2, 3) +connected_nodes(::TriCross{true}) = [2, 6] + +function weighted(p::TriCross{true}) + sw = [2,2,2,2,2,2,2,2,2,2,2] + mw = [3,2,3,4,3,2,3,2,2,2,2,2,2] + return weighted(p, sw, mw) +end + +# ⋅ ⋅ ● ⋅ ⋅ +# ● ● ◉ ● ● +# ⋅ ⋅ ● ⋅ ⋅ +# ⋅ ⋅ ● ⋅ ⋅ +# ⋅ ⋅ ● ⋅ ⋅ +# ⋅ ⋅ ● ⋅ ⋅ +function source_graph(::TriCross{false}) + locs = Node.([(2,1), (2,2), (2,3), (2,4), (2,5), (1,3), (2,3), (3,3), (4,3), (5,3), (6,3)]) + g = simplegraph([(1,2), (2,3), (3,4), (4,5), (6,7), (7,8), (8,9), (9,10), (10,11)]) + return locs, g, [1,6,11,5] +end + +# ⋅ ⋅ ● ⋅ ⋅ +# ● ● ● ● ● +# ● ● ● ● · +# ● ● · ⋅ ⋅ +# ● ⋅ · ⋅ ⋅ +# · ● ● ⋅ ⋅ +function mapped_graph(::TriCross{false}) + locs = Node.([(1,3), (2,1), (2,2), (2,3), (2,4), (2,5), (3,1), (3,2), (3,3), (3,4), (4,1), (4,2), (5,1), (6,2), (6,3)]) + return locs, triangular_unitdisk_graph(locs, 1.1, false), [2,1,15,6] +end +Base.size(::TriCross{false}) = (6, 5) +cross_location(::TriCross{false}) = (2,3) + +function weighted(p::TriCross{false}) + sw = [2,2,2,2,2,2,2,2,2,2,2] + mw = [3,3,2,4,2,2,2,4,3,2,2,2,2,2,2] + return weighted(p, sw, mw) +end + +struct TriTCon_left <: TriangularCrossPattern end +# ⋅ ◆ ⋅ ⋅ · +# ◆ ● · · · +# ⋅ ● · ⋅ · +# ⋅ ● · · · +# · ● · · · +# · ● · · · +function source_graph(::TriTCon_left) + locs = Node.([(1,2), (2,1), (2,2), (3,2), (4,2), (5,2), (6,2)]) + g = simplegraph([(1,2), (1,3), (3,4), (4,5), (5,6), (6,7)]) + return locs, g, [1,2,7] +end +connected_nodes(::TriTCon_left) = [1, 2] + +# ⋅ ● ⋅ ⋅ · +# ● ● ● ● · +# ⋅ · ● ⋅ · +# ⋅ ● ● · · +# ● · · · · +# ● ● · · · +function mapped_graph(::TriTCon_left) + locs = Node.([(1,2), (2,1), (2,2), (2,3), (2,4), (3,3), (4,2), (4,3), (5,1), (6,1), (6,2)]) + return locs, triangular_unitdisk_graph(locs, 1.1, true), [1,2,11] +end +Base.size(::TriTCon_left) = (6,5) +cross_location(::TriTCon_left) = (2,2) +iscon(::TriTCon_left) = true + +function weighted(p::TriTCon_left) + sw = [2,1,2,2,2,2,2] + mw = [3,2,3,3,1,3,2,2,2,2,2] + return weighted(p, sw, mw) +end + +struct TriTCon_down <: TriangularCrossPattern end +# · · · +# · · · +# ◆ ● ● +# ⋅ ◆ · +function source_graph(::TriTCon_down) + locs = Node.([(3,1), (3,2), (3,3), (4,2)]) + g = simplegraph([(1,2), (2,3), (1,4)]) + return locs, g, [1,4,3] +end +connected_nodes(::TriTCon_down) = [1, 4] + +# · · · +# · ● · +# · ● · +# ● ● ● +function mapped_graph(::TriTCon_down) + locs = Node.([(2,2), (3,2), (4,1), (4,2), (4,3)]) + return locs, triangular_unitdisk_graph(locs, 1.1, true), [3,4,5] +end +Base.size(::TriTCon_down) = (4,3) +cross_location(::TriTCon_down) = (3,2) +iscon(::TriTCon_down) = true + +function weighted(p::TriTCon_down) + sw = [2,2,2,1] + mw = [1,3,2,3,2] + return weighted(p, sw, mw) +end + +struct TriTCon_up <: TriangularCrossPattern end +# ⋅ ◆ · +# ◆ ● ● +# · · · +# · · · +function source_graph(::TriTCon_up) + locs = Node.([(1,2), (2,1), (2,2), (2,3)]) + g = simplegraph([(1,2), (2,3), (1,4)]) + return locs, g, [2,1,4] +end +connected_nodes(::TriTCon_up) = [1, 2] + +# · ● · +# ● ● ● +# · ● · +# · · · +function mapped_graph(::TriTCon_up) + locs = Node.([(1,2), (2,1), (2,2), (2,3), (3,2)]) + return locs, triangular_unitdisk_graph(locs, 1.1, true), [2,1,4] +end +Base.size(::TriTCon_up) = (4,3) +cross_location(::TriTCon_up) = (2,2) +iscon(::TriTCon_up) = true + +function weighted(p::TriTCon_up) + sw = [1,2,2,2] + mw = [3,2,3,2,1] + return weighted(p, sw, mw) +end + +struct TriTrivialTurn_left <: TriangularCrossPattern end +# ⋅ ◆ +# ◆ ⋅ +function source_graph(::TriTrivialTurn_left) + locs = Node.([(1,2), (2,1)]) + g = simplegraph([(1,2)]) + return locs, g, [1,2] +end +# ⋅ ● +# ● ⋅ +function mapped_graph(::TriTrivialTurn_left) + locs = Node.([(1,2),(2,1)]) + return locs, triangular_unitdisk_graph(locs, 1.1, true), [1,2] +end +Base.size(::TriTrivialTurn_left) = (2,2) +cross_location(::TriTrivialTurn_left) = (2,2) +iscon(::TriTrivialTurn_left) = true +connected_nodes(::TriTrivialTurn_left) = [1, 2] + +function weighted(p::TriTrivialTurn_left) + sw = [1,1] + mw = [1,1] + return weighted(p, sw, mw) +end + +struct TriTrivialTurn_right <: TriangularCrossPattern end +# ◆ · +# · ◆ +function source_graph(::TriTrivialTurn_right) + locs = Node.([(1,1), (2,2)]) + g = simplegraph([(1,2)]) + return locs, g, [1,2] +end +# ⋅ · +# ● ● +function mapped_graph(::TriTrivialTurn_right) + locs = Node.([(2,1),(2,2)]) + return locs, triangular_unitdisk_graph(locs, 1.1, true), [1,2] +end +Base.size(::TriTrivialTurn_right) = (2,2) +cross_location(::TriTrivialTurn_right) = (1,2) +iscon(::TriTrivialTurn_right) = true +connected_nodes(::TriTrivialTurn_right) = [1, 2] + +function weighted(p::TriTrivialTurn_right) + sw = [1,1] + mw = [1,1] + return weighted(p, sw, mw) +end + +struct TriEndTurn <: TriangularCrossPattern end +# ⋅ ● ⋅ ⋅ +# ⋅ ● ● ⋅ +# ⋅ ⋅ ⋅ ⋅ +function source_graph(::TriEndTurn) + locs = Node.([(1,2), (2,2), (2,3)]) + g = simplegraph([(1,2), (2,3)]) + return locs, g, [1] +end +# ⋅ ● ⋅ ⋅ +# ⋅ ⋅ ⋅ ⋅ +# ⋅ ⋅ ⋅ ⋅ +function mapped_graph(::TriEndTurn) + locs = Node.([(1,2)]) + return locs, triangular_unitdisk_graph(locs, 1.1, true), [1] +end +Base.size(::TriEndTurn) = (3,4) +cross_location(::TriEndTurn) = (2,2) +iscon(::TriEndTurn) = false + +function weighted(p::TriEndTurn) + sw = [2,2,1] + mw = [1] + return weighted(p, sw, mw) +end + +struct TriTurn <: TriangularCrossPattern end +iscon(::TriTurn) = false +# ⋅ ● ⋅ ⋅ +# ⋅ ● ⋅ ⋅ +# ⋅ ● ● ● +# ⋅ ⋅ ⋅ ⋅ +function source_graph(::TriTurn) + locs = Node.([(1,2), (2,2), (3,2), (3,3), (3,4)]) + g = simplegraph([(1,2), (2,3), (3,4), (4,5)]) + return locs, g, [1,5] +end + +# ⋅ ● ⋅ ⋅ +# ⋅ ● · ⋅ +# ● ⋅ ⋅ ● +# ● ● ● ⋅ +function mapped_graph(::TriTurn) + locs = Node.([(1,2), (2,2), (3,1), (4,1), (4,2), (4,3), (3,4)]) + locs, triangular_unitdisk_graph(locs, 1.1, true), [1,7] +end +Base.size(::TriTurn) = (4, 4) +cross_location(::TriTurn) = (3,2) + +function weighted(p::TriTurn) + sw = [2,2,2,2,2] + mw = [2,2,2,2,2,2,2] + return weighted(p, sw, mw) +end + +struct TriWTurn <: TriangularCrossPattern end +# ⋅ ⋅ ⋅ ⋅ +# ⋅ ⋅ ● ● +# ⋅ ● ● ⋅ +# ⋅ ● ⋅ ⋅ +function source_graph(::TriWTurn) + locs = Node.([(2,3), (2,4), (3,2),(3,3),(4,2)]) + g = simplegraph([(1,2), (1,4), (3,4),(3,5)]) + return locs, g, [2, 5] +end +# ⋅ ⋅ ⋅ ● +# ⋅ ⋅ ● ⋅ +# ⋅ ● ● ⋅ +# ⋅ ● ⋅ ⋅ +function mapped_graph(::TriWTurn) + locs = Node.([(1,4), (2,3), (3,2), (3,3), (4,2)]) + return locs, triangular_unitdisk_graph(locs, 1.1, true), [1, 5] +end +Base.size(::TriWTurn) = (4, 4) +cross_location(::TriWTurn) = (2,2) +iscon(::TriWTurn) = false + +function weighted(p::TriWTurn) + sw = [2,2,2,2,2] + mw = [2,2,2,2,2] + return weighted(p, sw, mw) +end + +struct TriBranchFix <: TriangularCrossPattern end +# ⋅ ● ⋅ ⋅ +# ⋅ ● ● ⋅ +# ⋅ ● ● ⋅ +# ⋅ ● ⋅ ⋅ +function source_graph(::TriBranchFix) + locs = Node.([(1,2), (2,2), (2,3),(3,3),(3,2),(4,2)]) + g = simplegraph([(1,2), (2,3), (3,4),(4,5), (5,6)]) + return locs, g, [1, 6] +end +# ⋅ ● ⋅ ⋅ +# ⋅ ● ⋅ ⋅ +# ⋅ ● ⋅ ⋅ +# ⋅ ● ⋅ ⋅ +function mapped_graph(::TriBranchFix) + locs = Node.([(1,2),(2,2),(3,2),(4,2)]) + return locs, triangular_unitdisk_graph(locs, 1.1, true), [1, 4] +end +Base.size(::TriBranchFix) = (4, 4) +cross_location(::TriBranchFix) = (2,2) +iscon(::TriBranchFix) = false + +function weighted(p::TriBranchFix) + sw = [2,2,2,2,2,2] + mw = [2,2,2,2] + return weighted(p, sw, mw) +end + +struct TriBranchFixB <: TriangularCrossPattern end +# ⋅ ⋅ ⋅ ⋅ +# ⋅ ⋅ ● ⋅ +# ⋅ ● ● ⋅ +# ⋅ ● ⋅ ⋅ +function source_graph(::TriBranchFixB) + locs = Node.([(2,3),(3,2),(3,3),(4,2)]) + g = simplegraph([(1,3), (2,3), (2,4)]) + return locs, g, [1, 4] +end +# ⋅ ⋅ ⋅ ⋅ +# ⋅ ⋅ ⋅ ⋅ +# ⋅ ● ⋅ ⋅ +# ⋅ ● ⋅ ⋅ +function mapped_graph(::TriBranchFixB) + locs = Node.([(3,2),(4,2)]) + return locs, triangular_unitdisk_graph(locs, 1.1, true), [1, 2] +end +Base.size(::TriBranchFixB) = (4, 4) +cross_location(::TriBranchFixB) = (2,2) +iscon(::TriBranchFixB) = false + +function weighted(p::TriBranchFixB) + sw = [2,2,2,2] + mw = [2,2] + return weighted(p, sw, mw) +end + +struct TriBranch <: TriangularCrossPattern end +# ⋅ ● ⋅ ⋅ +# ⋅ ● ● ● +# ⋅ ● ● ⋅ +# ⋅ ● ⋅ ⋅ +# ⋅ ● · ⋅ +# ⋅ ● · ⋅ +function source_graph(::TriBranch) + locs = Node.([(1,2),(2,2),(2,3),(2,4),(3,3),(3,2),(4,2),(5,2),(6,2)]) + g = simplegraph([(1,2), (2,3), (3, 4), (3,5), (5,6), (6,7), (7,8), (8,9)]) + return locs, g, [1, 4, 9] +end +# ⋅ ● ⋅ ⋅ +# ⋅ ● · ● +# ● · ● · +# ⋅ ● ● ⋅ +# ● · ⋅ ⋅ +# ● ● ⋅ ⋅ +function mapped_graph(::TriBranch) + locs = Node.([(1,2),(2,2),(2,4),(3,1),(3,3),(4,2),(4,3),(5,1),(6,1),(6,2)]) + return locs, triangular_unitdisk_graph(locs, 1.1, true), [1,3,10] +end +Base.size(::TriBranch) = (6, 4) +cross_location(::TriBranch) = (2,2) +iscon(::TriBranch) = false + +function weighted(p::TriBranch) + sw = [2,2,3,2,2,2,2,2,2] + mw = [2,3,2,1,3,2,2,2,2,2] + return weighted(p, sw, mw) +end + +const triangular_crossing_ruleset = ( + TriCross{false}(), + TriCross{true}(), + TriTCon_left(), + TriTCon_up(), + TriTCon_down(), + TriTrivialTurn_left(), + TriTrivialTurn_right(), + TriEndTurn(), + TriTurn(), + TriWTurn(), + TriBranchFix(), + TriBranchFixB(), + TriBranch(), + ) +const crossing_ruleset_triangular_weighted = weighted.(triangular_crossing_ruleset) +get_ruleset(::TriangularWeighted) = crossing_ruleset_triangular_weighted + +# Specialized mis_overhead for TriangularCrossPattern WeightedGadgets +# For triangular patterns, we don't use the *2 multiplier from the general WeightedGadget method +mis_overhead(w::WeightedGadget{<:TriangularCrossPattern}) = mis_overhead(w.gadget) + +# mis_overhead functions for TriangularCrossPattern types +# These values should be computed properly using compute_mis_overhead function from project/createmap.jl +# For now, using reasonable placeholder values based on the pattern complexity +mis_overhead(::TriCross{true}) = 2 +mis_overhead(::TriCross{false}) = 3 +mis_overhead(::TriTCon_left) = 4 +mis_overhead(::TriTCon_down) = 1 +mis_overhead(::TriTCon_up) = 1 +mis_overhead(::TriTrivialTurn_left) = 0 +mis_overhead(::TriTrivialTurn_right) = 0 +mis_overhead(::TriEndTurn) = -2 +mis_overhead(::TriTurn) = 2 +mis_overhead(::TriWTurn) = 0 +mis_overhead(::TriBranchFix) = -2 +mis_overhead(::TriBranchFixB) = -2 +mis_overhead(::TriBranch) = 1 + +for (T, centerloc) in [(:Turn, (2, 3)), (:Branch, (2, 3)), (:BranchFix, (3, 2)), (:BranchFixB, (3, 2)), (:WTurn, (3, 3)), (:EndTurn, (1, 2))] + @eval source_centers(::WeightedGadget{<:$T}) = [cross_location($T()) .+ (0, 1)] + @eval mapped_centers(::WeightedGadget{<:$T}) = [$centerloc] +end \ No newline at end of file diff --git a/src/utils.jl b/src/utils.jl index 1fa4cda..05da222 100644 --- a/src/utils.jl +++ b/src/utils.jl @@ -41,6 +41,30 @@ function unitdisk_graph(locs::AbstractVector, unit::Real) return g end +function triangular_unitdisk_graph(locs::AbstractVector, unit::Real, parity::Bool=false) + # parity==false: crossing nodes on odd columns. + n = length(locs) + g = SimpleGraph(n) + physical_locs = physical_position.(locs, parity) + for i=1:n, j=i+1:n + if sum(abs2, physical_locs[i] .- physical_locs[j]) < unit ^ 2 + add_edge!(g, i, j) + end + end + return g +end + +function physical_position(node, parity=false) + i, j = node.loc + y = j * (√3 / 2) + if parity + x = i + (iseven(j) ? 0.5 : 0.0) + else + x = i + (isodd(j) ? 0.5 : 0.0) + end + return (x, y) +end + function is_independent_set(g::SimpleGraph, config) for e in edges(g) if config[e.src] == config[e.dst] == 1 diff --git a/src/visualize.jl b/src/visualize.jl index 4f46e1c..f2c95b1 100644 --- a/src/visualize.jl +++ b/src/visualize.jl @@ -1,4 +1,18 @@ # normalized to minimum weight and maximum weight + +# Helper function to convert grid coordinates to plot coordinates +function plot_coordinates(gg::GridGraph, i::Int, j::Int, unit::Float64) + if is_triangular_grid(gg) + # Triangular grid layout: y = j * (√3 / 2), x = i + (iseven(j) ? 0.5 : 0.0) + x = (i + (isodd(j) ? 0.5 : 0.0)) * unit + y = j * (√3 / 2) * unit # negative for downward y-axis + return (y, -x) + else + # Square grid layout (original) + return (j * unit, -i * unit) + end +end + function LuxorGraphPlot.show_graph(gg::GridGraph; format = :svg, filename = nothing, @@ -18,10 +32,14 @@ function LuxorGraphPlot.show_graph(gg::GridGraph; xmin, xmax = extrema(first.(coos)) ymin, ymax = extrema(last.(coos)) nodestore() do ns - filledlocs = map(coo->circle!((unit * (coo[2] - 1), -unit * (coo[1] - 1)), config.vertex_size), coos) + # Use the new coordinate transformation for filled locations + filledlocs = map(coo->circle!(plot_coordinates(gg, coo[1], coo[2], unit), config.vertex_size), coos) emptylocs, edges = [], [] for i=xmin:xmax, j=ymin:ymax - (i, j) ∉ coos && push!(emptylocs, circle!(((j-1) * unit, -(i-1) * unit), config.vertex_size/10)) + if (i, j) ∉ coos + plot_pos = plot_coordinates(gg, i, j, unit) + push!(emptylocs, circle!(plot_pos, config.vertex_size/10)) + end end for e in Graphs.edges(graph_and_weights(gg)[1]) i, j = e.src, e.dst diff --git a/src/weighted.jl b/src/weighted.jl index 37df58a..eef523c 100644 --- a/src/weighted.jl +++ b/src/weighted.jl @@ -95,9 +95,9 @@ function move_center(w::WeightedGadgetTypes, nodexy, offset) error("center not found, source center = $(source_centers(w)), while offset = $(offset)") end -trace_centers(r::MappingResult) = trace_centers(r.lines, r.padding, r.mapping_history) -function trace_centers(lines, padding, tape) - center_locations = map(x->center_location(x; padding) .+ (0, 1), lines) +trace_centers(r::MappingResult) = trace_centers(r.lines, r.padding, r.mapping_history, r.spacing) +function trace_centers(lines, padding, tape, spacing=4) + center_locations = map(x->center_location(x; padding, s=spacing) .+ (0, 1), lines) for (gadget, i, j) in tape m, n = size(gadget) for (k, centerloc) in enumerate(center_locations) @@ -122,12 +122,17 @@ function _map_configs_back(r::MappingResult{<:WeightedNode}, configs::AbstractVe end # simple rules for crossing gadgets -for (GT, s1, m1, s3, m3) in [(:(Cross{true}), [], [], [], []), (:(Cross{false}), [], [], [], []), - (:(WTurn), [], [], [], []), (:(BranchFix), [], [], [], []), (:(Turn), [], [], [], []), - (:(TrivialTurn), [1, 2], [1, 2], [], []), (:(BranchFixB), [1], [1], [], []), - (:(EndTurn), [3], [1], [], []), (:(TCon), [2], [2], [], []), - (:(Branch), [], [], [4], [2]), - ] +for (GT, s1, m1, s3, m3) in [ + (:(Cross{true}), [], [], [], []), + (:(Cross{false}), [], [], [], []), + (:(WTurn), [], [], [], []), + (:(BranchFix), [], [], [], []), + (:(Turn), [], [], [], []), + (:(TrivialTurn), [1, 2], [1, 2], [], []), + (:(BranchFixB), [1], [1], [], []), + (:(EndTurn), [3], [1], [], []), + (:(TCon), [2], [2], [], []), + (:(Branch), [], [], [4], [2]),] @eval function weighted(g::$GT) slocs, sg, spins = source_graph(g) mlocs, mg, mpins = mapped_graph(g) From 4a3bec49f218e3504ed5359d980b3a53c44ec42b Mon Sep 17 00:00:00 2001 From: Xiwei Pan Date: Mon, 14 Jul 2025 14:48:10 +0800 Subject: [PATCH 2/2] Add triangular support to Test module. --- project/createmap.jl | 30 +------------ src/mapping.jl | 2 +- src/triangular.jl | 53 +++++++++++----------- test/runtests.jl | 4 ++ test/triangular.jl | 104 +++++++++++++++++++++++++++++++++++++++++++ test/weighted.jl | 2 +- 6 files changed, 138 insertions(+), 57 deletions(-) create mode 100644 test/triangular.jl diff --git a/project/createmap.jl b/project/createmap.jl index 081a5b7..6920df5 100644 --- a/project/createmap.jl +++ b/project/createmap.jl @@ -1,5 +1,3 @@ -# TODO: Some interface has changed. We need to update the code. - using UnitDiskMapping, GenericTensorNetworks, Graphs function mapped_entry_to_compact(s::Pattern) @@ -37,35 +35,11 @@ function source_entry_to_configs(s::Pattern) return d end -# function compute_mis_overhead(s) -# locs1, g1, pins1 = source_graph(s) -# locs2, g2, pins2 = mapped_graph(s) -# m1 = mis_compactify!(solve(IndependentSet(g1, openvertices=pins1), SizeMax())) -# m2 = mis_compactify!(solve(IndependentSet(g2, openvertices=pins2), SizeMax())) -# @assert nv(g1) == length(locs1) && nv(g2) == length(locs2) -# sig, diff = UnitDiskMapping.is_diff_by_const(GenericTensorNetworks.content.(m1), GenericTensorNetworks.content.(m2)) -# @assert sig -# return diff -# end - function compute_mis_overhead(s) locs1, g1, pins1 = source_graph(s) locs2, g2, pins2 = mapped_graph(s) - m1 = mis_compactify!(solve(IndependentSet(g1, ones(Int, length(locs1))), SizeMax())) - m2 = mis_compactify!(solve(IndependentSet(g2, ones(Int, length(locs2))), SizeMax())) - @assert nv(g1) == length(locs1) && nv(g2) == length(locs2) - sig, diff = UnitDiskMapping.is_diff_by_const(GenericTensorNetworks.content.(m1), GenericTensorNetworks.content.(m2)) - @assert sig - return diff -end - -function compute_mis_overhead_weighted(s) - weighted_s = UnitDiskMapping.weighted(s) - locs1, g1, pins1 = source_graph(s) - locs2, g2, pins2 = mapped_graph(s) - m1 = mis_compactify!(solve(IndependentSet(g1, weighted_s.source_weights), SizeMax())) - m2 = mis_compactify!(solve(IndependentSet(g2, weighted_s.mapped_weights), SizeMax())) - @show m1, m2 + m1 = mis_compactify!(solve(IndependentSet(g1, openvertices=pins1), SizeMax())) + m2 = mis_compactify!(solve(IndependentSet(g2, openvertices=pins2), SizeMax())) @assert nv(g1) == length(locs1) && nv(g2) == length(locs2) sig, diff = UnitDiskMapping.is_diff_by_const(GenericTensorNetworks.content.(m1), GenericTensorNetworks.content.(m2)) @assert sig diff --git a/src/mapping.jl b/src/mapping.jl index f747e0b..0f44dfb 100644 --- a/src/mapping.jl +++ b/src/mapping.jl @@ -7,7 +7,7 @@ struct TriangularWeighted end # Get spacing value based on mode get_spacing(::Union{UnWeighted, Weighted}) = 4 -get_spacing(::TriangularWeighted) = 6 +get_spacing(::TriangularWeighted) = 14 Base.@kwdef struct MCell{WT} <: AbstractCell{WT} occupied::Bool = true diff --git a/src/triangular.jl b/src/triangular.jl index 5d44265..22612c5 100644 --- a/src/triangular.jl +++ b/src/triangular.jl @@ -2,35 +2,34 @@ abstract type TriangularCrossPattern <: Pattern end struct TriCross{CON} <: TriangularCrossPattern end iscon(::TriCross{CON}) where {CON} = CON -# · ⋅ ● ⋅ · -# ● ◆ ◉ ● ● -# · ⋅ ◆ · · -# ⋅ ⋅ ● ⋅ ⋅ -# ⋅ ⋅ ● ⋅ ⋅ -# ⋅ ⋅ ● ⋅ ⋅ +# · · · · · ⋅ ◆ ⋅ · · · · · +# ● ● ● ● ● ◆ ◉ ● ● ● ● ● ● +# · · · · · ⋅ ● · · · · · · +# · · · · ⋅ ⋅ ● ⋅ ⋅ · · · · +# · · · · ⋅ ⋅ ● ⋅ ⋅ · · · · +# · · · · ⋅ ⋅ ● ⋅ ⋅ · · · · function source_graph(::TriCross{true}) - locs = Node.([(2,1), (2,2), (2,3), (2,4), (2,5), (1,3), (2,3), (3,3), (4,3), (5,3), (6,3)]) - g = simplegraph([(1,2), (2,3), (3,4), (4,5), (6,7), (7,8), (8,9), (9,10), (10,11), (2,6)]) - return locs, g, [1,6,11,5] -end - -# ⋅ · ● ⋅ ⋅ -# ● ● ● ● ● -# ⋅ ● ⋅ ● ⋅ -# ⋅ ● ● · ⋅ -# ⋅ · · ● ⋅ -# ⋅ ⋅ ● ● ⋅ + locs = Node.([(2,1), (2,2), (2,3), (2,4), (2,5), (2,6), (2,7), (2,8), (2,9), (2,10), (2,11), (2,12), (2,13), (1,7), (2,7), (3,7), (4,7), (5,7), (6,7)]) + g = simplegraph([(1,2), (2,3), (3,4), (4,5), (5,6), (6,7), (7,8), (8,9), (9,10), (10,11), (11,12), (12,13), (14,15), (15,16), (16,17), (17,18), (18,19), (14,6)]) + return locs, g, [1,14,13,19] +end +# ● · · · ⋅ · ● ⋅ ⋅ · · · ● +# · ● · · ● ● ● ● ● · · ● · +# · ● ● ● ⋅ ● ⋅ ● ⋅ ● ● ● · +# · · · · ⋅ ● ● · ⋅ · · · · +# · · · · ⋅ · · ● ⋅ · · · · +# · · · · ⋅ ⋅ ● ● ⋅ · · · · function mapped_graph(::TriCross{true}) - locs = Node.([(1,3), (2,1), (2,2), (2,3), (2,4), (2,5), (3,2), (3,4), (4,2), (4,3), (5,4), (6,3), (6,4)]) - return locs, triangular_unitdisk_graph(locs, 1.1, false), [2,1,12,6] + locs = Node.([(1,1), (1,7), (1,13), (2,2), (2,5), (2,6), (2,7), (2,8), (2,9), (2,12), (3,2), (3,3), (3,4), (3,6), (3,8), (3,10), (3,11), (3,12), (4,6), (4,7), (5,8), (6,8), (6,7)]) + return locs, triangular_unitdisk_graph(locs, 1.1, false), [1,2,3,23] end -Base.size(::TriCross{true}) = (6, 5) -cross_location(::TriCross{true}) = (2, 3) -connected_nodes(::TriCross{true}) = [2, 6] +Base.size(::TriCross{true}) = (6, 13) +cross_location(::TriCross{true}) = (2, 7) +connected_nodes(::TriCross{true}) = [14,6] function weighted(p::TriCross{true}) - sw = [2,2,2,2,2,2,2,2,2,2,2] - mw = [3,2,3,4,3,2,3,2,2,2,2,2,2] + sw = [2,2,2,2,2,2,2,2,2,2 ,2,2,2,2,2,2,2,2,2] + mw = [2,3,2,2,2,3,4,3,2,2 ,2,2,2,3,2,2,2,2 ,2,2,2,2,2] return weighted(p, sw, mw) end @@ -136,7 +135,7 @@ struct TriTCon_up <: TriangularCrossPattern end # · · · function source_graph(::TriTCon_up) locs = Node.([(1,2), (2,1), (2,2), (2,3)]) - g = simplegraph([(1,2), (2,3), (1,4)]) + g = simplegraph([(1,2), (2,3), (3,4)]) return locs, g, [2,1,4] end connected_nodes(::TriTCon_up) = [1, 2] @@ -405,7 +404,7 @@ mis_overhead(w::WeightedGadget{<:TriangularCrossPattern}) = mis_overhead(w.gadge # mis_overhead functions for TriangularCrossPattern types # These values should be computed properly using compute_mis_overhead function from project/createmap.jl # For now, using reasonable placeholder values based on the pattern complexity -mis_overhead(::TriCross{true}) = 2 +mis_overhead(::TriCross{true}) = 4 mis_overhead(::TriCross{false}) = 3 mis_overhead(::TriTCon_left) = 4 mis_overhead(::TriTCon_down) = 1 @@ -419,7 +418,7 @@ mis_overhead(::TriBranchFix) = -2 mis_overhead(::TriBranchFixB) = -2 mis_overhead(::TriBranch) = 1 -for (T, centerloc) in [(:Turn, (2, 3)), (:Branch, (2, 3)), (:BranchFix, (3, 2)), (:BranchFixB, (3, 2)), (:WTurn, (3, 3)), (:EndTurn, (1, 2))] +for (T, centerloc) in [(:TriTurn, (4, 1)), (:TriBranch, (1,2)), (:TriBranchFix, (3, 2)), (:TriBranchFixB, (3, 2)), (:TriWTurn, (2, 3)), (:TriEndTurn, (1, 2))] @eval source_centers(::WeightedGadget{<:$T}) = [cross_location($T()) .+ (0, 1)] @eval mapped_centers(::WeightedGadget{<:$T}) = [$centerloc] end \ No newline at end of file diff --git a/test/runtests.jl b/test/runtests.jl index 2350059..6c9c7ed 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -55,4 +55,8 @@ end @testset "reduceto" begin include("reduceto.jl") +end + +@testset "triangular" begin + include("triangular.jl") end \ No newline at end of file diff --git a/test/triangular.jl b/test/triangular.jl new file mode 100644 index 0000000..b5b71ca --- /dev/null +++ b/test/triangular.jl @@ -0,0 +1,104 @@ +using Test, UnitDiskMapping, Graphs, GenericTensorNetworks +using GenericTensorNetworks: TropicalF64, content +using Random +using UnitDiskMapping: is_independent_set + +@testset "triangular gadgets" begin + for s in UnitDiskMapping.crossing_ruleset_triangular_weighted + println("Testing triangular gadget:\n$s") + locs1, g1, pins1 = source_graph(s) + locs2, g2, pins2 = mapped_graph(s) + @assert length(locs1) == nv(g1) + w1 = getfield.(locs1, :weight) + w2 = getfield.(locs2, :weight) + w1[pins1] .-= 1 + w2[pins2] .-= 1 + gp1 = GenericTensorNetwork(IndependentSet(g1, w1), openvertices=pins1) + gp2 = GenericTensorNetwork(IndependentSet(g2, w2), openvertices=pins2) + m1 = solve(gp1, SizeMax()) + m2 = solve(gp2, SizeMax()) + mm1 = maximum(m1) + mm2 = maximum(m2) + @test nv(g1) == length(locs1) && nv(g2) == length(locs2) + if !(all((mm1 .== m1) .== (mm2 .== m2))) + @show m1 + @show m2 + end + @test all((mm1 .== m1) .== (mm2 .== m2)) + @test content(mm1 / mm2) == -mis_overhead(s) + end +end + +@testset "triangular copy lines" begin + for (vstart, vstop, hstop) in [ + (3, 7, 8), (3, 5, 8), (5, 9, 8), (5, 5, 8), + (1, 7, 5), (5, 8, 5), (1, 5, 5), (5, 5, 5)] + tc = UnitDiskMapping.CopyLine(1, 5, 5, vstart, vstop, hstop) + locs = UnitDiskMapping.copyline_locations(UnitDiskMapping.WeightedNode, tc; padding=2) + g = SimpleGraph(length(locs)) + weights = getfield.(locs, :weight) + for i=1:length(locs)-1 + if i==1 || locs[i-1].weight == 1 # starting point + add_edge!(g, length(locs), i) + else + add_edge!(g, i, i-1) + end + end + gp = GenericTensorNetwork(IndependentSet(g, weights)) + @test solve(gp, SizeMax())[].n == UnitDiskMapping.mis_overhead_copyline(TriangularWeighted(), tc) + end +end + +@testset "triangular map configurations back" begin + Random.seed!(2) + for graphname in [:bull, :petersen, :cubical, :house, :diamond, :tutte] + @show graphname + g = smallgraph(graphname) + weights = fill(0.25, nv(g)) + r = map_graph(TriangularWeighted(), g) + mapped_weights = UnitDiskMapping.map_weights(r, weights) + mgraph, _ = graph_and_weights(r.grid_graph) + + gp = GenericTensorNetwork(IndependentSet(mgraph, mapped_weights); optimizer=GreedyMethod(nrepeat=10)) + missize_map = solve(gp, CountingMax())[] + missize = solve(GenericTensorNetwork(IndependentSet(g, weights)), CountingMax())[] + @test r.mis_overhead + missize.n == missize_map.n + @test missize.c == missize_map.c + + T = GenericTensorNetworks.sampler_type(nv(mgraph), 2) + misconfig = solve(gp, SingleConfigMax())[].c + c = zeros(Int, size(r.grid_graph)) + for (i, n) in enumerate(r.grid_graph.nodes) + c[n.loc...] = misconfig.data[i] + end + + center_locations = trace_centers(r) + indices = CartesianIndex.(center_locations) + sc = c[indices] + @test count(isone, sc) == missize.n * 4 + @test is_independent_set(g, sc) + end +end + +@testset "triangular interface" begin + Random.seed!(2) + g = smallgraph(:petersen) + res = map_graph(TriangularWeighted(), g) + + # checking size + mgraph, _ = graph_and_weights(res.grid_graph) + ws = rand(nv(g)) + weights = UnitDiskMapping.map_weights(res, ws) + + gp = GenericTensorNetwork(IndependentSet(mgraph, weights); optimizer=TreeSA(ntrials=1, niters=10)) + missize_map = solve(gp, SizeMax())[].n + missize = solve(GenericTensorNetwork(IndependentSet(g, ws)), SizeMax())[].n + @test res.mis_overhead + missize ≈ missize_map + + # checking mapping back + T = GenericTensorNetworks.sampler_type(nv(mgraph), 2) + misconfig = solve(gp, SingleConfigMax())[].c + original_configs = map_config_back(res, collect(misconfig.data)) + @test count(isone, original_configs) == solve(GenericTensorNetwork(IndependentSet(g)), SizeMax())[].n + @test is_independent_set(g, original_configs) +end diff --git a/test/weighted.jl b/test/weighted.jl index b8331a9..a59b7ed 100644 --- a/test/weighted.jl +++ b/test/weighted.jl @@ -64,7 +64,7 @@ end # trace back configurations mgraph = SimpleGraph(ug3) weights = fill(0.5, nv(g)) - r = UnitDiskMapping.MappingResult(GridGraph(ug3), ug3.lines, ug3.padding, [tape..., tape2...], mis_overhead0+mis_overhead1+mis_overhead2) + r = UnitDiskMapping.MappingResult(GridGraph(Weighted(), ug3), ug3.lines, ug3.padding, [tape..., tape2...], mis_overhead0+mis_overhead1+mis_overhead2, ug.spacing) mapped_weights = UnitDiskMapping.map_weights(r, weights) gp = GenericTensorNetwork(IndependentSet(mgraph, mapped_weights); optimizer=GreedyMethod(nrepeat=10)) missize_map = solve(gp, CountingMax())[]