-
Notifications
You must be signed in to change notification settings - Fork 1
Fix issue #25 #30
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?
Fix issue #25 #30
Changes from all commits
1192a5c
6cbdce8
f41d44f
70fe42a
58aadbb
e10eeba
4d2d256
1cb4d2f
513d64b
bb50db3
4d3d0ee
066ad54
2beb57e
39fb976
5d24835
0c0e3d8
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 |
|---|---|---|
| @@ -0,0 +1,61 @@ | ||
| using DiscreteVoronoi | ||
| using BenchmarkTools | ||
| using Random | ||
| using StaticArrays | ||
|
|
||
| using DiscreteVoronoi: Coord, exact_aux, centre_anchor_aux, exact_aux_es, centre_anchor_aux_es | ||
|
|
||
| function random_coordinates(N, M, K) | ||
| Coord.(shuffle!([Iterators.product(1:N, 1:M)...])[1:min(N * M, K)]) | ||
| end | ||
|
|
||
| for n in [400] | ||
| for s in [isqrt(n), n, n * isqrt(n), n * n] | ||
| @show n, s | ||
|
|
||
| println("jfa_voronoi!") | ||
| @btime jfa_voronoi!(grid, sites) setup = ( | ||
| Random.seed!(42); | ||
| grid = zeros(Coord, ($n, $n)); | ||
| sites = random_coordinates(size(grid)..., $s)) evals=1 | ||
|
|
||
| if s <= n | ||
| println("dac_voronoi!") | ||
| @btime dac_voronoi!(grid, sites) setup=( | ||
| Random.seed!(42); | ||
| grid = zeros(Coord, ($n, $n)); | ||
| sites = random_coordinates(size(grid)..., $s); | ||
| preset_voronoi!(grid, sites)) evals=1 | ||
| end | ||
|
|
||
| println("redac_voronoi!") | ||
| @show exact_aux | ||
| @btime redac_voronoi!(grid, sites, auxiliary=exact_aux) setup=( | ||
| Random.seed!(42); | ||
| grid = zeros(Coord, ($n, $n)); | ||
| sites = random_coordinates(size(grid)..., $s); | ||
| preset_voronoi!(grid, sites)) evals=1 | ||
|
|
||
| @show centre_anchor_aux | ||
| @btime redac_voronoi!(grid, sites, auxiliary=centre_anchor_aux) setup=( | ||
| Random.seed!(42); | ||
| grid = zeros(Coord, ($n, $n)); | ||
| sites = random_coordinates(size(grid)..., $s); | ||
| preset_voronoi!(grid, sites)) evals=1 | ||
|
|
||
| println("redac_voronoi_es!") | ||
| @show exact_aux_es | ||
| @btime redac_voronoi_es!(grid, sites, auxiliary=exact_aux_es) setup=( | ||
| Random.seed!(42); | ||
| grid = zeros(Coord, ($n, $n)); | ||
| sites = random_coordinates(size(grid)..., $s); | ||
| preset_voronoi!(grid, sites)) evals=1 | ||
|
|
||
| @show centre_anchor_aux_es | ||
| @btime redac_voronoi_es!(grid, sites, auxiliary=centre_anchor_aux_es) setup=( | ||
| Random.seed!(42); | ||
| grid = zeros(Coord, ($n, $n)); | ||
| sites = random_coordinates(size(grid)..., $s); | ||
| preset_voronoi!(grid, sites)) evals=1 | ||
| end | ||
| end |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -50,6 +50,15 @@ function jfa_voronoi!(grid::Matrix{T}, sites::Vector{T}; distance=euclidean) whe | |
| return nothing | ||
| end | ||
|
|
||
| @inbounds function preset_voronoi!(grid, sites) | ||
| for site in sites | ||
| if checkbounds(Bool, grid, site...) | ||
| grid[site...] = site | ||
| end | ||
| end | ||
| return nothing | ||
| end | ||
|
|
||
| """ | ||
| dac_voronoi!(grid::Matrix{T}, sites::Vector{T}; distance=euclidean) where {T<:SVector{2,Int}} | ||
|
|
||
|
|
@@ -67,19 +76,31 @@ end | |
| if all(BR .== TL) | ||
| grid[TL...] = find_closest_site(TL, sites, distance=distance) | ||
| elseif length(sites) == 1 # Same if there is a single site | ||
| view(grid, TL[1]:BR[1], TL[2]:BR[2]) .= Ref(first(sites)) | ||
| grid[TL[1]:BR[1], TL[2]:BR[2]] .= Ref(first(sites)) | ||
| else | ||
| # Otherwise we check if all corners have the same closest site | ||
| all(site -> site != zero(Coord), @view grid[TL[1]:BR[1], TL[2]:BR[2]]) && return nothing | ||
| # Otherwise we check if all corners have the same closest site ... | ||
|
Owner
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. This part I don't understand
Collaborator
Author
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. If you modify the code here like you'll see the non unique sites and if you also set the rectangle to the the site you'll see the test failures for Chebyshev distance. BTW we could also drop the whole code sequence, because filtering is good enough (see the benchmark for different find and filter combinations in legacy). |
||
| corners = get_corners(TL, BR) | ||
| closest_corners = (find_closest_site(corner, sites, distance=distance) for corner in corners) | ||
| if allequal(closest_corners) | ||
| grid[TL[1]:BR[1], TL[2]:BR[2]] .= Ref(first(closest_corners)) | ||
| else | ||
| # And if not we divide the grid into quadrants and "conquer" each one | ||
| for (quadrant_TL, quadrant_BR) in get_quadrants(TL, BR) | ||
| _dac_voronoi!(grid, quadrant_TL, quadrant_BR, sites; distance=distance) | ||
| mins = ((findmin(sites) do site | ||
| distance(corner, site) | ||
| end for corner in corners)...,) | ||
| if allequal(site for (dist, site) in mins) | ||
| # ... and if the closest site is unique | ||
| min_site = sites[mins[1][2]] | ||
| dists = ((minimum(site for site in sites if site != min_site) do site | ||
| distance(corner, site) | ||
| end for corner in corners)...,) | ||
| if all(zip(mins, dists)) do ((min_dist, _), dist) | ||
| dist > min_dist | ||
| end | ||
| grid[TL[1]:BR[1], TL[2]:BR[2]] .= Ref(min_site) | ||
| return nothing | ||
| end | ||
| end | ||
| # And if not we divide the grid into quadrants and "conquer" each one | ||
| for (quadrant_TL, quadrant_BR) in get_quadrants(TL, BR) | ||
| _dac_voronoi!(grid, quadrant_TL, quadrant_BR, sites; distance=distance) | ||
| end | ||
| end | ||
| return nothing | ||
| end | ||
|
|
@@ -93,32 +114,58 @@ step which aims to reduce the work of subsequent steps. | |
| function redac_voronoi!(grid::Matrix{T}, sites::Vector{T}; distance=euclidean, auxiliary=exact_aux) where {T<:Coord} | ||
| TL = 1, 1 | ||
| BR = size(grid) | ||
| _redac_voronoi!(grid, TL, BR, EarlyStopper(sites); distance=distance, auxiliary=auxiliary) | ||
| _redac_voronoi!(grid, TL, BR, sites; distance=distance, auxiliary=auxiliary) | ||
| return nothing | ||
| end | ||
|
|
||
| @inbounds function _redac_voronoi!(grid, TL, BR, sites::ES; distance, auxiliary) where {ES<:EarlyStopper} | ||
| @inbounds function _redac_voronoi!(grid, TL, BR, sites; distance, auxiliary) | ||
| any(TL .> BR) && return nothing | ||
| # Then, if the grid is a single cell then we are done | ||
| if all(BR .== TL) | ||
| find_closest_site!(grid, TL, sites; distance=distance) | ||
| elseif length(sites) == 1 # Same if there is a single site | ||
| view(grid, TL[1]:BR[1], TL[2]:BR[2]) .= Ref(first(sites)) | ||
| grid[TL[1]:BR[1], TL[2]:BR[2]] .= Ref(first(sites)) | ||
| else | ||
| # Otherwise we check if all corners have the same closest site | ||
| corners = get_corners(TL, BR) | ||
| closest_corners = (find_closest_site!(grid, corner, sites, distance=distance) for corner in corners) | ||
| if allequal(closest_corners) | ||
| view(grid, TL[1]:BR[1], TL[2]:BR[2]) .= Ref(first(closest_corners)) | ||
| else | ||
| # And if not we eliminate faraway seeds from subsequent steps | ||
| # `auxiliary` sorts sites by whether the predicate is true and stores how many are true. | ||
| local_sites = auxiliary(grid, sites, TL, BR; distance=distance) | ||
| # then divide the grid into quadrants and "conquer" each one | ||
| for (quadrant_TL, quadrant_BR) in get_quadrants(TL, BR) | ||
| _redac_voronoi!(grid, quadrant_TL, quadrant_BR, local_sites; distance=distance, auxiliary=auxiliary) | ||
| end | ||
| all(site -> site != zero(Coord), @view grid[TL[1]:BR[1], TL[2]:BR[2]]) && return nothing | ||
| # And if not we eliminate faraway seeds from subsequent steps | ||
| # `auxiliary` sorts sites by whether the predicate is true and stores how many are true. | ||
| local_sites = auxiliary(grid, sites, TL, BR; distance=distance) | ||
| # then divide the grid into quadrants and "conquer" each one | ||
| for (quadrant_TL, quadrant_BR) in get_quadrants(TL, BR) | ||
| _redac_voronoi!(grid, quadrant_TL, quadrant_BR, local_sites; distance=distance, auxiliary=auxiliary) | ||
| end | ||
| end | ||
| return nothing | ||
| end | ||
|
|
||
| """ | ||
| redac_voronoi!(grid::Matrix{T}, sites::Vector{T}; distance=euclidean, auxiliary=exact_aux) where {T<:SVector{2,Int}} | ||
| Performs a divide-and-conquer method similar to `dac_voronoi!` but has an additional site-elimination | ||
| step which aims to reduce the work of subsequent steps. | ||
| """ | ||
| function redac_voronoi_es!(grid::Matrix{T}, sites::Vector{T}; distance=euclidean, auxiliary=exact_aux) where {T<:Coord} | ||
| TL = 1, 1 | ||
| BR = size(grid) | ||
| _redac_voronoi_es!(grid, TL, BR, EarlyStopper(sites); distance=distance, auxiliary=auxiliary) | ||
| return nothing | ||
| end | ||
|
|
||
| @inbounds function _redac_voronoi_es!(grid, TL, BR, sites::ES; distance, auxiliary) where {ES<:EarlyStopper} | ||
| any(TL .> BR) && return nothing | ||
| # Then, if the grid is a single cell then we are done | ||
| if all(BR .== TL) | ||
| find_closest_site!(grid, TL, sites; distance=distance) | ||
| elseif length(sites) == 1 # Same if there is a single site | ||
| grid[TL[1]:BR[1], TL[2]:BR[2]] .= Ref(first(sites)) | ||
| else | ||
| all(site -> site != zero(Coord), @view grid[TL[1]:BR[1], TL[2]:BR[2]]) && return nothing | ||
| # And if not we eliminate faraway seeds from subsequent steps | ||
| # `auxiliary` sorts sites by whether the predicate is true and stores how many are true. | ||
| local_sites = auxiliary(grid, sites, TL, BR; distance=distance) | ||
| # then divide the grid into quadrants and "conquer" each one | ||
| for (quadrant_TL, quadrant_BR) in get_quadrants(TL, BR) | ||
| _redac_voronoi_es!(grid, quadrant_TL, quadrant_BR, local_sites; distance=distance, auxiliary=auxiliary) | ||
| end | ||
| end | ||
| return nothing | ||
| end | ||
| end | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -15,14 +15,30 @@ function exact_condition(site, sites, TL, BR; distance=euclidean) | |
| end | ||
|
|
||
| function centre_anchor_condition(site, sites, TL, BR; distance=euclidean) | ||
| centre = @. TL + BR / 2 | ||
| anchor = find_closest_site(centre, sites) | ||
| centre = @. (TL + BR) / 2 | ||
| anchor = find_closest_site(centre, sites; distance=distance) | ||
|
Owner
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. Good find, didn't realise this was bugged |
||
| corners = get_corners(TL, BR) | ||
| return any(distance(site, corner) <= distance(anchor, corner) for corner in corners) | ||
| end | ||
|
|
||
| function centre_anchor_aux(grid, sites, TL, BR; distance=euclidean) | ||
| centre = @. TL + BR / 2 | ||
| centre = @. (TL + BR) / 2 | ||
| anchor = find_closest_site(centre, sites; distance=distance) | ||
| corners = get_corners(TL, BR) | ||
| function predicate(site) | ||
| return all(TL .<= site .<= BR) || | ||
| any(distance(corner, site) <= distance(corner, anchor) for corner in corners) | ||
| end | ||
| return unstable_partition!(predicate, sites)[1] | ||
| end | ||
|
|
||
| function exact_aux(grid, sites, TL, BR; distance=euclidean) | ||
| predicate(site) = all(TL .<= site .<= BR) || exact_condition(site, sites, TL, BR; distance=distance) | ||
| return unstable_partition!(predicate, sites)[1] | ||
| end | ||
|
|
||
| function centre_anchor_aux_es(grid, sites, TL, BR; distance=euclidean) | ||
| centre = @. (TL + BR) / 2 | ||
| anchor = find_closest_site(centre, sites) | ||
| corners = get_corners(TL, BR) | ||
| function predicate(site) | ||
|
|
@@ -32,7 +48,7 @@ function centre_anchor_aux(grid, sites, TL, BR; distance=euclidean) | |
| return early_stop_sort!(sites, predicate) | ||
| end | ||
|
|
||
| function exact_aux(grid, sites, TL, BR; distance=euclidean) | ||
| function exact_aux_es(grid, sites, TL, BR; distance=euclidean) | ||
| predicate(site) = all(TL .<= site .<= BR) || exact_condition(site, sites, TL, BR; distance=distance) | ||
| return early_stop_sort!(sites, predicate) | ||
| end | ||
| end | ||
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.
thumbs up