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 -2.3564 21.5424 5.2915 85.2672 11.6371 1.0104 ⋯
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.2279 0.7764 0.0459 289.3536 326.5058 1.0117 ⋯
a 0.0818 0.8130 0.0458 318.6189 314.8640 0.9992 ⋯
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.1964 0.7793 0.0460 286.8711 325.3525 1.0070 ⋯
a 0.1261 0.7743 0.0456 289.7106 312.8636 1.0145 ⋯
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.