Skip to content

Commit 79cd78b

Browse files
authored
Merge pull request #27 from mauriciogtec/docs+workflows
Docs+workflows
2 parents 385f824 + 51c1066 commit 79cd78b

26 files changed

Lines changed: 4299 additions & 404 deletions

.github/workflows/Docs.yml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -50,9 +50,9 @@ jobs:
5050
run: |
5151
julia --project=docs -e '
5252
using Documenter: DocMeta, doctest
53-
using ARSampling
54-
DocMeta.setdocmeta!(ARSampling, :DocTestSetup, :(using ARSampling); recursive=true)
55-
doctest(ARSampling)'
53+
using AdaptiveRejectionSampling
54+
DocMeta.setdocmeta!(AdaptiveRejectionSampling, :DocTestSetup, :(using AdaptiveRejectionSampling); recursive=true)
55+
doctest(AdaptiveRejectionSampling)'
5656
- name: Generate and deploy documentation
5757
run: julia --project=docs docs/make.jl
5858
env:

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,3 +2,4 @@
22
*.jl.*.cov
33
*.jl.mem
44
Manifest.toml
5+
**/build/

README.md

Lines changed: 47 additions & 88 deletions
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,13 @@ This package is useful for efficient sampling from log-concave univariate densit
1212
## Examples
1313

1414
```julia
15-
using AdaptiveRejectionSampling: Objective, ARSampler, sample!, eval_hull, abscissae
15+
# Import packages and setup
16+
using AdaptiveRejectionSampling: Objective, ARSampler, sample!, eval_hull, abscissae, hullplot!
1617
using SpecialFunctions: gamma
1718
using CairoMakie
19+
using Chairmarks
20+
21+
set_theme!(theme_minimal())
1822
```
1923

2024
### Sampling from a shifted normal distribution
@@ -31,18 +35,18 @@ function bench()
3135
# Build the sampler and simulate 10,000 samples
3236
obj = Objective(f)
3337
sampler = ARSampler(obj, support)
34-
b = @be deepcopy(sampler) sample!(_, 10000, true, 10);
38+
b = @be deepcopy(sampler) sample!(_, 10000, max_segments = 10);
3539
return sampler, b
3640
end
3741
s, b = bench();
3842
b
3943
```
4044

41-
Benchmark: 126 samples with 1 evaluation
42-
min 616.951 μs (17 allocs: 80.523 KiB)
43-
median 641.532 μs (17 allocs: 80.523 KiB)
44-
mean 749.812 μs (17.10 allocs: 80.625 KiB, 0.75% gc time)
45-
max 13.744 ms (20 allocs: 83.711 KiB, 94.06% gc time)
45+
Benchmark: 166 samples with 1 evaluation
46+
min 535.050 μs (3 allocs: 78.195 KiB)
47+
median 565.130 μs (6 allocs: 81.852 KiB)
48+
mean 571.223 μs (5.73 allocs: 81.521 KiB)
49+
max 740.072 μs (6 allocs: 81.852 KiB)
4650

4751
Let's verify the result
4852

@@ -55,15 +59,10 @@ envelop = eval_hull.(s.upper_hull, x)
5559
target = f.(x)
5660
samples = sample!(s, 10000, max_segments = 5)
5761

58-
fig, ax, p = hist(samples, bins=25, normalization = :pdf, label = "Samples");
59-
lines!(ax, -10..10, x -> exp(f(x)), label = "Target", color = :orange)
60-
lines!(ax, x, exp.(envelop), label = "Envelop", color = :black, alpha = 0.8)
61-
absc = ARS.abscissae(s.upper_hull)
62-
scatter!(ax, absc, exp.(eval_hull.(s.upper_hull, absc)), label = "Abscissae", color = :red)
62+
fig, ax, p = hist(samples, bins=25, color = :grey, normalization = :pdf, label = "Samples");
63+
hullplot!(ax, -10..10, s, target = true)
6364
axislegend(ax)
6465
fig
65-
# histogram(sim, normalize = true, label = "Histogram")
66-
# plot!(x, [target envelop], width = 2, label = ["Normal(μ, σ)" "Envelop"])
6766
```
6867

6968

@@ -80,25 +79,16 @@ support = (0.0, Inf)
8079

8180
obj = Objective(x -> log(f(x)))
8281
sam = ARSampler(obj, support)
83-
@time sim = sample!(sam, 10000, max_segments = 5)
82+
sim = sample!(sam, 10000, max_segments = 5)
8483

8584
# Verify result
86-
x = range(0.0, 8.0, length=100)
87-
envelop = eval_hull.(sam.upper_hull, x)
88-
target = f.(x)
8985
mx = maximum(sim)
90-
fig, ax, p = hist(sim, bins=50, normalization = :pdf, label = "Samples");
91-
lines!(ax, 0..mx, y -> f(y), label = "Target", color = :orange)
92-
lines!(ax, 0..mx, y -> exp(eval_hull(sam.upper_hull, y)), label = "Envelop", color = :black, alpha = 0.8)
93-
absc = abscissae(sam.upper_hull)
94-
scatter!(ax, absc, exp.(eval_hull.(sam.upper_hull, absc)), label = "Abscissae", color = :red)
86+
fig, ax, p = hist(sim, bins=50, color = :grey, normalization = :pdf, label = "Samples");
87+
hullplot!(ax, 0..mx, sam, target = true)
9588
axislegend(ax)
9689
fig
9790
```
9891

99-
0.000772 seconds (100 allocations: 85.211 KiB)
100-
101-
10292
![](img/example2.svg)
10393

10494
### Truncated distributions and unknown normalization constant
@@ -111,23 +101,18 @@ We don't to provide an exact density--it will sample up to proportionality--and
111101
f(x) = β^α * x^-1) * exp(-β*x) / gamma(α)
112102
support = (1.0, 3.5)
113103

114-
# Build the sampler and simulate 10,000 samples
115-
sampler = RejectionSampler(f, support)
116-
@time sim = run_sampler!(sampler, 10000)
104+
obj = Objective(x -> log(f(x)))
105+
sam = ARSampler(obj, support)
106+
sim = sample!(sam, 10000, max_segments = 10)
117107

118108
# Plot the results and compare to target distribution
119-
x = range(0.01, 8.0, length=100)
120-
envelop = [eval_envelop(sampler.envelop, xi) for xi in x]
121-
target = [f(xi) for xi in x]
122-
123-
histogram(sim, normalize = true, label = "histogram")
124-
plot!(x, [target envelop], width = 2, label = ["target density" "envelop"])
109+
fig, ax, p = hist(sim, bins=50, color = :grey, normalization = :pdf, label = "Samples");
110+
hullplot!(ax, 0.01..8.0, sam, target = true)
111+
axislegend(ax)
112+
fig
125113
```
126114

127-
0.007766 seconds (181.82 k allocations: 3.024 MiB)
128-
129-
130-
![](img/example3.png)
115+
![](img/example3.svg)
131116

132117
### Elastic Net Distribution
133118

@@ -140,40 +125,22 @@ function f(x, μ, λ1, λ2)
140125
nl = λ1 * abs(δ) + λ2 * δ^2
141126
return exp(-nl)
142127
end
143-
support = (-Inf, Inf)
144128

145-
# Build the sampler and simulate 10,000 samples
146-
μ, λ1, λ2 = 0.0, 2.0, 1.0
147-
sampler = RejectionSampler(x -> f(x, μ, λ1, λ2), support, max_segments = 5)
148-
@time sim = run_sampler!(sampler, 10000);
149-
150-
# Plot the results and compare to target distribution
151-
x = range(-2.3, 2.3, length=100)
152-
envelop = [eval_envelop(sampler.envelop, xi) for xi in x]
153-
target = [f(xi, μ, λ1, λ2) for xi in x]
129+
support = (-Inf, Inf)
130+
mu, L1, L2 = 0.0, 2.0, 1.0
131+
obj = Objective(x -> log(f(x, mu, L1, L2)))
132+
sam = ARSampler(obj, support)
133+
sim = sample!(sam, 10000, max_segments = 10)
154134

155-
histogram(sim, normalize = true, label = "histogram")
156-
plot!(x, [target envelop], width = 2, label = ["target density" "envelop"])
135+
fig, ax, p = hist(sim, bins=50, color = :grey, normalization = :pdf, label = "Samples");
136+
hullplot!(ax, -3..3, sam, target = true)
137+
axislegend(ax)
138+
fig
157139
```
158140

159-
![](img/example4.png)
160-
161-
### Tips for numerical stability, use of logdensity
162-
163-
Here are some tips:
141+
![](img/example4.svg)
164142

165-
- Make sure the logdensity is numerically stable in the domain and avoid logdensity values > 25 (since
166-
the evaluation of the envelop requires exponentials);
167-
- Use log densities instead of densities using the keyword `logdensity=true`;
168-
- Specify a `min_slope` and `max_slope` to find better initial points. The default is 1e-6 and 1e6, respectively.
169-
The `min_slope` is the minimum slope of the logdensity in the initial points of the envelop in absolute value. In general,
170-
it is a good idea to leave `min_slope` with the default and try `max_slope=10.0` or a smaller number.
171-
- Try setting `δ` to a smaller value in the search_grid. The default is 0.5.
172-
173-
174-
⚠️ *Warning* ⚠️: Using `logdensity=true` will be the default in v1.0.
175-
176-
Here is an example
143+
#### Example of more complicated density
177144

178145
```julia
179146
import StatsFuns: logsumexp
@@ -185,36 +152,28 @@ theta = 1.0
185152

186153
# a complicated logdensity
187154
logf(v) = n * v - (n - k * alpha) * logsumexp([v, log(tau)]) - theta / alpha * ( (tau + exp(v) )^alpha )
155+
f(x) = exp(logf(x))
188156

189157
# run sampler
190158
δ = 0.1
191159
support = (-Inf, Inf)
192160
search = (0.0, 10.0)
193-
sampler = RejectionSampler(logf, support, δ, max_segments=10, logdensity=true, search_range=search, max_slope=10.0)
194-
@time sim = run_sampler!(sampler, 10000)
195-
```
161+
obj = Objective(logf)
162+
sam = ARSampler(obj, support, search)
163+
sim = sample!(sam, 10000, max_segments = 10)
196164

197-
```
198-
[ Info: initial points found at 1.08, 5.43 with grads 9.94522619043481, -9.98968199019509
199-
0.016296 seconds (371.21 k allocations: 6.850 MiB)
200-
```
201-
202-
203-
```julia
204165
x = range(0, 10, length=200)
205166
normconst = sum(f.(x)) * (x[2] - x[1])
206-
envelop = [eval_envelop(sampler.envelop, xi) for xi in x] ./ normconst
207-
target = [f(xi) for xi in x] ./ normconst
208-
209-
# make two plots of logf and f
210-
p1 = plot(logf, -20, 20, label = "logf")
211-
p2 = histogram(sim, normalize=true, label="histogram")
212-
plot!(p2, x, [target envelop], width=2, label=["target density" "envelop"])
213167

214-
plot(p1, p2, layout = (1, 2))
168+
fig, ax, p = lines(-20..20, logf);
169+
ax2 = Axis(fig[1,2])
170+
hist!(ax2, sim, bins=50, color = :grey, normalization = :pdf, label = "Samples")
171+
hullplot!(ax2, 0..10, sam, target = true, normconst = 1 / normconst)
172+
axislegend(ax2)
173+
fig
215174
```
216175

217-
![](img/example5.png)
176+
![](img/example5.svg)
218177

219178
## Citation
220179

@@ -223,7 +182,7 @@ plot(p1, p2, layout = (1, 2))
223182
```bibtex
224183
@manual{tec2018ars,
225184
title = {AdaptiveRejectionSampling.jl},
226-
author = {Mauricio Tec},
185+
author = {Mauricio Tec, Elias Sjölin},
227186
year = {2018},
228187
url = {https://github.com/mauriciogtec/AdaptiveRejectionSampling.jl}
229188
}

0 commit comments

Comments
 (0)