Skip to content

Add support for the triangular lattice #53

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
66 changes: 59 additions & 7 deletions src/Core.jl
Original file line number Diff line number Diff line change
Expand Up @@ -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
Comment on lines +75 to +76
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we remove these two functions?


# 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)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

use dispatch, e.g.

function graph_and_weights(grid::GridGraph{NT, <:SquareGrid}) 
function graph_and_weights(grid::GridGraph{NT, <:TriangularGrid}) where NT

# For triangular grids, use physical positions
physical_locs = [physical_position(node) for node in grid.nodes]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You do not need to use dispatch, just implement the same physical_position interface for square lattice.

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)

Expand Down
6 changes: 4 additions & 2 deletions src/UnitDiskMapping.jl
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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")
Expand All @@ -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")
Expand Down
57 changes: 34 additions & 23 deletions src/mapping.jl
Original file line number Diff line number Diff line change
Expand Up @@ -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) = 14
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is so big. Can we make it smaller, just use different spacing for X and Y axis.


Base.@kwdef struct MCell{WT} <: AbstractCell{WT}
occupied::Bool = true
Expand Down Expand Up @@ -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)]
Expand All @@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why +2 now?

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)
Expand All @@ -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

Expand Down Expand Up @@ -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
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
function mis_overhead_copyline(w::W, line::CopyLine, s::Int=4) where W
function mis_overhead_copyline(w::W, line::CopyLine, s::Int) where W

Do not use default parameter for low level API.

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
Expand All @@ -365,6 +374,7 @@ struct MappingResult{NT}
padding::Int
mapping_history::Vector{Tuple{Pattern,Int,Int}}
mis_overhead::Int
spacing::Int
end

"""
Expand Down Expand Up @@ -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

"""
Expand Down Expand Up @@ -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)
Expand Down
Loading