Slice Sampling
SliceSampling.jl provides a family of derivative-free slice samplers. Once using SliceSampling, they can sample any compiled BUGSModel, so you get gradient-free inference without configuring an AD backend. This is handy for models with awkward geometry, non-differentiable pieces, or as a robust component sampler inside JuliaBUGS.Gibbs.
Slice samplers are used two ways:
- Standalone — pass a slice sampler to
AbstractMCMC.sampleto update the whole model. - Inside
JuliaBUGS.Gibbs— assign a slice sampler to one or more variable groups in thesampler_map; JuliaBUGS drives it through the Gibbs sweep.
Setup
using JuliaBUGS
using JuliaBUGS: Gibbs
using SliceSampling
using AbstractMCMC
using MCMCChains
using OrderedCollections: OrderedDict
model_def = @bugs begin
mu ~ dnorm(0, 0.0001)
y ~ dnorm(mu, 1)
end
model = model_def((; y = 1.5))BUGSModel (parameters are in transformed (unconstrained) space, with dimension 1):
Model parameters:
mu
Variable sizes and types:
y: type = Float64
mu: type = Float64
Standalone sampling
Univariate slice samplers such as SliceSteppingOut and SliceDoublingOut update one coordinate at a time. On a single-parameter model you can pass one directly:
chain = AbstractMCMC.sample(
model,
SliceSteppingOut(1.0), # 1.0 is the initial slice window width
500;
chain_type = Chains,
progress = false,
)
summarystats(chain)Summary Statistics
parameters mean std mcse ess_bulk ess_tail rhat e ⋯
Symbol Float64 Float64 Float64 Real Float64 Float64 ⋯
mu 1.2498 2.8127 0.2015 348.6235 210.6334 1.0010 ⋯
1 column omitted
No initial_params is required: the extension implements SliceSampling.initial_sample, which seeds the sampler from the model's current parameter values.
For a model with more than one parameter, wrap a univariate sampler in a multivariate strategy (e.g. RandPermGibbs, which cycles through coordinates in a random order), or use a genuinely multivariate slice sampler:
multi_def = @bugs begin
a ~ dnorm(0, 1)
b ~ dnorm(0, 1)
y ~ dnorm(a + b, 1)
end
multi_model = multi_def((; y = 0.5))
multi_chain = AbstractMCMC.sample(
multi_model,
RandPermGibbs(SliceSteppingOut(1.0)),
500;
chain_type = Chains,
progress = false,
)
summarystats(multi_chain)Summary Statistics
parameters mean std mcse ess_bulk ess_tail rhat e ⋯
Symbol Float64 Float64 Float64 Real Float64 Float64 ⋯
b 0.2273 0.7661 0.0418 335.7381 343.2729 1.0010 ⋯
a 0.1199 0.7923 0.0440 340.1794 327.9930 0.9993 ⋯
1 column omitted
Inside Gibbs
Because each single-site conditional in JuliaBUGS.Gibbs is univariate, a bare univariate slice sampler works per site — no multivariate wrapper needed. Map variable groups to samplers in an OrderedDict:
sampler_map = OrderedDict(
@varname(a) => SliceSteppingOut(1.0),
@varname(b) => SliceSteppingOut(1.0),
)
gibbs = Gibbs(multi_model, sampler_map)
gibbs_chain = AbstractMCMC.sample(
multi_model,
gibbs,
500;
chain_type = Chains,
progress = false,
)
summarystats(gibbs_chain)Summary Statistics
parameters mean std mcse ess_bulk ess_tail rhat e ⋯
Symbol Float64 Float64 Float64 Real Float64 Float64 ⋯
b 0.0438 0.8810 0.0517 288.6005 307.2861 1.0038 ⋯
a 0.2451 0.8613 0.0522 270.9563 315.5853 0.9986 ⋯
1 column omitted
Slice samplers can be freely mixed with other samplers (HMC, IndependentMH, …) in the same sampler_map.
Output formats and statistics
Both chain backends are supported:
chain_type = Chainsreturns anMCMCChains.Chains(shown above).chain_type = VNChainreturns aFlexiChains.FlexiChainkeyed byVarName(requiresusing FlexiChains):
using FlexiChains
chain = AbstractMCMC.sample(model, SliceSteppingOut(1.0), 500; chain_type = VNChain, progress = false)In either case the sampler's own statistics are recorded alongside the draws: the log density lp and num_proposals (the number of proposals the slice sampler evaluated per step). Under MCMCChains these appear as internals; under FlexiChains they are FlexiChains.Extra entries. For a multivariate sampler the per-coordinate num_proposals is flattened into num_proposals[i] columns for MCMCChains.