Skip to content
This repository was archived by the owner on Nov 6, 2023. It is now read-only.

Commit 925425d

Browse files
ErickChaconjuliohm
andauthored
Inhomogeneous (#32)
* sampling for inhomogeneous poisson process * use rand instead of rand_single * remove all method for box * export thinnedsampling * Sampling over a Geometry or Mesh * remove discretized sampling for inhomogeneous case * remove completely productsampling * point process with piecewise constant intensity * discretizedsampling for inhomogeneous process * documentation for poisson process * more methods when lambda is a vector * fix grammar * Apply suggestions from code review Space where to sample without particular type. Co-authored-by: Júlio Hoffimann <[email protected]> * fix tests * return nothing when no points need to be sampled * discrete sampling with intensity function over mesh * default sampling depending only on pointprocess * alternative SimpleThinnedSampling * fix grammar * adding tests for sampling PoissonProcess * remove comment * lowercase comments * Update src/processes/binomial.jl Co-authored-by: Júlio Hoffimann <[email protected]> * Update src/processes/poisson.jl Co-authored-by: Júlio Hoffimann <[email protected]> * Update src/processes/poisson.jl Co-authored-by: Júlio Hoffimann <[email protected]> * Update src/processes/poisson.jl Co-authored-by: Júlio Hoffimann <[email protected]> * Apply suggestions from code review Co-authored-by: Júlio Hoffimann <[email protected]> * remove collect * remove simplethinnedsampling * remove export simplethinnedsampling * empty * simplify thinnedsampling * abstractvector * prepare to not export sampling algorithms * Do not export sampling methods Co-authored-by: Júlio Hoffimann <[email protected]> * default_sampling depends also of geometry * use rand_single inside rand_single * documenting DiscretizedSampling * defaults sampling depends of geometry * keep same order for sampling methods --------- Co-authored-by: Júlio Hoffimann <[email protected]>
1 parent b37c55e commit 925425d

File tree

5 files changed

+148
-67
lines changed

5 files changed

+148
-67
lines changed

src/processes.jl

Lines changed: 22 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -23,16 +23,16 @@ Generate `n` realizations of spatial point process `p`
2323
inside geometry `g`. Optionally specify sampling
2424
algorithm `algo` and random number generator `rng`.
2525
"""
26-
Base.rand(rng::Random.AbstractRNG, p::PointProcess, g::Geometry, n::Int; algo=default_sampling_algorithm(p, g)) =
26+
Base.rand(rng::Random.AbstractRNG, p::PointProcess, g, n::Int; algo=default_sampling_algorithm(p, g)) =
2727
[rand_single(rng, p, g, algo) for i in 1:n]
2828

29-
Base.rand(rng::Random.AbstractRNG, p::PointProcess, g::Geometry; algo=default_sampling_algorithm(p, g)) =
29+
Base.rand(rng::Random.AbstractRNG, p::PointProcess, g; algo=default_sampling_algorithm(p, g)) =
3030
rand_single(rng, p, g, algo)
3131

32-
Base.rand(p::PointProcess, g::Geometry, n::Int; algo=default_sampling_algorithm(p, g)) =
32+
Base.rand(p::PointProcess, g, n::Int; algo=default_sampling_algorithm(p, g)) =
3333
rand(Random.GLOBAL_RNG, p, g, n; algo=algo)
3434

35-
Base.rand(p::PointProcess, g::Geometry; algo=default_sampling_algorithm(p, g)) =
35+
Base.rand(p::PointProcess, g; algo=default_sampling_algorithm(p, g)) =
3636
rand(Random.GLOBAL_RNG, p, g; algo=algo)
3737

3838
"""
@@ -47,17 +47,32 @@ function rand_single end
4747
default_sampling_algorithm(p, g)
4848
4949
Default sampling algorithm for spatial point process `p`
50-
on geometry `g`.
50+
on geometry or domain `g`.
5151
"""
5252
function default_sampling_algorithm end
5353

5454
# --------------------
5555
# SAMPLING ALGORITHMS
5656
# --------------------
5757

58-
struct ProductSampling end
59-
struct ThinnedSampling end
58+
"""
59+
ThinnedSampling(λmax)
60+
61+
Generate sample using Lewis-Shedler algorithm (1979) with
62+
maximum real value `λmax` of the intensity function.
63+
"""
64+
struct ThinnedSampling{T<:Real}
65+
λmax::T
66+
end
67+
68+
"""
69+
DiscretizedSampling()
70+
71+
Generate sample assuming the intensity is constant over a `Geometry`
72+
or piecewise constant over a `Domain`.
73+
"""
6074
struct DiscretizedSampling end
75+
6176
struct UnionSampling end
6277

6378
#-----------------

src/processes/binomial.jl

Lines changed: 4 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -13,15 +13,9 @@ end
1313

1414
ishomogeneous(p::BinomialProcess) = true
1515

16-
default_sampling_algorithm(::BinomialProcess, ::Geometry) = ProductSampling()
16+
default_sampling_algorithm(::BinomialProcess, ::Any) = DiscretizedSampling()
1717

18-
function rand_single(rng::Random.AbstractRNG, p::BinomialProcess, b::Box{Dim,T}, ::ProductSampling) where {Dim,T}
19-
# region configuration
20-
lo, up = coordinates.(extrema(b))
21-
22-
# product of uniform distributions
23-
U = product_distribution([Uniform(lo[i], up[i]) for i in 1:Dim])
24-
25-
# return point pattern
26-
PointSet(rand(rng, U, p.n))
18+
function rand_single(rng::Random.AbstractRNG, p::BinomialProcess, g, ::DiscretizedSampling)
19+
points = sample(g, HomogeneousSampling(p.n))
20+
PointSet(points)
2721
end

src/processes/poisson.jl

Lines changed: 61 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,14 @@
55
"""
66
PoissonProcess(λ)
77
8-
A Poisson process with intensity `λ`.
8+
A Poisson process with intensity `λ`. For a homogeneous process,
9+
define `λ` as a constant real value, while for an inhomogeneous process,
10+
define `λ` as a function or vector of values. If `λ` is a vector, it is
11+
assumed that the process is associated with a `Domain` with the same
12+
number of elements as `λ`.
913
"""
10-
struct PoissonProcess{L<:Union{Real,Function}} <: PointProcess
14+
15+
struct PoissonProcess{L<:Union{Real,Function,AbstractVector}} <: PointProcess
1116
λ::L
1217
end
1318

@@ -19,61 +24,82 @@ Base.union(p₁::PoissonProcess{<:Real}, p₂::PoissonProcess{<:Function}) = Poi
1924

2025
Base.union(p₁::PoissonProcess{<:Function}, p₂::PoissonProcess{<:Real}) = PoissonProcess(x -> p₁.λ(x) + p₂.λ)
2126

27+
Base.union(p₁::PoissonProcess{<:AbstractVector}, p₂::PoissonProcess{<:AbstractVector}) = PoissonProcess(x -> p₁.λ + p₂.λ)
28+
2229
ishomogeneous(p::PoissonProcess{<:Real}) = true
2330
ishomogeneous(p::PoissonProcess{<:Function}) = false
31+
ishomogeneous(p::PoissonProcess{<:AbstractVector}) = false
2432

25-
default_sampling_algorithm(::PoissonProcess, ::Geometry) = DiscretizedSampling()
26-
default_sampling_algorithm(::PoissonProcess{<:Real}, ::Box) = ProductSampling()
33+
default_sampling_algorithm(::PoissonProcess, ::Any) = DiscretizedSampling()
34+
default_sampling_algorithm(p::PoissonProcess{<:Function}, g) = ThinnedSampling(default_lambda_max(p, g))
35+
36+
function default_lambda_max(p::PoissonProcess{<:Function}, g)
37+
points = sample(g, HomogeneousSampling(10000))
38+
λvec = p.λ.(points)
39+
maximum(λvec) + 0.05 * (maximum(λvec) - minimum(λvec))
40+
end
2741

2842
#------------------
2943
# HOMOGENEOUS CASE
3044
#------------------
3145

32-
function rand_single(rng::Random.AbstractRNG, p::PoissonProcess{<:Real}, g::Geometry, ::DiscretizedSampling)
46+
function rand_single(rng::Random.AbstractRNG, p::PoissonProcess{<:Real}, g, ::DiscretizedSampling)
3347
# simulate number of points
3448
λ = p.λ
3549
V = measure(g)
3650
n = rand(rng, Poisson* V))
3751

38-
# simulate homogeneous process
39-
pts = sample(g, HomogeneousSampling(n))
40-
41-
# return point pattern
42-
PointSet(collect(pts))
43-
end
44-
45-
function rand_single(rng::Random.AbstractRNG, p::PoissonProcess{<:Real}, b::Box, ::ProductSampling)
46-
# region configuration
47-
lo, up = coordinates.(extrema(b))
48-
49-
# simulate number of points
50-
λ = p.λ
51-
V = measure(b)
52-
n = rand(rng, Poisson* V))
53-
54-
# product of uniform distributions
55-
U = product_distribution([Uniform(lo[i], up[i]) for i in 1:embeddim(b)])
52+
if iszero(n)
53+
# PointSet{embeddim(g), coordtype(g)}([])
54+
nothing
55+
else
56+
# simulate homogeneous process
57+
points = sample(g, HomogeneousSampling(n))
5658

57-
# return point pattern
58-
PointSet(rand(rng, U, n))
59+
# return point pattern
60+
PointSet(points)
61+
end
5962
end
6063

6164
#--------------------
6265
# INHOMOGENEOUS CASE
6366
#--------------------
6467

65-
function rand_single(rng::Random.AbstractRNG, p::PoissonProcess{<:Function}, b::Box, algo::DiscretizedSampling)
66-
# discretize region
67-
# TODO
68+
function rand_single(rng::Random.AbstractRNG, p::PoissonProcess{<:AbstractVector}, d::Domain, algo::DiscretizedSampling)
69+
# simulate number of points
70+
λ = p.λ
71+
V = measure.(d)
72+
n = rand(rng, Poisson(sum.* V)))
73+
74+
# simulate n points
75+
if iszero(n)
76+
nothing
77+
else
78+
# sample elements with weights proportial to expected number of points
79+
w = WeightedSampling(n, λ .* V, replace = true)
80+
81+
# within each element sample a single point
82+
sampler = HomogeneousSampling(1)
83+
points = (first(sample(rng, e, sampler)) for e in sample(rng, d, w))
84+
85+
# return point pattern
86+
PointSet(points)
87+
end
88+
end
6889

69-
# discretize retention
70-
# TODO
90+
function rand_single(rng::Random.AbstractRNG, p::PoissonProcess{<:Function}, g, algo::ThinnedSampling)
91+
# simulate a homogeneous process
92+
pp = rand_single(rng, PoissonProcess(algo.λmax), g, DiscretizedSampling())
7193

72-
# sample each element
73-
# TODO
94+
# thin point pattern
95+
thin(pp, RandomThinning(x -> p.λ(x) / algo.λmax))
7496
end
7597

76-
function rand_single(rng::Random.AbstractRNG, p::PoissonProcess{<:Function}, b::Box, algo::ThinnedSampling)
77-
# Lewis-Shedler algorithm
78-
# TODO
98+
function rand_single(rng::Random.AbstractRNG, p::PoissonProcess{<:Function}, d::Domain, algo::DiscretizedSampling)
99+
# compute intensity on centroids
100+
c = centroid.(d)
101+
λvec = p.λ.(c)
102+
103+
# simulate inhomogeneous process
104+
rand_single(rng, PoissonProcess(λvec), d, algo)
79105
end

src/processes/union.jl

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,9 +21,9 @@ Base.union(p₁::PointProcess, p₂::PointProcess) = UnionProcess(p₁, p₂)
2121

2222
ishomogeneous(p::UnionProcess) = ishomogeneous(p.p₁) && ishomogeneous(p.p₂)
2323

24-
default_sampling_algorithm(::UnionProcess, ::Geometry) = UnionSampling()
24+
default_sampling_algorithm(::UnionProcess, ::Any) = UnionSampling()
2525

26-
function rand_single(rng::Random.AbstractRNG, p::UnionProcess, g::Geometry, ::UnionSampling)
26+
function rand_single(rng::Random.AbstractRNG, p::UnionProcess, g, ::UnionSampling)
2727
pp₁ = rand(rng, p.p₁, g)
2828
pp₂ = rand(rng, p.p₂, g)
2929

test/processes.jl

Lines changed: 59 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,18 @@
11
@testset "Processes" begin
2+
seg = Segment((0.0,0.0), (11.3,11.3))
3+
tri = Triangle((0.0, 0.0), (5.65, 0.0), (5.65, 5.65))
4+
quad = Quadrangle((0.0,0.0), (0.0,4.0), (4.0, 4.0), (4.0, 0.0))
5+
box = Box((0.0,0.0), (4.0, 4.0))
6+
ball = Ball((1.0,1.0), 2.25)
7+
outer = Point2[(0,-4),(4,-1),(4,1.5),(0,3)]
8+
hole1 = Point2[(0.2,-0.2),(1.4,-0.2),(1.4,0.6),(0.2,0.6)]
9+
hole2 = Point2[(2,-0.2),(3,-0.2),(3,0.4),(2,0.4)]
10+
poly = PolyArea(outer, [hole1, hole2])
11+
grid = CartesianGrid((0,0), (4,4), dims = (10, 10))
12+
points = Point2[(0, 0), (4.5, 0), (0, 4.2), (4, 4.3), (1.5, 1.5)]
13+
connec = connect.([(1, 2, 5), (2, 4, 5), (4, 3, 5), (3, 1, 5)], Triangle)
14+
mesh = SimpleMesh(points, connec)
15+
216
@testset "Basic" begin
317
for p in [BinomialProcess(100), PoissonProcess(100.0)]
418
b = Box((0.0, 1.0), (1.0, 2.0))
@@ -10,22 +24,54 @@
1024
end
1125

1226
@testset "Binomial" begin
13-
# TODO
27+
p = BinomialProcess(10)
28+
for g in [seg, tri, quad, box, ball, poly, grid, mesh]
29+
pp = rand(p, g)
30+
@test nelements(pp) == 10
31+
@test all((g), pp)
32+
end
1433
end
1534

1635
@testset "Poisson" begin
17-
p = PoissonProcess(100.0)
18-
t = Triangle((0.0, 0.0), (1.0, 0.0), (1.0, 1.0))
19-
pp = rand(p, t)
20-
xs = coordinates.(pp)
21-
@test all(0 .≤ first.(xs) .≤ 1)
22-
@test all(0 .≤ last.(xs))
23-
24-
q = Quadrangle((0.0, 0.0), (1.0, 0.0), (1.0, 1.0), (0.0, 1.0))
25-
pp = rand(p, q)
26-
xs = coordinates.(pp)
27-
@test all(0 .≤ first.(xs) .≤ 1)
28-
@test all(0 .≤ last.(xs) .≤ 1)
36+
# homogeneous
37+
p = PoissonProcess(10.0)
38+
for g in [seg, tri, quad, box, ball, poly, grid, mesh]
39+
pp = rand(p, g)
40+
@test all((g), pp)
41+
end
42+
43+
# inhomogeneous with intensity function
44+
λ(s::Point2) = sum(coordinates(s) .^ 2)
45+
p = PoissonProcess(λ)
46+
for g in [seg, tri, quad, box, ball, poly, grid, mesh]
47+
# default thinnedsampling
48+
pp = rand(p, g)
49+
@test all((g), pp)
50+
# custom thinnedsampling using λmax
51+
pp = rand(p, g, algo = PointPatterns.ThinnedSampling(λ(Point2(12.0, 12.0))))
52+
@test all((g), pp)
53+
# discretizedsampling
54+
g = discretize(g)
55+
pp = rand(p, g, algo = PointPatterns.DiscretizedSampling())
56+
@test all((g), g)
57+
end
58+
59+
# inhomogeneous with piecewise constant intensity
60+
for g in [grid, mesh]
61+
λ(s::Point2) = sum(coordinates(s) .^ 2)
62+
λvec = λ.(centroid.(g))
63+
p = PoissonProcess(λvec)
64+
# discretizedsampling by default
65+
pp = rand(p, g)
66+
@test all((g), pp)
67+
end
68+
69+
# empty pointsets
70+
for g in [seg, tri, quad, box, ball, poly, grid, mesh]
71+
@test isnothing(rand(PoissonProcess(0.0), seg))
72+
end
73+
ps = PointSet(rand(Point2, 10))
74+
@test isnothing(rand(PoissonProcess(100.0), ps))
2975
end
3076

3177
@testset "Union" begin

0 commit comments

Comments
 (0)