Skip to content

Commit 1b3c06e

Browse files
committed
Fix poisson in union of disk for hard core spatial
1 parent 22f6cbe commit 1b3c06e

File tree

5 files changed

+91
-41
lines changed

5 files changed

+91
-41
lines changed

src/display.jl

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ function plot(
1919
Plots.plot!(x[1] .+ circ_x,
2020
x[2] .+ circ_y,
2121
color="black",
22-
linewidth=0.2)
22+
linewidth=0.5)
2323
end
2424

2525
win = pp.window
@@ -33,7 +33,6 @@ function plot(
3333
ising::Ising,
3434
state
3535
)
36-
3736
pos = collect(Iterators.product(1:ising.dims[1], 1:ising.dims[2]))[:]
3837
locs_x, locs_y = map(x->x[1], pos), map(x->x[2], pos)
3938

src/hard_core_spatial.jl

Lines changed: 12 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,9 @@ end
6767

6868
"""
6969
Sample from spatial hard core model a.k.a Poisson disk sampling with intensity λ and radius r on [0, 1]^2, using Partial Rejection Sampling [https://arxiv.org/pdf/1801.07342.pdf](H. Guo, M. Jerrum).
70+
!!! warning "Side effects"
71+
72+
In the current implementation, the return sample may contain some point outside of the box! (see generate_sample_poisson_union_disks)
7073
"""
7174
function generate_sample_prs(
7275
hc::HardCorePointProcess{T};
@@ -115,32 +118,33 @@ function generate_sample_poisson_union_disks(
115118
for (i, c) in enumerate(eachcol(centers))
116119
n = rand(rng, 𝒫)
117120
n == 0 && continue
118-
proposed_points = generate_sample_uniform_in_disk(n, r, c; rng=rng)
121+
proposed_points = generate_sample_uniform_in_disk(n, c, r; rng=rng)
119122
if i == 1
120123
points = hcat(points, proposed_points)
121124
continue
122125
end
123-
centers_1i = @view centers[:, 1:i]
124-
accept = vec(all(pairwise_distances(centers_1i, proposed_points) .> r, dims=1))
126+
centers_ = @view centers[:, 1:i-1]
127+
accept = vec(all(pairwise_distances(centers_, proposed_points) .> r, dims=1))
125128
points = hcat(points, proposed_points[:, accept])
126129
end
127130
return points
128131
end
129132

130133
"""
131-
generate_sample_uniform_in_disk(n, center, radius; rng=-1)
134+
generate_sample_uniform_in_disk(n, center, radius,
132135
133136
Sample `n` points uniformly in ``D(c, r)`` (disk with `center` and `radius`)
134137
"""
135138
function generate_sample_uniform_in_disk(
136139
n::Integer,
137-
radius::Real,
138-
center::AbstractVector;
140+
center::AbstractVector,
141+
radius::Real;
139142
rng=-1
140143
)::Matrix{Float64}
141-
@assert n > 0
142-
@assert length(center) == 2
143144
@assert radius > 0
145+
@assert length(center) == 2
146+
147+
n == 0 && return Matrix{Float64}(undef, 2, 0)
144148
rng = getRNG(rng)
145149

146150
sample = repeat(center, 1, n)
@@ -152,22 +156,6 @@ function generate_sample_uniform_in_disk(
152156
return sample
153157
end
154158

155-
"""
156-
pairwise_distances(X, Y)
157-
158-
Pairwise distance matrix between columns of `X` and `Y`.
159-
Equivalent to `[norm(x - y) for x in X, y in Y]`.
160-
"""
161-
function pairwise_distances(X, Y)
162-
return Distances.pairwise(Distances.Euclidean(1e-8), X, Y; dims=2)
163-
end
164-
165-
function pairwise_distances(X)
166-
dist = Distances.pairwise(Distances.Euclidean(1e-8), X; dims=2)
167-
dist[LA.diagind(dist)] .= Inf
168-
return dist
169-
end
170-
171159
# Default sample generate_sample
172160

173161
"""

src/utils.jl

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,3 +55,20 @@ function random_edge_orientation(
5555
rng = getRNG(rng)
5656
return LG.SimpleDiGraphFromIterator(rand(rng) < p ? e : reverse(e) for e in LG.edges(g))
5757
end
58+
59+
60+
"""
61+
pairwise_distances(X, Y)
62+
63+
Pairwise distance matrix between columns of `X` and `Y`.
64+
Equivalent to `[norm(x - y) for x in X, y in Y]`.
65+
"""
66+
function pairwise_distances(X, Y)
67+
return Distances.pairwise(Distances.Euclidean(1e-8), X, Y; dims=2)
68+
end
69+
70+
function pairwise_distances(X)
71+
dist = Distances.pairwise(Distances.Euclidean(1e-8), X; dims=2)
72+
dist[LA.diagind(dist)] .= Inf
73+
return dist
74+
end

src/window.jl

Lines changed: 60 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,44 +1,54 @@
11
abstract type AbstractWindow end
22

3+
# Discrete
4+
35
abstract type AbstractDiscreteWindow{T} <: AbstractWindow end
46

57
struct GraphNode{T<:Int64} <: AbstractDiscreteWindow{T}
68
# Corner
79
idx::T
810
end
11+
function GraphNode(idx::Integer)
12+
return GraphNode{typeof(idx)}(idx)
13+
end
14+
15+
# Spatial
916

1017
abstract type AbstractSpatialWindow{T<:Float64} <: AbstractWindow end
18+
19+
abstract type AbstractRectangleWindow{T} <: AbstractSpatialWindow{T} end
1120
# Πᵢ [cᵢ, cᵢ + wᵢ]
12-
struct RectangleWindow{T} <: AbstractSpatialWindow{T}
21+
struct RectangleWindow{T} <: AbstractRectangleWindow{T}
1322
# Corner
1423
c::Vector{T}
1524
# Width
1625
w::Vector{T}
1726
end
1827

28+
function RectangleWindow(c::Vector, w::Vector)
29+
@assert length(c) == length(w)
30+
return RectangleWindow{Float64}(c, w)
31+
end
32+
1933
# Πᵢ [cᵢ, cᵢ + w]
20-
struct SquareWindow{T} <: AbstractSpatialWindow{T}
34+
struct SquareWindow{T} <: AbstractRectangleWindow{T}
2135
# Corner
2236
c::Vector{T}
2337
# Width
2438
w::T
2539
end
2640

27-
function GraphNode(idx::Integer)
28-
return GraphNode{typeof(idx)}(idx)
29-
end
30-
31-
function RectangleWindow(c::Vector, w::Vector)
32-
@assert length(c) == length(w)
33-
return RectangleWindow{Float64}(float.(c), float.(w))
41+
function SquareWindow(c::Vector, w::Real)
42+
return SquareWindow{Float64}(c, w)
3443
end
3544

36-
function SquareWindow(c::Vector, w::Real)
37-
return SquareWindow{Float64}(float.(c), float(w))
45+
struct BallWindow{T} <: AbstractSpatialWindow{T}
46+
center::Vector{T}
47+
radius::T
3848
end
3949

40-
function spatial_window(c::Vector, w::Union{Real,Vector})
41-
return allequal(w) ? SquareWindow(c, w[1]) : RectangleWindow(c, w)
50+
function BallWindow(center::Vector, radius::Real)
51+
return BallWindow{Float64}(center, radius)
4252
end
4353

4454
dimension(win::GraphNode) = 0
@@ -47,11 +57,47 @@ dimension(win::AbstractSpatialWindow) = length(win.c)
4757
volume(win::GraphNode) = 0
4858
volume(win::RectangleWindow) = prod(win.w)
4959
volume(win::SquareWindow) = win.w^dimension(win)
60+
function volume(win::BallWindow)
61+
d = dimension(win)
62+
return π^(d/2) * win.radius^d / gamma(d/2 + 1)
63+
end
64+
65+
function Base.in(
66+
x::AbstractVector,
67+
win::AbstractRectangleWindow
68+
)
69+
return all(win.c .<= x) && all(x .<= win.c .+ win.w)
70+
end
71+
72+
function Base.in(
73+
x::AbstractVector,
74+
win::BallWindow
75+
)
76+
return Distances.euclidean(x, win.center) <= win.radius
77+
end
5078

79+
"""
80+
Sample uniformly in `RectangleWindow`
81+
"""
5182
function Base.rand(
52-
win::AbstractSpatialWindow{T};
83+
win::AbstractRectangleWindow{T};
5384
rng=-1
5485
)::Vector{T} where {T}
5586
rng = getRNG(rng)
5687
return win.c .+ win.w .* rand(rng, T, dimension(win))
5788
end
89+
90+
"""
91+
Sample uniformly in `BallWindow`
92+
"""
93+
function Base.rand(
94+
win::BallWindow{T};
95+
rng=-1
96+
)::Vector{T} where {T}
97+
rng = getRNG(rng)
98+
d = dimension(win)
99+
x = zeros(T, d+2)
100+
randn!(rng, x)
101+
normalize!(x)
102+
return win.radius .* x[1:d] .+ win.center
103+
end

test/hard_core_spatial.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ using PartialRejectionSampling
22
const PRS = PartialRejectionSampling
33

44
β₀ = 0.1
5-
r = 0.01 # interaction range = 2*radius
5+
r = 0.05 # interaction range = 2*radius
66
b = β₀ /* (r/2)^2)
77

88
c, w = [0.0, 0.0], 1.0

0 commit comments

Comments
 (0)