Skip to content

Commit

Permalink
more flexible proposal options
Browse files Browse the repository at this point in the history
  • Loading branch information
itsdfish committed Aug 30, 2020
1 parent 74fa57a commit f27f4df
Show file tree
Hide file tree
Showing 2 changed files with 64 additions and 11 deletions.
66 changes: 58 additions & 8 deletions src/crossover.jl
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ Performs crossover step for each particle pt in the chain
function crossover!(model, de, group)
for pt in group
# generate the proposal
proposal = generate_proposal(de, pt, group)
proposal = de.generate_proposal(de, pt, group)
# compute the weight of the proposal: prior loglikelihood + data loglikelihood
compute_posterior!(de, model, proposal)
# accept proposal according to Metropolis-Hastings rule
Expand All @@ -22,8 +22,7 @@ Generate proposal according to θ' = θt + γ1(θm − θn) + γ2(θb − θt) +
* `Pt`: current particle
* `group`: a group of particles
"""
# 2.38/sqrt(2d)
function generate_proposal(de, Pt, group)
function random_gamma(de, Pt, group)
Np = length(Pt.Θ)
# select the base particle θb
Pb = select_base(group)
Expand All @@ -34,7 +33,7 @@ function generate_proposal(de, Pt, group)
# sample gamma weights
γ₁ = rand(Uniform(.5, 1))
# set γ₂ = 0 after burnin
de.iter > de.burnin ? γ₂ = 0.0 : γ₂ = rand(Uniform(.5, 1))
γ₂ = de.iter > de.burnin ? 0.0 : rand(Uniform(.5, 1))
# sample noise for each parameter
b = Uniform(-de.ϵ, de.ϵ)
# compute proposal value
Expand All @@ -44,15 +43,66 @@ function generate_proposal(de, Pt, group)
return Θp
end

"""
Generate proposal according to θ' = θt + γ(θm − θn) + b
where γ = 2.38
* `de`: differential evolution object
* `Pt`: current particle
* `group`: a group of particles
"""
function fixed_gamma(de, Pt, group)
Np = length(Pt.Θ)
# select the base particle θb
Pb = select_base(group)
# group without Pb
group_diff = setdiff(group, [Pt])
# sample particles for θm and θn
Pm,Pn = sample(group_diff, 2, replace=false)
# sample gamma weights
γ = 2.38
# sample noise for each parameter
b = Uniform(-de.ϵ, de.ϵ)
# compute proposal value
Θp = Pt + γ * (Pm - Pn) + b
# reset each parameter to previous value with probability (1-κ)
recombination!(de, Pt, Θp)
return Θp
end

"""
Generate proposal according to θ' = θt + γ(θm − θn) + b
where γ = 2.38/√(2d) where d is the number of parameters
* `de`: differential evolution object
* `Pt`: current particle
* `group`: a group of particles
"""
function variable_gamma(de, Pt, group)
Np = length(Pt.Θ)
# select the base particle θb
Pb = select_base(group)
# group without Pb
group_diff = setdiff(group, [Pt])
# sample particles for θm and θn
Pm,Pn = sample(group_diff, 2, replace=false)
γ = 2.38 / sqrt(2 * Np)
# sample noise for each parameter
b = Uniform(-de.ϵ, de.ϵ)
# compute proposal value
Θp = Pt + γ * (Pm - Pn) + b
# reset each parameter to previous value with probability (1-κ)
recombination!(de, Pt, Θp)
return Θp
end

"""
Selects base particle θb with probability proportional to weight
* `group`: a group of particles
"""
function select_base(group)
function select_base(group)
w = map(x -> x.weight, group)
θ = exp.(w) / sum(exp.(w))
p = sample(group, Weights(θ))
return p
return p
end

"""
Expand All @@ -72,7 +122,7 @@ function recombination!(de, pt, pp)
rand() <= (1 - de.κ) ? pp.Θ[i] = pt.Θ[i] : nothing
end
end
return nothing
return nothing
end

# Handles elements within an array
Expand All @@ -81,5 +131,5 @@ function recombination!(de, pt, pp, idx)
for i in 1:N
rand() <= (1 - de.κ) ? pp.Θ[idx][i] = pt.Θ[idx][i] : nothing
end
return nothing
return nothing
end
9 changes: 6 additions & 3 deletions src/structs.jl
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ Differential Evolution MCMC object
* `κ`: recombination with probability (1-κ) during crossover. Default = 1.0
* `bounds`: a vector of tuples for lower and upper bounds of each parameter
* `iter`: current iteration
* `generate_proposal`: a function that generates proposals. Default is the two mode proposal described in
Turner et al. 2012. You can also choose fixed_gamma, variable_gamma (see help) or pass a custom function
Constructor signature:
Expand All @@ -26,7 +28,7 @@ References:
* Turner, B. M., & Sederberg, P. B. (2012). Approximate Bayesian computation with differential evolution. Journal of Mathematical Psychology, 56(5), 375-385.
"""
mutable struct DE{T1} <: AbstractSampler
mutable struct DE{T1,F <: Function} <: AbstractSampler
n_groups::Int64
Np::Int64
burnin::Int64
Expand All @@ -37,15 +39,16 @@ mutable struct DE{T1} <: AbstractSampler
κ::Float64
bounds::T1
iter::Int64
generate_proposal::F
end

function DE(;n_groups=4, priors=nothing, Np=num_parms(priors) * 3, burnin=1000, α=.1, β=.1, ϵ=.001,
σ=.05, κ=1.0, bounds)
σ=.05, κ=1.0, bounds, generate_proposal=random_gamma)
if> 0) && (n_groups == 1)
α = 0.0
@warn "migration probability α > 0 but n_groups == 1. Changing α = 0.0"
end
return DE(n_groups, Np, burnin, α, β, ϵ, σ, κ, bounds, 1)
return DE(n_groups, Np, burnin, α, β, ϵ, σ, κ, bounds, 1, generate_proposal)
end

"""
Expand Down

0 comments on commit f27f4df

Please sign in to comment.