@@ -191,6 +191,31 @@ function AbstractMCMC.step(
191
191
return transition, transition
192
192
end
193
193
194
+ """
195
+ is_symmetric_proposal(proposal)::Bool
196
+
197
+ Implementing this for a custom proposal will allow `AbstractMCMC.step` to avoid
198
+ computing the "Hastings" part of the Metropolis-Hasting log acceptance
199
+ probability (if the proposal is indeed symmetric). By default,
200
+ `is_symmetric_proposal(proposal)` returns `false`. The user is responsible for
201
+ determining whether a custom proposal distribution is indeed symmetric. As
202
+ noted in `MetropolisHastings`, `proposal` is a `Proposal`, `NamedTuple` of
203
+ `Proposal`, or `Array{Proposal}` in the shape of your data.
204
+ """
205
+ is_symmetric_proposal (proposal) = false
206
+
207
+ # The following univariate random walk proposals are symmetric.
208
+ is_symmetric_proposal (:: RandomWalkProposal{<:Normal} ) = true
209
+ is_symmetric_proposal (:: RandomWalkProposal{<:MvNormal} ) = true
210
+ is_symmetric_proposal (:: RandomWalkProposal{<:TDist} ) = true
211
+ is_symmetric_proposal (:: RandomWalkProposal{<:Cauchy} ) = true
212
+
213
+ # The following multivariate random walk proposals are symmetric.
214
+ is_symmetric_proposal (:: RandomWalkProposal{<:AbstractArray{<:Normal}} ) = true
215
+ is_symmetric_proposal (:: RandomWalkProposal{<:AbstractArray{<:MvNormal}} ) = true
216
+ is_symmetric_proposal (:: RandomWalkProposal{<:AbstractArray{<:TDist}} ) = true
217
+ is_symmetric_proposal (:: RandomWalkProposal{<:AbstractArray{<:Cauchy}} ) = true
218
+
194
219
# Define the other sampling steps.
195
220
# Return a 2-tuple consisting of the next sample and the the next state.
196
221
# In this case they are identical, and either a new proposal (if accepted)
@@ -206,8 +231,12 @@ function AbstractMCMC.step(
206
231
params = propose (rng, spl, model, params_prev)
207
232
208
233
# Calculate the log acceptance probability.
209
- logα = logdensity (model, params) - logdensity (model, params_prev) +
210
- q (spl, params_prev, params) - q (spl, params, params_prev)
234
+ logα = logdensity (model, params) - logdensity (model, params_prev)
235
+
236
+ # Compute Hastings portion of ratio if proposal is not symmetric.
237
+ if ! is_symmetric_proposal (spl. proposal)
238
+ logα += q (spl, params_prev, params) - q (spl, params, params_prev)
239
+ end
211
240
212
241
# Decide whether to return the previous params or the new one.
213
242
if - Random. randexp (rng) < logα
0 commit comments