-
Notifications
You must be signed in to change notification settings - Fork 5
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
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -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) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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] | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You do not need to use dispatch, just implement the same |
||
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) | ||
|
||
|
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
|
@@ -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 | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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 | ||||||
|
@@ -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 | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why |
||||||
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 | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
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 | ||||||
|
@@ -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) | ||||||
|
There was a problem hiding this comment.
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?