diff --git a/index.html b/index.html index 3ac2596..6a5afc3 100644 --- a/index.html +++ b/index.html @@ -1,3 +1,2 @@ - diff --git a/previews/PR150/.documenter-siteinfo.json b/previews/PR150/.documenter-siteinfo.json index 743a8d2..796de29 100644 --- a/previews/PR150/.documenter-siteinfo.json +++ b/previews/PR150/.documenter-siteinfo.json @@ -1 +1 @@ -{"documenter":{"julia_version":"1.11.1","generation_timestamp":"2024-10-27T10:50:04","documenter_version":"1.7.0"}} \ No newline at end of file +{"documenter":{"julia_version":"1.11.1","generation_timestamp":"2024-10-27T10:52:00","documenter_version":"1.7.0"}} \ No newline at end of file diff --git a/previews/PR150/api/index.html b/previews/PR150/api/index.html index 3826c4d..9450323 100644 --- a/previews/PR150/api/index.html +++ b/previews/PR150/api/index.html @@ -1,475 +1,17 @@ -API · AbstractMCMC - - - - - -

API

AbstractMCMC defines an interface for sampling Markov chains.

Model

AbstractMCMC.LogDensityModelType
LogDensityModel <: AbstractMCMC.AbstractModel

Wrapper around something that implements the LogDensityProblem.jl interface.

Note that this does not implement the LogDensityProblems.jl interface itself, but it simply useful for indicating to the sample and other AbstractMCMC methods that the wrapped object implements the LogDensityProblems.jl interface.

Fields

  • logdensity: The object that implements the LogDensityProblems.jl interface.
source

Sampler

AbstractMCMC.AbstractSamplerType
AbstractSampler

The AbstractSampler type is intended to be inherited from when implementing a custom sampler. Any persistent state information should be saved in a subtype of AbstractSampler.

When defining a new sampler, you should also overload the function transition_type, which tells the sample function what type of parameter it should expect to receive.

source

Sampling a single chain

StatsBase.sampleMethod
sample(
+API · AbstractMCMC

API

AbstractMCMC defines an interface for sampling Markov chains.

Model

AbstractMCMC.LogDensityModelType
LogDensityModel <: AbstractMCMC.AbstractModel

Wrapper around something that implements the LogDensityProblem.jl interface.

Note that this does not implement the LogDensityProblems.jl interface itself, but it simply useful for indicating to the sample and other AbstractMCMC methods that the wrapped object implements the LogDensityProblems.jl interface.

Fields

  • logdensity: The object that implements the LogDensityProblems.jl interface.
source

Sampler

AbstractMCMC.AbstractSamplerType
AbstractSampler

The AbstractSampler type is intended to be inherited from when implementing a custom sampler. Any persistent state information should be saved in a subtype of AbstractSampler.

When defining a new sampler, you should also overload the function transition_type, which tells the sample function what type of parameter it should expect to receive.

source

Sampling a single chain

StatsBase.sampleMethod
sample(
     rng::Random.AbatractRNG=Random.default_rng(),
     model::AbstractModel,
     sampler::AbstractSampler,
     N_or_isdone;
     kwargs...,
-)

Sample from the model with the Markov chain Monte Carlo sampler and return the samples.

If N_or_isdone is an Integer, exactly N_or_isdone samples are returned.

Otherwise, sampling is performed until a convergence criterion N_or_isdone returns true. The convergence criterion has to be a function with the signature

isdone(rng, model, sampler, samples, state, iteration; kwargs...)

where state and iteration are the current state and iteration of the sampler, respectively. It should return true when sampling should end, and false otherwise.

Keyword arguments

See https://turinglang.org/AbstractMCMC.jl/dev/api/#Common-keyword-arguments for common keyword arguments.

source
StatsBase.sampleMethod
sample(
+)

Sample from the model with the Markov chain Monte Carlo sampler and return the samples.

If N_or_isdone is an Integer, exactly N_or_isdone samples are returned.

Otherwise, sampling is performed until a convergence criterion N_or_isdone returns true. The convergence criterion has to be a function with the signature

isdone(rng, model, sampler, samples, state, iteration; kwargs...)

where state and iteration are the current state and iteration of the sampler, respectively. It should return true when sampling should end, and false otherwise.

Keyword arguments

See https://turinglang.org/AbstractMCMC.jl/dev/api/#Common-keyword-arguments for common keyword arguments.

source
StatsBase.sampleMethod
sample(
     rng::Random.AbstractRNG=Random.default_rng(),
     logdensity,
     sampler::AbstractSampler,
     N_or_isdone;
     kwargs...,
-)

Wrap the logdensity function in a LogDensityModel, and call sample with the resulting model instead of logdensity.

The logdensity function has to support the LogDensityProblems.jl interface.

source

Iterator

Iterator

AbstractMCMC.stepsMethod
steps(
     rng::Random.AbstractRNG=Random.default_rng(),
     model::AbstractModel,
     sampler::AbstractSampler;
@@ -486,12 +28,12 @@
 julia> iterator = steps(MyModel(), MySampler());
 
 julia> collect(Iterators.take(iterator, 10)) == zeros(10)
-true
source
AbstractMCMC.stepsMethod
steps(
     rng::Random.AbstractRNG=Random.default_rng(),
     logdensity,
     sampler::AbstractSampler;
     kwargs...,
-)

Wrap the logdensity function in a LogDensityModel, and call steps with the resulting model instead of logdensity.

The logdensity function has to support the LogDensityProblems.jl interface.

source

Transducer

Transducer

AbstractMCMC.SampleMethod
Sample(
     rng::Random.AbstractRNG=Random.default_rng(),
     model::AbstractModel,
     sampler::AbstractSampler;
@@ -508,12 +50,12 @@
 julia> transducer = Sample(MyModel(), MySampler());
 
 julia> collect(transducer(1:10)) == zeros(10)
-true
source
AbstractMCMC.SampleMethod
Sample(
     rng::Random.AbstractRNG=Random.default_rng(),
     logdensity,
     sampler::AbstractSampler;
     kwargs...,
-)

Wrap the logdensity function in a LogDensityModel, and call Sample with the resulting model instead of logdensity.

The logdensity function has to support the LogDensityProblems.jl interface.

source

Sampling multiple chains in parallel

Sampling multiple chains in parallel

StatsBase.sampleMethod
sample(
     rng::Random.AbstractRNG=Random.default_rng(),
     model::AbstractModel,
     sampler::AbstractSampler,
@@ -521,7 +63,7 @@
     N::Integer,
     nchains::Integer;
     kwargs...,
-)

Sample nchains Monte Carlo Markov chains from the model with the sampler in parallel using the parallel algorithm, and combine them into a single chain.

Keyword arguments

See https://turinglang.org/AbstractMCMC.jl/dev/api/#Common-keyword-arguments for common keyword arguments.

source
StatsBase.sampleMethod
sample(
+)

Sample nchains Monte Carlo Markov chains from the model with the sampler in parallel using the parallel algorithm, and combine them into a single chain.

Keyword arguments

See https://turinglang.org/AbstractMCMC.jl/dev/api/#Common-keyword-arguments for common keyword arguments.

source
StatsBase.sampleMethod
sample(
     rng::Random.AbstractRNG=Random.default_rng(),
     logdensity,
     sampler::AbstractSampler,
@@ -529,7 +71,7 @@
     N::Integer,
     nchains::Integer;
     kwargs...,
-)

Wrap the logdensity function in a LogDensityModel, and call sample with the resulting model instead of logdensity.

The logdensity function has to support the LogDensityProblems.jl interface.

source

Two algorithms are provided for parallel sampling with multiple threads and multiple processes, and one allows for the user to sample multiple chains in serial (no parallelization):

Common keyword arguments

Common keyword arguments for regular and parallel sampling are:

  • progress (default: AbstractMCMC.PROGRESS[] which is true initially): toggles progress logging
  • chain_type (default: Any): determines the type of the returned chain
  • callback (default: nothing): if callback !== nothing, then callback(rng, model, sampler, sample, iteration) is called after every sampling step, where sample is the most recent sample of the Markov chain and iteration is the current iteration
  • num_warmup (default: 0): number of "warm-up" steps to take before the first "regular" step, i.e. number of times to call AbstractMCMC.step_warmup before the first call to AbstractMCMC.step.
  • discard_initial (default: num_warmup): number of initial samples that are discarded. Note that if discard_initial < num_warmup, warm-up samples will also be included in the resulting samples.
  • thinning (default: 1): factor by which to thin samples.
  • initial_state (default: nothing): if initial_state !== nothing, the first call to AbstractMCMC.step is passed initial_state as the state argument.
Info

The common keyword arguments progress, chain_type, and callback are not supported by the iterator AbstractMCMC.steps and the transducer AbstractMCMC.Sample.

There is no "official" way for providing initial parameter values yet. However, multiple packages such as EllipticalSliceSampling.jl and AdvancedMH.jl support an initial_params keyword argument for setting the initial values when sampling a single chain. To ensure that sampling multiple chains "just works" when sampling of a single chain is implemented, we decided to support initial_params in the default implementations of the ensemble methods:

  • initial_params (default: nothing): if initial_params isa AbstractArray, then the ith element of initial_params is used as initial parameters of the ith chain. If one wants to use the same initial parameters x for every chain, one can specify e.g. initial_params = FillArrays.Fill(x, N).

Progress logging can be enabled and disabled globally with AbstractMCMC.setprogress!(progress).

AbstractMCMC.setprogress!Function
setprogress!(progress::Bool; silent::Bool=false)

Enable progress logging globally if progress is true, and disable it otherwise. Optionally disable informational message if silent is true.

source

Chains

The chain_type keyword argument allows to set the type of the returned chain. A common choice is to return chains of type Chains from MCMCChains.jl.

AbstractMCMC defines the abstract type AbstractChains for Markov chains.

AbstractMCMC.AbstractChainsType
AbstractChains

AbstractChains is an abstract type for an object that stores parameter samples generated through a MCMC process.

source

For chains of this type, AbstractMCMC defines the following two methods.

AbstractMCMC.chainscatFunction
chainscat(c::AbstractChains...)

Concatenate multiple chains.

By default, the chains are concatenated along the third dimension by calling cat(c...; dims=3).

source
AbstractMCMC.chainsstackFunction
chainsstack(c::AbstractVector)

Stack chains in c.

By default, the vector of chains is returned unmodified. If eltype(c) <: AbstractChains, then reduce(chainscat, c) is called.

source

Interacting with states of samplers

To make it a bit easier to interact with some arbitrary sampler state, we encourage implementations of AbstractSampler to implement the following methods:

AbstractMCMC.getparamsFunction
getparams([model::AbstractModel, ]state)

Retrieve the values of parameters from the sampler's state as a Vector{<:Real}.

source
AbstractMCMC.setparams!!Function
setparams!!([model::AbstractModel, ]state, params)

Set the values of parameters in the sampler's state from a Vector{<:Real}.

This function should follow the BangBang interface: mutate state in-place if possible and return the mutated state. Otherwise, it should return a new state containing the updated parameters.

Although not enforced, it should hold that setparams!!(state, getparams(state)) == state. In other words, the sampler should implement a consistent transformation between its internal representation and the vector representation of the parameter values.

Sometimes, to maintain the consistency of the log density and parameter values, a model should be provided. This is useful for samplers that need to evaluate the log density at the new parameter values.

source

getparams and setparams!! provide a generic interface for interacting with the parameters of a sampler's state, regardless of how that state is represented internally. If the model argument is not provided, the functions will be dispatched to the implementations without the model argument.

This allows generic code to be written that works with any sampler implementing this interface. For example, a generic ensemble sampler could use getparams to extract the parameters from each of its component samplers' states, and setparams!! to initialize each component sampler with a different set of parameters.

The optional model argument to these functions allows sampler implementations to customize their behavior based on the model being used. This is useful for samplers that need to access or modify the model in order to extract or set the parameters.

These methods are particularly useful for implementing samplers which wrap some inner samplers, such as a mixture of samplers. In the next section, we will see how getparams and setparams!! can be used to implement a MixtureSampler.

Example: MixtureSampler

In a MixtureSampler we need two things:

  • components: collection of samplers.
  • weights: collection of weights representing the probability of choosing the corresponding sampler.
struct MixtureSampler{W,C} <: AbstractMCMC.AbstractSampler
+)

Wrap the logdensity function in a LogDensityModel, and call sample with the resulting model instead of logdensity.

The logdensity function has to support the LogDensityProblems.jl interface.

source

Two algorithms are provided for parallel sampling with multiple threads and multiple processes, and one allows for the user to sample multiple chains in serial (no parallelization):

Common keyword arguments

Common keyword arguments for regular and parallel sampling are:

  • progress (default: AbstractMCMC.PROGRESS[] which is true initially): toggles progress logging
  • chain_type (default: Any): determines the type of the returned chain
  • callback (default: nothing): if callback !== nothing, then callback(rng, model, sampler, sample, iteration) is called after every sampling step, where sample is the most recent sample of the Markov chain and iteration is the current iteration
  • num_warmup (default: 0): number of "warm-up" steps to take before the first "regular" step, i.e. number of times to call AbstractMCMC.step_warmup before the first call to AbstractMCMC.step.
  • discard_initial (default: num_warmup): number of initial samples that are discarded. Note that if discard_initial < num_warmup, warm-up samples will also be included in the resulting samples.
  • thinning (default: 1): factor by which to thin samples.
  • initial_state (default: nothing): if initial_state !== nothing, the first call to AbstractMCMC.step is passed initial_state as the state argument.
Info

The common keyword arguments progress, chain_type, and callback are not supported by the iterator AbstractMCMC.steps and the transducer AbstractMCMC.Sample.

There is no "official" way for providing initial parameter values yet. However, multiple packages such as EllipticalSliceSampling.jl and AdvancedMH.jl support an initial_params keyword argument for setting the initial values when sampling a single chain. To ensure that sampling multiple chains "just works" when sampling of a single chain is implemented, we decided to support initial_params in the default implementations of the ensemble methods:

  • initial_params (default: nothing): if initial_params isa AbstractArray, then the ith element of initial_params is used as initial parameters of the ith chain. If one wants to use the same initial parameters x for every chain, one can specify e.g. initial_params = FillArrays.Fill(x, N).

Progress logging can be enabled and disabled globally with AbstractMCMC.setprogress!(progress).

AbstractMCMC.setprogress!Function
setprogress!(progress::Bool; silent::Bool=false)

Enable progress logging globally if progress is true, and disable it otherwise. Optionally disable informational message if silent is true.

source

Chains

The chain_type keyword argument allows to set the type of the returned chain. A common choice is to return chains of type Chains from MCMCChains.jl.

AbstractMCMC defines the abstract type AbstractChains for Markov chains.

AbstractMCMC.AbstractChainsType
AbstractChains

AbstractChains is an abstract type for an object that stores parameter samples generated through a MCMC process.

source

For chains of this type, AbstractMCMC defines the following two methods.

AbstractMCMC.chainscatFunction
chainscat(c::AbstractChains...)

Concatenate multiple chains.

By default, the chains are concatenated along the third dimension by calling cat(c...; dims=3).

source
AbstractMCMC.chainsstackFunction
chainsstack(c::AbstractVector)

Stack chains in c.

By default, the vector of chains is returned unmodified. If eltype(c) <: AbstractChains, then reduce(chainscat, c) is called.

source

Interacting with states of samplers

To make it a bit easier to interact with some arbitrary sampler state, we encourage implementations of AbstractSampler to implement the following methods:

AbstractMCMC.getparamsFunction
getparams([model::AbstractModel, ]state)

Retrieve the values of parameters from the sampler's state as a Vector{<:Real}.

source
AbstractMCMC.setparams!!Function
setparams!!([model::AbstractModel, ]state, params)

Set the values of parameters in the sampler's state from a Vector{<:Real}.

This function should follow the BangBang interface: mutate state in-place if possible and return the mutated state. Otherwise, it should return a new state containing the updated parameters.

Although not enforced, it should hold that setparams!!(state, getparams(state)) == state. In other words, the sampler should implement a consistent transformation between its internal representation and the vector representation of the parameter values.

Sometimes, to maintain the consistency of the log density and parameter values, a model should be provided. This is useful for samplers that need to evaluate the log density at the new parameter values.

source

getparams and setparams!! provide a generic interface for interacting with the parameters of a sampler's state, regardless of how that state is represented internally.

This allows generic code to be written that works with any sampler implementing this interface. For example, a generic ensemble sampler could use getparams to extract the parameters from each of its component samplers' states, and setparams!! to initialize each component sampler with a different set of parameters.

The optional model argument to these functions allows sampler implementations to customize their behavior based on the model being used. For example, some samplers may need to evaluate the log density at new parameter values when setting parameters, which requires access to the model. If access to model is not needed, the sampler only needs to implement the version without the model argument - the default implementations will then call those methods directly.

These methods are particularly useful for implementing samplers which wrap some inner samplers, such as a mixture of samplers. In the next section, we will see how getparams and setparams!! can be used to implement a MixtureSampler.

Example: MixtureSampler

In a MixtureSampler we need two things:

  • components: collection of samplers.
  • weights: collection of weights representing the probability of choosing the corresponding sampler.
struct MixtureSampler{W,C} <: AbstractMCMC.AbstractSampler
     components::C
     weights::W
 end

To implement the state, we need to keep track of a couple of things:

  • index: the index of the sampler used in this step.
  • states: the current states of all the components.

We need to keep track of the states of all components rather than just the state for the sampler we used previously. The reason is that lots of samplers keep track of more than just the previous realizations of the variables, e.g. in AdvancedHMC.jl we keep track of the momentum used, the metric used, etc.

struct MixtureState{S}
@@ -607,5 +149,4 @@
 transition, state = AbstractMCMC.step(rng, model, sampler)
 while ...
     transition, state = AbstractMCMC.step(rng, model, sampler, state)
-end
- +end diff --git a/previews/PR150/design/index.html b/previews/PR150/design/index.html index cc0ca86..7d04722 100644 --- a/previews/PR150/design/index.html +++ b/previews/PR150/design/index.html @@ -1,463 +1,5 @@ -Design · AbstractMCMC - - - - - -

Design

This page explains the default implementations and design choices of AbstractMCMC. It is not intended for users but for developers that want to implement the AbstractMCMC interface for Markov chain Monte Carlo sampling. The user-facing API is explained in API.

Overview

AbstractMCMC provides a default implementation of the user-facing interface described in API. You can completely neglect these and define your own implementation of the interface. However, as described below, in most use cases the default implementation allows you to obtain support of parallel sampling, progress logging, callbacks, iterators, and transducers for free by just defining the sampling step of your inference algorithm, drastically reducing the amount of code you have to write. In general, the docstrings of the functions described below might be helpful if you intend to make use of the default implementations.

Basic structure

The simplified structure for regular sampling (the actual implementation contains some additional error checks and support for progress logging and callbacks) is

StatsBase.sample(
+Design · AbstractMCMC

Design

This page explains the default implementations and design choices of AbstractMCMC. It is not intended for users but for developers that want to implement the AbstractMCMC interface for Markov chain Monte Carlo sampling. The user-facing API is explained in API.

Overview

AbstractMCMC provides a default implementation of the user-facing interface described in API. You can completely neglect these and define your own implementation of the interface. However, as described below, in most use cases the default implementation allows you to obtain support of parallel sampling, progress logging, callbacks, iterators, and transducers for free by just defining the sampling step of your inference algorithm, drastically reducing the amount of code you have to write. In general, the docstrings of the functions described below might be helpful if you intend to make use of the default implementations.

Basic structure

The simplified structure for regular sampling (the actual implementation contains some additional error checks and support for progress logging and callbacks) is

StatsBase.sample(
     rng::Random.AbstractRNG,
     model::AbstractMCMC.AbstractModel,
     sampler::AbstractMCMC.AbstractSampler,
@@ -482,5 +24,4 @@
     end
 
     return AbstractMCMC.bundle_samples(samples, model, sampler, state, chain_type; kwargs...)
-end

All other default implementations make use of the same structure and in particular call the same methods.

Sampling step

The only method for which no default implementation is provided (and hence which downstream packages have to implement) is AbstractMCMC.step. It defines the sampling step of the inference method.

AbstractMCMC.stepFunction
step(rng, model, sampler[, state; kwargs...])

Return a 2-tuple of the next sample and the next state of the MCMC sampler for model.

Samples describe the results of a single step of the sampler. As an example, a sample might include a vector of parameters sampled from a prior distribution.

When sampling using sample, every step call after the first has access to the current state of the sampler.

source

If one also has some special handling of the warmup-stage of sampling, then this can be specified by overloading

AbstractMCMC.step_warmupFunction
step_warmup(rng, model, sampler[, state; kwargs...])

Return a 2-tuple of the next sample and the next state of the MCMC sampler for model.

When sampling using sample, this takes the place of AbstractMCMC.step in the first num_warmup number of iterations, as specified by the num_warmup keyword to sample. This is useful if the sampler has an initial "warmup"-stage that is different from the standard iteration.

By default, this simply calls AbstractMCMC.step.

source

which will be used for the first num_warmup iterations, as specified as a keyword argument to AbstractMCMC.sample. Note that this is optional; by default it simply calls AbstractMCMC.step from above.

Collecting samples

Note

This section does not apply to the iterator and transducer interface.

After the initial sample is obtained, the default implementations for regular and parallel sampling (not for the iterator and the transducer since it is not needed there) create a container for all samples (the initial one and all subsequent samples) using AbstractMCMC.samples.

AbstractMCMC.samplesFunction
samples(sample, model, sampler[, N; kwargs...])

Generate a container for the samples of the MCMC sampler for the model, whose first sample is sample.

The method can be called with and without a predefined number N of samples.

source

In each step, the sample is saved in the container by AbstractMCMC.save!!. The notation !! follows the convention of the package BangBang.jl which is used in the default implementation of AbstractMCMC.save!!. It indicates that the sample is pushed to the container but a "widening" fallback is used if the container type does not allow to save the sample. Therefore AbstractMCMC.save!! always has to return the container.

AbstractMCMC.save!!Function
save!!(samples, sample, iteration, model, sampler[, N; kwargs...])

Save the sample of the MCMC sampler at the current iteration in the container of samples.

The function can be called with and without a predefined number N of samples. By default, AbstractMCMC uses push!! from the Julia package BangBang to append to the container, and widen its type if needed.

source

For most use cases the default implementation of AbstractMCMC.samples and AbstractMCMC.save!! should work out of the box and hence need not to be overloaded in downstream code.

Creating chains

Note

This section does not apply to the iterator and transducer interface.

At the end of the sampling procedure for regular and paralle sampling we transform the collection of samples to the desired output type by calling AbstractMCMC.bundle_samples.

AbstractMCMC.bundle_samplesFunction
bundle_samples(samples, model, sampler, state, chain_type[; kwargs...])

Bundle all samples that were sampled from the model with the given sampler in a chain.

The final state of the sampler can be included in the chain. The type of the chain can be specified with the chain_type argument.

By default, this method returns samples.

source

The default implementation should be fine in most use cases, but downstream packages could, e.g., save the final state of the sampler as well if they overload AbstractMCMC.bundle_samples.

- +end

All other default implementations make use of the same structure and in particular call the same methods.

Sampling step

The only method for which no default implementation is provided (and hence which downstream packages have to implement) is AbstractMCMC.step. It defines the sampling step of the inference method.

AbstractMCMC.stepFunction
step(rng, model, sampler[, state; kwargs...])

Return a 2-tuple of the next sample and the next state of the MCMC sampler for model.

Samples describe the results of a single step of the sampler. As an example, a sample might include a vector of parameters sampled from a prior distribution.

When sampling using sample, every step call after the first has access to the current state of the sampler.

source

If one also has some special handling of the warmup-stage of sampling, then this can be specified by overloading

AbstractMCMC.step_warmupFunction
step_warmup(rng, model, sampler[, state; kwargs...])

Return a 2-tuple of the next sample and the next state of the MCMC sampler for model.

When sampling using sample, this takes the place of AbstractMCMC.step in the first num_warmup number of iterations, as specified by the num_warmup keyword to sample. This is useful if the sampler has an initial "warmup"-stage that is different from the standard iteration.

By default, this simply calls AbstractMCMC.step.

source

which will be used for the first num_warmup iterations, as specified as a keyword argument to AbstractMCMC.sample. Note that this is optional; by default it simply calls AbstractMCMC.step from above.

Collecting samples

Note

This section does not apply to the iterator and transducer interface.

After the initial sample is obtained, the default implementations for regular and parallel sampling (not for the iterator and the transducer since it is not needed there) create a container for all samples (the initial one and all subsequent samples) using AbstractMCMC.samples.

AbstractMCMC.samplesFunction
samples(sample, model, sampler[, N; kwargs...])

Generate a container for the samples of the MCMC sampler for the model, whose first sample is sample.

The method can be called with and without a predefined number N of samples.

source

In each step, the sample is saved in the container by AbstractMCMC.save!!. The notation !! follows the convention of the package BangBang.jl which is used in the default implementation of AbstractMCMC.save!!. It indicates that the sample is pushed to the container but a "widening" fallback is used if the container type does not allow to save the sample. Therefore AbstractMCMC.save!! always has to return the container.

AbstractMCMC.save!!Function
save!!(samples, sample, iteration, model, sampler[, N; kwargs...])

Save the sample of the MCMC sampler at the current iteration in the container of samples.

The function can be called with and without a predefined number N of samples. By default, AbstractMCMC uses push!! from the Julia package BangBang to append to the container, and widen its type if needed.

source

For most use cases the default implementation of AbstractMCMC.samples and AbstractMCMC.save!! should work out of the box and hence need not to be overloaded in downstream code.

Creating chains

Note

This section does not apply to the iterator and transducer interface.

At the end of the sampling procedure for regular and paralle sampling we transform the collection of samples to the desired output type by calling AbstractMCMC.bundle_samples.

AbstractMCMC.bundle_samplesFunction
bundle_samples(samples, model, sampler, state, chain_type[; kwargs...])

Bundle all samples that were sampled from the model with the given sampler in a chain.

The final state of the sampler can be included in the chain. The type of the chain can be specified with the chain_type argument.

By default, this method returns samples.

source

The default implementation should be fine in most use cases, but downstream packages could, e.g., save the final state of the sampler as well if they overload AbstractMCMC.bundle_samples.

diff --git a/previews/PR150/index.html b/previews/PR150/index.html index 2a264f3..fc52452 100644 --- a/previews/PR150/index.html +++ b/previews/PR150/index.html @@ -1,461 +1,2 @@ -Home · AbstractMCMC - - - - - -

AbstractMCMC.jl

Abstract types and interfaces for Markov chain Monte Carlo methods.

AbstractMCMC defines an interface for sampling and combining Markov chains. It comes with a default sampling algorithm that provides support of progress bars, parallel sampling (multithreaded and multicore), and user-provided callbacks out of the box. Typically developers only have to define the sampling step of their inference method in an iterator-like fashion to make use of this functionality. Additionally, the package defines an iterator and a transducer for sampling Markov chains based on the interface.

- +Home · AbstractMCMC

AbstractMCMC.jl

Abstract types and interfaces for Markov chain Monte Carlo methods.

AbstractMCMC defines an interface for sampling and combining Markov chains. It comes with a default sampling algorithm that provides support of progress bars, parallel sampling (multithreaded and multicore), and user-provided callbacks out of the box. Typically developers only have to define the sampling step of their inference method in an iterator-like fashion to make use of this functionality. Additionally, the package defines an iterator and a transducer for sampling Markov chains based on the interface.

diff --git a/previews/PR150/search_index.js b/previews/PR150/search_index.js index f1ea8c1..1c051b7 100644 --- a/previews/PR150/search_index.js +++ b/previews/PR150/search_index.js @@ -1,3 +1,3 @@ var documenterSearchIndex = {"docs": -[{"location":"api/#API","page":"API","title":"API","text":"","category":"section"},{"location":"api/","page":"API","title":"API","text":"AbstractMCMC defines an interface for sampling Markov chains.","category":"page"},{"location":"api/#Model","page":"API","title":"Model","text":"","category":"section"},{"location":"api/","page":"API","title":"API","text":"AbstractMCMC.AbstractModel\nAbstractMCMC.LogDensityModel","category":"page"},{"location":"api/#AbstractMCMC.AbstractModel","page":"API","title":"AbstractMCMC.AbstractModel","text":"AbstractModel\n\nAn AbstractModel represents a generic model type that can be used to perform inference.\n\n\n\n\n\n","category":"type"},{"location":"api/#AbstractMCMC.LogDensityModel","page":"API","title":"AbstractMCMC.LogDensityModel","text":"LogDensityModel <: AbstractMCMC.AbstractModel\n\nWrapper around something that implements the LogDensityProblem.jl interface.\n\nNote that this does not implement the LogDensityProblems.jl interface itself, but it simply useful for indicating to the sample and other AbstractMCMC methods that the wrapped object implements the LogDensityProblems.jl interface.\n\nFields\n\nlogdensity: The object that implements the LogDensityProblems.jl interface.\n\n\n\n\n\n","category":"type"},{"location":"api/#Sampler","page":"API","title":"Sampler","text":"","category":"section"},{"location":"api/","page":"API","title":"API","text":"AbstractMCMC.AbstractSampler","category":"page"},{"location":"api/#AbstractMCMC.AbstractSampler","page":"API","title":"AbstractMCMC.AbstractSampler","text":"AbstractSampler\n\nThe AbstractSampler type is intended to be inherited from when implementing a custom sampler. Any persistent state information should be saved in a subtype of AbstractSampler.\n\nWhen defining a new sampler, you should also overload the function transition_type, which tells the sample function what type of parameter it should expect to receive.\n\n\n\n\n\n","category":"type"},{"location":"api/#Sampling-a-single-chain","page":"API","title":"Sampling a single chain","text":"","category":"section"},{"location":"api/","page":"API","title":"API","text":"AbstractMCMC.sample(::AbstractRNG, ::AbstractMCMC.AbstractModel, ::AbstractMCMC.AbstractSampler, ::Any)\nAbstractMCMC.sample(::AbstractRNG, ::Any, ::AbstractMCMC.AbstractSampler, ::Any)\n","category":"page"},{"location":"api/#StatsBase.sample-Tuple{AbstractRNG, AbstractMCMC.AbstractModel, AbstractMCMC.AbstractSampler, Any}","page":"API","title":"StatsBase.sample","text":"sample(\n rng::Random.AbatractRNG=Random.default_rng(),\n model::AbstractModel,\n sampler::AbstractSampler,\n N_or_isdone;\n kwargs...,\n)\n\nSample from the model with the Markov chain Monte Carlo sampler and return the samples.\n\nIf N_or_isdone is an Integer, exactly N_or_isdone samples are returned.\n\nOtherwise, sampling is performed until a convergence criterion N_or_isdone returns true. The convergence criterion has to be a function with the signature\n\nisdone(rng, model, sampler, samples, state, iteration; kwargs...)\n\nwhere state and iteration are the current state and iteration of the sampler, respectively. It should return true when sampling should end, and false otherwise.\n\nKeyword arguments\n\nSee https://turinglang.org/AbstractMCMC.jl/dev/api/#Common-keyword-arguments for common keyword arguments.\n\n\n\n\n\n","category":"method"},{"location":"api/#StatsBase.sample-Tuple{AbstractRNG, Any, AbstractMCMC.AbstractSampler, Any}","page":"API","title":"StatsBase.sample","text":"sample(\n rng::Random.AbstractRNG=Random.default_rng(),\n logdensity,\n sampler::AbstractSampler,\n N_or_isdone;\n kwargs...,\n)\n\nWrap the logdensity function in a LogDensityModel, and call sample with the resulting model instead of logdensity.\n\nThe logdensity function has to support the LogDensityProblems.jl interface.\n\n\n\n\n\n","category":"method"},{"location":"api/#Iterator","page":"API","title":"Iterator","text":"","category":"section"},{"location":"api/","page":"API","title":"API","text":"AbstractMCMC.steps(::AbstractRNG, ::AbstractMCMC.AbstractModel, ::AbstractMCMC.AbstractSampler)\nAbstractMCMC.steps(::AbstractRNG, ::Any, ::AbstractMCMC.AbstractSampler)","category":"page"},{"location":"api/#AbstractMCMC.steps-Tuple{AbstractRNG, AbstractMCMC.AbstractModel, AbstractMCMC.AbstractSampler}","page":"API","title":"AbstractMCMC.steps","text":"steps(\n rng::Random.AbstractRNG=Random.default_rng(),\n model::AbstractModel,\n sampler::AbstractSampler;\n kwargs...,\n)\n\nCreate an iterator that returns samples from the model with the Markov chain Monte Carlo sampler.\n\nExamples\n\njulia> struct MyModel <: AbstractMCMC.AbstractModel end\n\njulia> struct MySampler <: AbstractMCMC.AbstractSampler end\n\njulia> function AbstractMCMC.step(rng, ::MyModel, ::MySampler, state=nothing; kwargs...)\n # all samples are zero\n return 0.0, state\n end\n\njulia> iterator = steps(MyModel(), MySampler());\n\njulia> collect(Iterators.take(iterator, 10)) == zeros(10)\ntrue\n\n\n\n\n\n","category":"method"},{"location":"api/#AbstractMCMC.steps-Tuple{AbstractRNG, Any, AbstractMCMC.AbstractSampler}","page":"API","title":"AbstractMCMC.steps","text":"steps(\n rng::Random.AbstractRNG=Random.default_rng(),\n logdensity,\n sampler::AbstractSampler;\n kwargs...,\n)\n\nWrap the logdensity function in a LogDensityModel, and call steps with the resulting model instead of logdensity.\n\nThe logdensity function has to support the LogDensityProblems.jl interface.\n\n\n\n\n\n","category":"method"},{"location":"api/#Transducer","page":"API","title":"Transducer","text":"","category":"section"},{"location":"api/","page":"API","title":"API","text":"AbstractMCMC.Sample(::AbstractRNG, ::AbstractMCMC.AbstractModel, ::AbstractMCMC.AbstractSampler)\nAbstractMCMC.Sample(::AbstractRNG, ::Any, ::AbstractMCMC.AbstractSampler)","category":"page"},{"location":"api/#AbstractMCMC.Sample-Tuple{AbstractRNG, AbstractMCMC.AbstractModel, AbstractMCMC.AbstractSampler}","page":"API","title":"AbstractMCMC.Sample","text":"Sample(\n rng::Random.AbstractRNG=Random.default_rng(),\n model::AbstractModel,\n sampler::AbstractSampler;\n kwargs...,\n)\n\nCreate a transducer that returns samples from the model with the Markov chain Monte Carlo sampler.\n\nExamples\n\njulia> struct MyModel <: AbstractMCMC.AbstractModel end\n\njulia> struct MySampler <: AbstractMCMC.AbstractSampler end\n\njulia> function AbstractMCMC.step(rng, ::MyModel, ::MySampler, state=nothing; kwargs...)\n # all samples are zero\n return 0.0, state\n end\n\njulia> transducer = Sample(MyModel(), MySampler());\n\njulia> collect(transducer(1:10)) == zeros(10)\ntrue\n\n\n\n\n\n","category":"method"},{"location":"api/#AbstractMCMC.Sample-Tuple{AbstractRNG, Any, AbstractMCMC.AbstractSampler}","page":"API","title":"AbstractMCMC.Sample","text":"Sample(\n rng::Random.AbstractRNG=Random.default_rng(),\n logdensity,\n sampler::AbstractSampler;\n kwargs...,\n)\n\nWrap the logdensity function in a LogDensityModel, and call Sample with the resulting model instead of logdensity.\n\nThe logdensity function has to support the LogDensityProblems.jl interface.\n\n\n\n\n\n","category":"method"},{"location":"api/#Sampling-multiple-chains-in-parallel","page":"API","title":"Sampling multiple chains in parallel","text":"","category":"section"},{"location":"api/","page":"API","title":"API","text":"AbstractMCMC.sample(\n ::AbstractRNG,\n ::AbstractMCMC.AbstractModel,\n ::AbstractMCMC.AbstractSampler,\n ::AbstractMCMC.AbstractMCMCEnsemble,\n ::Integer,\n ::Integer,\n)\nAbstractMCMC.sample(\n ::AbstractRNG,\n ::Any,\n ::AbstractMCMC.AbstractSampler,\n ::AbstractMCMC.AbstractMCMCEnsemble,\n ::Integer,\n ::Integer,\n)","category":"page"},{"location":"api/#StatsBase.sample-Tuple{AbstractRNG, AbstractMCMC.AbstractModel, AbstractMCMC.AbstractSampler, AbstractMCMC.AbstractMCMCEnsemble, Integer, Integer}","page":"API","title":"StatsBase.sample","text":"sample(\n rng::Random.AbstractRNG=Random.default_rng(),\n model::AbstractModel,\n sampler::AbstractSampler,\n parallel::AbstractMCMCEnsemble,\n N::Integer,\n nchains::Integer;\n kwargs...,\n)\n\nSample nchains Monte Carlo Markov chains from the model with the sampler in parallel using the parallel algorithm, and combine them into a single chain.\n\nKeyword arguments\n\nSee https://turinglang.org/AbstractMCMC.jl/dev/api/#Common-keyword-arguments for common keyword arguments.\n\n\n\n\n\n","category":"method"},{"location":"api/#StatsBase.sample-Tuple{AbstractRNG, Any, AbstractMCMC.AbstractSampler, AbstractMCMC.AbstractMCMCEnsemble, Integer, Integer}","page":"API","title":"StatsBase.sample","text":"sample(\n rng::Random.AbstractRNG=Random.default_rng(),\n logdensity,\n sampler::AbstractSampler,\n parallel::AbstractMCMCEnsemble,\n N::Integer,\n nchains::Integer;\n kwargs...,\n)\n\nWrap the logdensity function in a LogDensityModel, and call sample with the resulting model instead of logdensity.\n\nThe logdensity function has to support the LogDensityProblems.jl interface.\n\n\n\n\n\n","category":"method"},{"location":"api/","page":"API","title":"API","text":"Two algorithms are provided for parallel sampling with multiple threads and multiple processes, and one allows for the user to sample multiple chains in serial (no parallelization):","category":"page"},{"location":"api/","page":"API","title":"API","text":"AbstractMCMC.MCMCThreads\nAbstractMCMC.MCMCDistributed\nAbstractMCMC.MCMCSerial","category":"page"},{"location":"api/#AbstractMCMC.MCMCThreads","page":"API","title":"AbstractMCMC.MCMCThreads","text":"MCMCThreads\n\nThe MCMCThreads algorithm allows users to sample MCMC chains in parallel using multiple threads.\n\n\n\n\n\n","category":"type"},{"location":"api/#AbstractMCMC.MCMCDistributed","page":"API","title":"AbstractMCMC.MCMCDistributed","text":"MCMCDistributed\n\nThe MCMCDistributed algorithm allows users to sample MCMC chains in parallel using multiple processes.\n\n\n\n\n\n","category":"type"},{"location":"api/#AbstractMCMC.MCMCSerial","page":"API","title":"AbstractMCMC.MCMCSerial","text":"MCMCSerial\n\nThe MCMCSerial algorithm allows users to sample serially, with no thread or process parallelism.\n\n\n\n\n\n","category":"type"},{"location":"api/#Common-keyword-arguments","page":"API","title":"Common keyword arguments","text":"","category":"section"},{"location":"api/","page":"API","title":"API","text":"Common keyword arguments for regular and parallel sampling are:","category":"page"},{"location":"api/","page":"API","title":"API","text":"progress (default: AbstractMCMC.PROGRESS[] which is true initially): toggles progress logging\nchain_type (default: Any): determines the type of the returned chain\ncallback (default: nothing): if callback !== nothing, then callback(rng, model, sampler, sample, iteration) is called after every sampling step, where sample is the most recent sample of the Markov chain and iteration is the current iteration\nnum_warmup (default: 0): number of \"warm-up\" steps to take before the first \"regular\" step, i.e. number of times to call AbstractMCMC.step_warmup before the first call to AbstractMCMC.step.\ndiscard_initial (default: num_warmup): number of initial samples that are discarded. Note that if discard_initial < num_warmup, warm-up samples will also be included in the resulting samples.\nthinning (default: 1): factor by which to thin samples.\ninitial_state (default: nothing): if initial_state !== nothing, the first call to AbstractMCMC.step is passed initial_state as the state argument.","category":"page"},{"location":"api/","page":"API","title":"API","text":"info: Info\nThe common keyword arguments progress, chain_type, and callback are not supported by the iterator AbstractMCMC.steps and the transducer AbstractMCMC.Sample.","category":"page"},{"location":"api/","page":"API","title":"API","text":"There is no \"official\" way for providing initial parameter values yet. However, multiple packages such as EllipticalSliceSampling.jl and AdvancedMH.jl support an initial_params keyword argument for setting the initial values when sampling a single chain. To ensure that sampling multiple chains \"just works\" when sampling of a single chain is implemented, we decided to support initial_params in the default implementations of the ensemble methods:","category":"page"},{"location":"api/","page":"API","title":"API","text":"initial_params (default: nothing): if initial_params isa AbstractArray, then the ith element of initial_params is used as initial parameters of the ith chain. If one wants to use the same initial parameters x for every chain, one can specify e.g. initial_params = FillArrays.Fill(x, N).","category":"page"},{"location":"api/","page":"API","title":"API","text":"Progress logging can be enabled and disabled globally with AbstractMCMC.setprogress!(progress).","category":"page"},{"location":"api/","page":"API","title":"API","text":"AbstractMCMC.setprogress!","category":"page"},{"location":"api/#AbstractMCMC.setprogress!","page":"API","title":"AbstractMCMC.setprogress!","text":"setprogress!(progress::Bool; silent::Bool=false)\n\nEnable progress logging globally if progress is true, and disable it otherwise. Optionally disable informational message if silent is true.\n\n\n\n\n\n","category":"function"},{"location":"api/#Chains","page":"API","title":"Chains","text":"","category":"section"},{"location":"api/","page":"API","title":"API","text":"The chain_type keyword argument allows to set the type of the returned chain. A common choice is to return chains of type Chains from MCMCChains.jl.","category":"page"},{"location":"api/","page":"API","title":"API","text":"AbstractMCMC defines the abstract type AbstractChains for Markov chains.","category":"page"},{"location":"api/","page":"API","title":"API","text":"AbstractMCMC.AbstractChains","category":"page"},{"location":"api/#AbstractMCMC.AbstractChains","page":"API","title":"AbstractMCMC.AbstractChains","text":"AbstractChains\n\nAbstractChains is an abstract type for an object that stores parameter samples generated through a MCMC process.\n\n\n\n\n\n","category":"type"},{"location":"api/","page":"API","title":"API","text":"For chains of this type, AbstractMCMC defines the following two methods.","category":"page"},{"location":"api/","page":"API","title":"API","text":"AbstractMCMC.chainscat\nAbstractMCMC.chainsstack","category":"page"},{"location":"api/#AbstractMCMC.chainscat","page":"API","title":"AbstractMCMC.chainscat","text":"chainscat(c::AbstractChains...)\n\nConcatenate multiple chains.\n\nBy default, the chains are concatenated along the third dimension by calling cat(c...; dims=3).\n\n\n\n\n\n","category":"function"},{"location":"api/#AbstractMCMC.chainsstack","page":"API","title":"AbstractMCMC.chainsstack","text":"chainsstack(c::AbstractVector)\n\nStack chains in c.\n\nBy default, the vector of chains is returned unmodified. If eltype(c) <: AbstractChains, then reduce(chainscat, c) is called.\n\n\n\n\n\n","category":"function"},{"location":"api/#Interacting-with-states-of-samplers","page":"API","title":"Interacting with states of samplers","text":"","category":"section"},{"location":"api/","page":"API","title":"API","text":"To make it a bit easier to interact with some arbitrary sampler state, we encourage implementations of AbstractSampler to implement the following methods:","category":"page"},{"location":"api/","page":"API","title":"API","text":"AbstractMCMC.getparams\nAbstractMCMC.setparams!!","category":"page"},{"location":"api/#AbstractMCMC.getparams","page":"API","title":"AbstractMCMC.getparams","text":"getparams([model::AbstractModel, ]state)\n\nRetrieve the values of parameters from the sampler's state as a Vector{<:Real}.\n\n\n\n\n\n","category":"function"},{"location":"api/#AbstractMCMC.setparams!!","page":"API","title":"AbstractMCMC.setparams!!","text":"setparams!!([model::AbstractModel, ]state, params)\n\nSet the values of parameters in the sampler's state from a Vector{<:Real}. \n\nThis function should follow the BangBang interface: mutate state in-place if possible and return the mutated state. Otherwise, it should return a new state containing the updated parameters.\n\nAlthough not enforced, it should hold that setparams!!(state, getparams(state)) == state. In other words, the sampler should implement a consistent transformation between its internal representation and the vector representation of the parameter values.\n\nSometimes, to maintain the consistency of the log density and parameter values, a model should be provided. This is useful for samplers that need to evaluate the log density at the new parameter values.\n\n\n\n\n\n","category":"function"},{"location":"api/","page":"API","title":"API","text":"getparams and setparams!! provide a generic interface for interacting with the parameters of a sampler's state, regardless of how that state is represented internally. If the model argument is not provided, the functions will be dispatched to the implementations without the model argument.","category":"page"},{"location":"api/","page":"API","title":"API","text":"This allows generic code to be written that works with any sampler implementing this interface. For example, a generic ensemble sampler could use getparams to extract the parameters from each of its component samplers' states, and setparams!! to initialize each component sampler with a different set of parameters.","category":"page"},{"location":"api/","page":"API","title":"API","text":"The optional model argument to these functions allows sampler implementations to customize their behavior based on the model being used. This is useful for samplers that need to access or modify the model in order to extract or set the parameters.","category":"page"},{"location":"api/","page":"API","title":"API","text":"These methods are particularly useful for implementing samplers which wrap some inner samplers, such as a mixture of samplers. In the next section, we will see how getparams and setparams!! can be used to implement a MixtureSampler.","category":"page"},{"location":"api/#Example:-MixtureSampler","page":"API","title":"Example: MixtureSampler","text":"","category":"section"},{"location":"api/","page":"API","title":"API","text":"In a MixtureSampler we need two things:","category":"page"},{"location":"api/","page":"API","title":"API","text":"components: collection of samplers.\nweights: collection of weights representing the probability of choosing the corresponding sampler.","category":"page"},{"location":"api/","page":"API","title":"API","text":"struct MixtureSampler{W,C} <: AbstractMCMC.AbstractSampler\n components::C\n weights::W\nend","category":"page"},{"location":"api/","page":"API","title":"API","text":"To implement the state, we need to keep track of a couple of things:","category":"page"},{"location":"api/","page":"API","title":"API","text":"index: the index of the sampler used in this step.\nstates: the current states of all the components.","category":"page"},{"location":"api/","page":"API","title":"API","text":"We need to keep track of the states of all components rather than just the state for the sampler we used previously. The reason is that lots of samplers keep track of more than just the previous realizations of the variables, e.g. in AdvancedHMC.jl we keep track of the momentum used, the metric used, etc.","category":"page"},{"location":"api/","page":"API","title":"API","text":"struct MixtureState{S}\n index::Int\n states::S\nend","category":"page"},{"location":"api/","page":"API","title":"API","text":"The step for a MixtureSampler is defined by the following generative process","category":"page"},{"location":"api/","page":"API","title":"API","text":"beginaligned\ni sim mathrmCategorical(w_1 dots w_k) \nX_t sim mathcalK_i(cdot mid X_t - 1)\nendaligned","category":"page"},{"location":"api/","page":"API","title":"API","text":"where mathcalK_i denotes the i-th kernel/sampler, and w_i denotes the weight/probability of choosing the i-th sampler. AbstractMCMC.getparams and AbstractMCMC.setparams!! comes into play in defining/computing mathcalK_i(cdot mid X_t - 1) since X_t - 1 could be coming from a different sampler.","category":"page"},{"location":"api/","page":"API","title":"API","text":"If we let state be the current MixtureState, i the current component, and i_prev is the previous component we sampled from, then this translates into the following piece of code:","category":"page"},{"location":"api/","page":"API","title":"API","text":"# Update the corresponding state, i.e. `state.states[i]`, using\n# the state and transition from the previous iteration.\nstate_current = AbstractMCMC.setparams!!(\n state.states[i], \n AbstractMCMC.getparams(state.states[i_prev]),\n)\n\n# Take a `step` for this sampler using the updated state.\ntransition, state_current = AbstractMCMC.step(\n rng, model, sampler_current, sampler_state;\n kwargs...\n)","category":"page"},{"location":"api/","page":"API","title":"API","text":"The full AbstractMCMC.step implementation would then be something like:","category":"page"},{"location":"api/","page":"API","title":"API","text":"function AbstractMCMC.step(rng, model::AbstractMCMC.AbstractModel, sampler::MixtureSampler, state; kwargs...)\n # Sample the component to use in this `step`.\n i = rand(Categorical(sampler.weights))\n sampler_current = sampler.components[i]\n\n # Update the corresponding state, i.e. `state.states[i]`, using\n # the state and transition from the previous iteration.\n i_prev = state.index\n state_current = AbstractMCMC.setparams!!( \n state.states[i], \n AbstractMCMC.getparams(state.states[i_prev]), \n )\n\n # Take a `step` for this sampler using the updated state.\n transition, state_current = AbstractMCMC.step(\n rng, model, sampler_current, state_current;\n kwargs...\n )\n\n # Create the new states.\n # NOTE: Code below will result in `states_new` being a `Vector`.\n # If we wanted to allow usage of alternative containers, e.g. `Tuple`,\n # it would be better to use something like `@set states[i] = state_current`\n # where `@set` is from Setfield.jl.\n states_new = map(1:length(state.states)) do j\n if j == i\n # Replace the i-th state with the new one.\n state_current\n else\n # Otherwise we just carry over the previous ones.\n state.states[j]\n end\n end\n\n # Create the new `MixtureState`.\n state_new = MixtureState(i, states_new)\n\n return transition, state_new\nend","category":"page"},{"location":"api/","page":"API","title":"API","text":"And for the initial AbstractMCMC.step we have:","category":"page"},{"location":"api/","page":"API","title":"API","text":"function AbstractMCMC.step(rng, model::AbstractMCMC.AbstractModel, sampler::MixtureSampler; kwargs...)\n # Initialize every state.\n transitions_and_states = map(sampler.components) do spl\n AbstractMCMC.step(rng, model, spl; kwargs...)\n end\n\n # Sample the component to use this `step`.\n i = rand(Categorical(sampler.weights))\n # Extract the corresponding transition.\n transition = first(transitions_and_states[i])\n # Extract states.\n states = map(last, transitions_and_states)\n # Create new `MixtureState`.\n state = MixtureState(i, states)\n\n return transition, state\nend","category":"page"},{"location":"api/","page":"API","title":"API","text":"Suppose we then wanted to use this with some of the packages which implements AbstractMCMC.jl's interface, e.g. AdvancedMH.jl, then we'd simply have to implement getparams and setparams!!.","category":"page"},{"location":"api/","page":"API","title":"API","text":"To use MixtureSampler with two samplers sampler1 and sampler2 from AdvancedMH.jl as components, we'd simply do","category":"page"},{"location":"api/","page":"API","title":"API","text":"sampler = MixtureSampler([sampler1, sampler2], [0.1, 0.9])\ntransition, state = AbstractMCMC.step(rng, model, sampler)\nwhile ...\n transition, state = AbstractMCMC.step(rng, model, sampler, state)\nend","category":"page"},{"location":"design/#Design","page":"Design","title":"Design","text":"","category":"section"},{"location":"design/","page":"Design","title":"Design","text":"This page explains the default implementations and design choices of AbstractMCMC. It is not intended for users but for developers that want to implement the AbstractMCMC interface for Markov chain Monte Carlo sampling. The user-facing API is explained in API.","category":"page"},{"location":"design/#Overview","page":"Design","title":"Overview","text":"","category":"section"},{"location":"design/","page":"Design","title":"Design","text":"AbstractMCMC provides a default implementation of the user-facing interface described in API. You can completely neglect these and define your own implementation of the interface. However, as described below, in most use cases the default implementation allows you to obtain support of parallel sampling, progress logging, callbacks, iterators, and transducers for free by just defining the sampling step of your inference algorithm, drastically reducing the amount of code you have to write. In general, the docstrings of the functions described below might be helpful if you intend to make use of the default implementations.","category":"page"},{"location":"design/#Basic-structure","page":"Design","title":"Basic structure","text":"","category":"section"},{"location":"design/","page":"Design","title":"Design","text":"The simplified structure for regular sampling (the actual implementation contains some additional error checks and support for progress logging and callbacks) is","category":"page"},{"location":"design/","page":"Design","title":"Design","text":"StatsBase.sample(\n rng::Random.AbstractRNG,\n model::AbstractMCMC.AbstractModel,\n sampler::AbstractMCMC.AbstractSampler,\n nsamples::Integer;\n chain_type = ::Type{Any},\n kwargs...\n)\n # Obtain the initial sample and state.\n sample, state = AbstractMCMC.step(rng, model, sampler; kwargs...)\n\n # Save the sample.\n samples = AbstractMCMC.samples(sample, model, sampler, N; kwargs...)\n samples = AbstractMCMC.save!!(samples, sample, 1, model, sampler, N; kwargs...)\n\n # Step through the sampler.\n for i in 2:N\n # Obtain the next sample and state.\n sample, state = AbstractMCMC.step(rng, model, sampler, state; kwargs...)\n\n # Save the sample.\n samples = AbstractMCMC.save!!(samples, sample, i, model, sampler, N; kwargs...)\n end\n\n return AbstractMCMC.bundle_samples(samples, model, sampler, state, chain_type; kwargs...)\nend","category":"page"},{"location":"design/","page":"Design","title":"Design","text":"All other default implementations make use of the same structure and in particular call the same methods.","category":"page"},{"location":"design/#Sampling-step","page":"Design","title":"Sampling step","text":"","category":"section"},{"location":"design/","page":"Design","title":"Design","text":"The only method for which no default implementation is provided (and hence which downstream packages have to implement) is AbstractMCMC.step. It defines the sampling step of the inference method.","category":"page"},{"location":"design/","page":"Design","title":"Design","text":"AbstractMCMC.step","category":"page"},{"location":"design/#AbstractMCMC.step","page":"Design","title":"AbstractMCMC.step","text":"step(rng, model, sampler[, state; kwargs...])\n\nReturn a 2-tuple of the next sample and the next state of the MCMC sampler for model.\n\nSamples describe the results of a single step of the sampler. As an example, a sample might include a vector of parameters sampled from a prior distribution.\n\nWhen sampling using sample, every step call after the first has access to the current state of the sampler.\n\n\n\n\n\n","category":"function"},{"location":"design/","page":"Design","title":"Design","text":"If one also has some special handling of the warmup-stage of sampling, then this can be specified by overloading","category":"page"},{"location":"design/","page":"Design","title":"Design","text":"AbstractMCMC.step_warmup","category":"page"},{"location":"design/#AbstractMCMC.step_warmup","page":"Design","title":"AbstractMCMC.step_warmup","text":"step_warmup(rng, model, sampler[, state; kwargs...])\n\nReturn a 2-tuple of the next sample and the next state of the MCMC sampler for model.\n\nWhen sampling using sample, this takes the place of AbstractMCMC.step in the first num_warmup number of iterations, as specified by the num_warmup keyword to sample. This is useful if the sampler has an initial \"warmup\"-stage that is different from the standard iteration.\n\nBy default, this simply calls AbstractMCMC.step.\n\n\n\n\n\n","category":"function"},{"location":"design/","page":"Design","title":"Design","text":"which will be used for the first num_warmup iterations, as specified as a keyword argument to AbstractMCMC.sample. Note that this is optional; by default it simply calls AbstractMCMC.step from above.","category":"page"},{"location":"design/#Collecting-samples","page":"Design","title":"Collecting samples","text":"","category":"section"},{"location":"design/","page":"Design","title":"Design","text":"note: Note\nThis section does not apply to the iterator and transducer interface.","category":"page"},{"location":"design/","page":"Design","title":"Design","text":"After the initial sample is obtained, the default implementations for regular and parallel sampling (not for the iterator and the transducer since it is not needed there) create a container for all samples (the initial one and all subsequent samples) using AbstractMCMC.samples.","category":"page"},{"location":"design/","page":"Design","title":"Design","text":"AbstractMCMC.samples","category":"page"},{"location":"design/#AbstractMCMC.samples","page":"Design","title":"AbstractMCMC.samples","text":"samples(sample, model, sampler[, N; kwargs...])\n\nGenerate a container for the samples of the MCMC sampler for the model, whose first sample is sample.\n\nThe method can be called with and without a predefined number N of samples.\n\n\n\n\n\n","category":"function"},{"location":"design/","page":"Design","title":"Design","text":"In each step, the sample is saved in the container by AbstractMCMC.save!!. The notation !! follows the convention of the package BangBang.jl which is used in the default implementation of AbstractMCMC.save!!. It indicates that the sample is pushed to the container but a \"widening\" fallback is used if the container type does not allow to save the sample. Therefore AbstractMCMC.save!! always has to return the container.","category":"page"},{"location":"design/","page":"Design","title":"Design","text":"AbstractMCMC.save!!","category":"page"},{"location":"design/#AbstractMCMC.save!!","page":"Design","title":"AbstractMCMC.save!!","text":"save!!(samples, sample, iteration, model, sampler[, N; kwargs...])\n\nSave the sample of the MCMC sampler at the current iteration in the container of samples.\n\nThe function can be called with and without a predefined number N of samples. By default, AbstractMCMC uses push!! from the Julia package BangBang to append to the container, and widen its type if needed.\n\n\n\n\n\n","category":"function"},{"location":"design/","page":"Design","title":"Design","text":"For most use cases the default implementation of AbstractMCMC.samples and AbstractMCMC.save!! should work out of the box and hence need not to be overloaded in downstream code.","category":"page"},{"location":"design/#Creating-chains","page":"Design","title":"Creating chains","text":"","category":"section"},{"location":"design/","page":"Design","title":"Design","text":"note: Note\nThis section does not apply to the iterator and transducer interface.","category":"page"},{"location":"design/","page":"Design","title":"Design","text":"At the end of the sampling procedure for regular and paralle sampling we transform the collection of samples to the desired output type by calling AbstractMCMC.bundle_samples.","category":"page"},{"location":"design/","page":"Design","title":"Design","text":"AbstractMCMC.bundle_samples","category":"page"},{"location":"design/#AbstractMCMC.bundle_samples","page":"Design","title":"AbstractMCMC.bundle_samples","text":"bundle_samples(samples, model, sampler, state, chain_type[; kwargs...])\n\nBundle all samples that were sampled from the model with the given sampler in a chain.\n\nThe final state of the sampler can be included in the chain. The type of the chain can be specified with the chain_type argument.\n\nBy default, this method returns samples.\n\n\n\n\n\n","category":"function"},{"location":"design/","page":"Design","title":"Design","text":"The default implementation should be fine in most use cases, but downstream packages could, e.g., save the final state of the sampler as well if they overload AbstractMCMC.bundle_samples.","category":"page"},{"location":"#AbstractMCMC.jl","page":"Home","title":"AbstractMCMC.jl","text":"","category":"section"},{"location":"","page":"Home","title":"Home","text":"Abstract types and interfaces for Markov chain Monte Carlo methods.","category":"page"},{"location":"","page":"Home","title":"Home","text":"AbstractMCMC defines an interface for sampling and combining Markov chains. It comes with a default sampling algorithm that provides support of progress bars, parallel sampling (multithreaded and multicore), and user-provided callbacks out of the box. Typically developers only have to define the sampling step of their inference method in an iterator-like fashion to make use of this functionality. Additionally, the package defines an iterator and a transducer for sampling Markov chains based on the interface.","category":"page"}] +[{"location":"api/#API","page":"API","title":"API","text":"","category":"section"},{"location":"api/","page":"API","title":"API","text":"AbstractMCMC defines an interface for sampling Markov chains.","category":"page"},{"location":"api/#Model","page":"API","title":"Model","text":"","category":"section"},{"location":"api/","page":"API","title":"API","text":"AbstractMCMC.AbstractModel\nAbstractMCMC.LogDensityModel","category":"page"},{"location":"api/#AbstractMCMC.AbstractModel","page":"API","title":"AbstractMCMC.AbstractModel","text":"AbstractModel\n\nAn AbstractModel represents a generic model type that can be used to perform inference.\n\n\n\n\n\n","category":"type"},{"location":"api/#AbstractMCMC.LogDensityModel","page":"API","title":"AbstractMCMC.LogDensityModel","text":"LogDensityModel <: AbstractMCMC.AbstractModel\n\nWrapper around something that implements the LogDensityProblem.jl interface.\n\nNote that this does not implement the LogDensityProblems.jl interface itself, but it simply useful for indicating to the sample and other AbstractMCMC methods that the wrapped object implements the LogDensityProblems.jl interface.\n\nFields\n\nlogdensity: The object that implements the LogDensityProblems.jl interface.\n\n\n\n\n\n","category":"type"},{"location":"api/#Sampler","page":"API","title":"Sampler","text":"","category":"section"},{"location":"api/","page":"API","title":"API","text":"AbstractMCMC.AbstractSampler","category":"page"},{"location":"api/#AbstractMCMC.AbstractSampler","page":"API","title":"AbstractMCMC.AbstractSampler","text":"AbstractSampler\n\nThe AbstractSampler type is intended to be inherited from when implementing a custom sampler. Any persistent state information should be saved in a subtype of AbstractSampler.\n\nWhen defining a new sampler, you should also overload the function transition_type, which tells the sample function what type of parameter it should expect to receive.\n\n\n\n\n\n","category":"type"},{"location":"api/#Sampling-a-single-chain","page":"API","title":"Sampling a single chain","text":"","category":"section"},{"location":"api/","page":"API","title":"API","text":"AbstractMCMC.sample(::AbstractRNG, ::AbstractMCMC.AbstractModel, ::AbstractMCMC.AbstractSampler, ::Any)\nAbstractMCMC.sample(::AbstractRNG, ::Any, ::AbstractMCMC.AbstractSampler, ::Any)\n","category":"page"},{"location":"api/#StatsBase.sample-Tuple{AbstractRNG, AbstractMCMC.AbstractModel, AbstractMCMC.AbstractSampler, Any}","page":"API","title":"StatsBase.sample","text":"sample(\n rng::Random.AbatractRNG=Random.default_rng(),\n model::AbstractModel,\n sampler::AbstractSampler,\n N_or_isdone;\n kwargs...,\n)\n\nSample from the model with the Markov chain Monte Carlo sampler and return the samples.\n\nIf N_or_isdone is an Integer, exactly N_or_isdone samples are returned.\n\nOtherwise, sampling is performed until a convergence criterion N_or_isdone returns true. The convergence criterion has to be a function with the signature\n\nisdone(rng, model, sampler, samples, state, iteration; kwargs...)\n\nwhere state and iteration are the current state and iteration of the sampler, respectively. It should return true when sampling should end, and false otherwise.\n\nKeyword arguments\n\nSee https://turinglang.org/AbstractMCMC.jl/dev/api/#Common-keyword-arguments for common keyword arguments.\n\n\n\n\n\n","category":"method"},{"location":"api/#StatsBase.sample-Tuple{AbstractRNG, Any, AbstractMCMC.AbstractSampler, Any}","page":"API","title":"StatsBase.sample","text":"sample(\n rng::Random.AbstractRNG=Random.default_rng(),\n logdensity,\n sampler::AbstractSampler,\n N_or_isdone;\n kwargs...,\n)\n\nWrap the logdensity function in a LogDensityModel, and call sample with the resulting model instead of logdensity.\n\nThe logdensity function has to support the LogDensityProblems.jl interface.\n\n\n\n\n\n","category":"method"},{"location":"api/#Iterator","page":"API","title":"Iterator","text":"","category":"section"},{"location":"api/","page":"API","title":"API","text":"AbstractMCMC.steps(::AbstractRNG, ::AbstractMCMC.AbstractModel, ::AbstractMCMC.AbstractSampler)\nAbstractMCMC.steps(::AbstractRNG, ::Any, ::AbstractMCMC.AbstractSampler)","category":"page"},{"location":"api/#AbstractMCMC.steps-Tuple{AbstractRNG, AbstractMCMC.AbstractModel, AbstractMCMC.AbstractSampler}","page":"API","title":"AbstractMCMC.steps","text":"steps(\n rng::Random.AbstractRNG=Random.default_rng(),\n model::AbstractModel,\n sampler::AbstractSampler;\n kwargs...,\n)\n\nCreate an iterator that returns samples from the model with the Markov chain Monte Carlo sampler.\n\nExamples\n\njulia> struct MyModel <: AbstractMCMC.AbstractModel end\n\njulia> struct MySampler <: AbstractMCMC.AbstractSampler end\n\njulia> function AbstractMCMC.step(rng, ::MyModel, ::MySampler, state=nothing; kwargs...)\n # all samples are zero\n return 0.0, state\n end\n\njulia> iterator = steps(MyModel(), MySampler());\n\njulia> collect(Iterators.take(iterator, 10)) == zeros(10)\ntrue\n\n\n\n\n\n","category":"method"},{"location":"api/#AbstractMCMC.steps-Tuple{AbstractRNG, Any, AbstractMCMC.AbstractSampler}","page":"API","title":"AbstractMCMC.steps","text":"steps(\n rng::Random.AbstractRNG=Random.default_rng(),\n logdensity,\n sampler::AbstractSampler;\n kwargs...,\n)\n\nWrap the logdensity function in a LogDensityModel, and call steps with the resulting model instead of logdensity.\n\nThe logdensity function has to support the LogDensityProblems.jl interface.\n\n\n\n\n\n","category":"method"},{"location":"api/#Transducer","page":"API","title":"Transducer","text":"","category":"section"},{"location":"api/","page":"API","title":"API","text":"AbstractMCMC.Sample(::AbstractRNG, ::AbstractMCMC.AbstractModel, ::AbstractMCMC.AbstractSampler)\nAbstractMCMC.Sample(::AbstractRNG, ::Any, ::AbstractMCMC.AbstractSampler)","category":"page"},{"location":"api/#AbstractMCMC.Sample-Tuple{AbstractRNG, AbstractMCMC.AbstractModel, AbstractMCMC.AbstractSampler}","page":"API","title":"AbstractMCMC.Sample","text":"Sample(\n rng::Random.AbstractRNG=Random.default_rng(),\n model::AbstractModel,\n sampler::AbstractSampler;\n kwargs...,\n)\n\nCreate a transducer that returns samples from the model with the Markov chain Monte Carlo sampler.\n\nExamples\n\njulia> struct MyModel <: AbstractMCMC.AbstractModel end\n\njulia> struct MySampler <: AbstractMCMC.AbstractSampler end\n\njulia> function AbstractMCMC.step(rng, ::MyModel, ::MySampler, state=nothing; kwargs...)\n # all samples are zero\n return 0.0, state\n end\n\njulia> transducer = Sample(MyModel(), MySampler());\n\njulia> collect(transducer(1:10)) == zeros(10)\ntrue\n\n\n\n\n\n","category":"method"},{"location":"api/#AbstractMCMC.Sample-Tuple{AbstractRNG, Any, AbstractMCMC.AbstractSampler}","page":"API","title":"AbstractMCMC.Sample","text":"Sample(\n rng::Random.AbstractRNG=Random.default_rng(),\n logdensity,\n sampler::AbstractSampler;\n kwargs...,\n)\n\nWrap the logdensity function in a LogDensityModel, and call Sample with the resulting model instead of logdensity.\n\nThe logdensity function has to support the LogDensityProblems.jl interface.\n\n\n\n\n\n","category":"method"},{"location":"api/#Sampling-multiple-chains-in-parallel","page":"API","title":"Sampling multiple chains in parallel","text":"","category":"section"},{"location":"api/","page":"API","title":"API","text":"AbstractMCMC.sample(\n ::AbstractRNG,\n ::AbstractMCMC.AbstractModel,\n ::AbstractMCMC.AbstractSampler,\n ::AbstractMCMC.AbstractMCMCEnsemble,\n ::Integer,\n ::Integer,\n)\nAbstractMCMC.sample(\n ::AbstractRNG,\n ::Any,\n ::AbstractMCMC.AbstractSampler,\n ::AbstractMCMC.AbstractMCMCEnsemble,\n ::Integer,\n ::Integer,\n)","category":"page"},{"location":"api/#StatsBase.sample-Tuple{AbstractRNG, AbstractMCMC.AbstractModel, AbstractMCMC.AbstractSampler, AbstractMCMC.AbstractMCMCEnsemble, Integer, Integer}","page":"API","title":"StatsBase.sample","text":"sample(\n rng::Random.AbstractRNG=Random.default_rng(),\n model::AbstractModel,\n sampler::AbstractSampler,\n parallel::AbstractMCMCEnsemble,\n N::Integer,\n nchains::Integer;\n kwargs...,\n)\n\nSample nchains Monte Carlo Markov chains from the model with the sampler in parallel using the parallel algorithm, and combine them into a single chain.\n\nKeyword arguments\n\nSee https://turinglang.org/AbstractMCMC.jl/dev/api/#Common-keyword-arguments for common keyword arguments.\n\n\n\n\n\n","category":"method"},{"location":"api/#StatsBase.sample-Tuple{AbstractRNG, Any, AbstractMCMC.AbstractSampler, AbstractMCMC.AbstractMCMCEnsemble, Integer, Integer}","page":"API","title":"StatsBase.sample","text":"sample(\n rng::Random.AbstractRNG=Random.default_rng(),\n logdensity,\n sampler::AbstractSampler,\n parallel::AbstractMCMCEnsemble,\n N::Integer,\n nchains::Integer;\n kwargs...,\n)\n\nWrap the logdensity function in a LogDensityModel, and call sample with the resulting model instead of logdensity.\n\nThe logdensity function has to support the LogDensityProblems.jl interface.\n\n\n\n\n\n","category":"method"},{"location":"api/","page":"API","title":"API","text":"Two algorithms are provided for parallel sampling with multiple threads and multiple processes, and one allows for the user to sample multiple chains in serial (no parallelization):","category":"page"},{"location":"api/","page":"API","title":"API","text":"AbstractMCMC.MCMCThreads\nAbstractMCMC.MCMCDistributed\nAbstractMCMC.MCMCSerial","category":"page"},{"location":"api/#AbstractMCMC.MCMCThreads","page":"API","title":"AbstractMCMC.MCMCThreads","text":"MCMCThreads\n\nThe MCMCThreads algorithm allows users to sample MCMC chains in parallel using multiple threads.\n\n\n\n\n\n","category":"type"},{"location":"api/#AbstractMCMC.MCMCDistributed","page":"API","title":"AbstractMCMC.MCMCDistributed","text":"MCMCDistributed\n\nThe MCMCDistributed algorithm allows users to sample MCMC chains in parallel using multiple processes.\n\n\n\n\n\n","category":"type"},{"location":"api/#AbstractMCMC.MCMCSerial","page":"API","title":"AbstractMCMC.MCMCSerial","text":"MCMCSerial\n\nThe MCMCSerial algorithm allows users to sample serially, with no thread or process parallelism.\n\n\n\n\n\n","category":"type"},{"location":"api/#Common-keyword-arguments","page":"API","title":"Common keyword arguments","text":"","category":"section"},{"location":"api/","page":"API","title":"API","text":"Common keyword arguments for regular and parallel sampling are:","category":"page"},{"location":"api/","page":"API","title":"API","text":"progress (default: AbstractMCMC.PROGRESS[] which is true initially): toggles progress logging\nchain_type (default: Any): determines the type of the returned chain\ncallback (default: nothing): if callback !== nothing, then callback(rng, model, sampler, sample, iteration) is called after every sampling step, where sample is the most recent sample of the Markov chain and iteration is the current iteration\nnum_warmup (default: 0): number of \"warm-up\" steps to take before the first \"regular\" step, i.e. number of times to call AbstractMCMC.step_warmup before the first call to AbstractMCMC.step.\ndiscard_initial (default: num_warmup): number of initial samples that are discarded. Note that if discard_initial < num_warmup, warm-up samples will also be included in the resulting samples.\nthinning (default: 1): factor by which to thin samples.\ninitial_state (default: nothing): if initial_state !== nothing, the first call to AbstractMCMC.step is passed initial_state as the state argument.","category":"page"},{"location":"api/","page":"API","title":"API","text":"info: Info\nThe common keyword arguments progress, chain_type, and callback are not supported by the iterator AbstractMCMC.steps and the transducer AbstractMCMC.Sample.","category":"page"},{"location":"api/","page":"API","title":"API","text":"There is no \"official\" way for providing initial parameter values yet. However, multiple packages such as EllipticalSliceSampling.jl and AdvancedMH.jl support an initial_params keyword argument for setting the initial values when sampling a single chain. To ensure that sampling multiple chains \"just works\" when sampling of a single chain is implemented, we decided to support initial_params in the default implementations of the ensemble methods:","category":"page"},{"location":"api/","page":"API","title":"API","text":"initial_params (default: nothing): if initial_params isa AbstractArray, then the ith element of initial_params is used as initial parameters of the ith chain. If one wants to use the same initial parameters x for every chain, one can specify e.g. initial_params = FillArrays.Fill(x, N).","category":"page"},{"location":"api/","page":"API","title":"API","text":"Progress logging can be enabled and disabled globally with AbstractMCMC.setprogress!(progress).","category":"page"},{"location":"api/","page":"API","title":"API","text":"AbstractMCMC.setprogress!","category":"page"},{"location":"api/#AbstractMCMC.setprogress!","page":"API","title":"AbstractMCMC.setprogress!","text":"setprogress!(progress::Bool; silent::Bool=false)\n\nEnable progress logging globally if progress is true, and disable it otherwise. Optionally disable informational message if silent is true.\n\n\n\n\n\n","category":"function"},{"location":"api/#Chains","page":"API","title":"Chains","text":"","category":"section"},{"location":"api/","page":"API","title":"API","text":"The chain_type keyword argument allows to set the type of the returned chain. A common choice is to return chains of type Chains from MCMCChains.jl.","category":"page"},{"location":"api/","page":"API","title":"API","text":"AbstractMCMC defines the abstract type AbstractChains for Markov chains.","category":"page"},{"location":"api/","page":"API","title":"API","text":"AbstractMCMC.AbstractChains","category":"page"},{"location":"api/#AbstractMCMC.AbstractChains","page":"API","title":"AbstractMCMC.AbstractChains","text":"AbstractChains\n\nAbstractChains is an abstract type for an object that stores parameter samples generated through a MCMC process.\n\n\n\n\n\n","category":"type"},{"location":"api/","page":"API","title":"API","text":"For chains of this type, AbstractMCMC defines the following two methods.","category":"page"},{"location":"api/","page":"API","title":"API","text":"AbstractMCMC.chainscat\nAbstractMCMC.chainsstack","category":"page"},{"location":"api/#AbstractMCMC.chainscat","page":"API","title":"AbstractMCMC.chainscat","text":"chainscat(c::AbstractChains...)\n\nConcatenate multiple chains.\n\nBy default, the chains are concatenated along the third dimension by calling cat(c...; dims=3).\n\n\n\n\n\n","category":"function"},{"location":"api/#AbstractMCMC.chainsstack","page":"API","title":"AbstractMCMC.chainsstack","text":"chainsstack(c::AbstractVector)\n\nStack chains in c.\n\nBy default, the vector of chains is returned unmodified. If eltype(c) <: AbstractChains, then reduce(chainscat, c) is called.\n\n\n\n\n\n","category":"function"},{"location":"api/#Interacting-with-states-of-samplers","page":"API","title":"Interacting with states of samplers","text":"","category":"section"},{"location":"api/","page":"API","title":"API","text":"To make it a bit easier to interact with some arbitrary sampler state, we encourage implementations of AbstractSampler to implement the following methods:","category":"page"},{"location":"api/","page":"API","title":"API","text":"AbstractMCMC.getparams\nAbstractMCMC.setparams!!","category":"page"},{"location":"api/#AbstractMCMC.getparams","page":"API","title":"AbstractMCMC.getparams","text":"getparams([model::AbstractModel, ]state)\n\nRetrieve the values of parameters from the sampler's state as a Vector{<:Real}.\n\n\n\n\n\n","category":"function"},{"location":"api/#AbstractMCMC.setparams!!","page":"API","title":"AbstractMCMC.setparams!!","text":"setparams!!([model::AbstractModel, ]state, params)\n\nSet the values of parameters in the sampler's state from a Vector{<:Real}. \n\nThis function should follow the BangBang interface: mutate state in-place if possible and return the mutated state. Otherwise, it should return a new state containing the updated parameters.\n\nAlthough not enforced, it should hold that setparams!!(state, getparams(state)) == state. In other words, the sampler should implement a consistent transformation between its internal representation and the vector representation of the parameter values.\n\nSometimes, to maintain the consistency of the log density and parameter values, a model should be provided. This is useful for samplers that need to evaluate the log density at the new parameter values.\n\n\n\n\n\n","category":"function"},{"location":"api/","page":"API","title":"API","text":"getparams and setparams!! provide a generic interface for interacting with the parameters of a sampler's state, regardless of how that state is represented internally.","category":"page"},{"location":"api/","page":"API","title":"API","text":"This allows generic code to be written that works with any sampler implementing this interface. For example, a generic ensemble sampler could use getparams to extract the parameters from each of its component samplers' states, and setparams!! to initialize each component sampler with a different set of parameters.","category":"page"},{"location":"api/","page":"API","title":"API","text":"The optional model argument to these functions allows sampler implementations to customize their behavior based on the model being used. For example, some samplers may need to evaluate the log density at new parameter values when setting parameters, which requires access to the model. If access to model is not needed, the sampler only needs to implement the version without the model argument - the default implementations will then call those methods directly.","category":"page"},{"location":"api/","page":"API","title":"API","text":"These methods are particularly useful for implementing samplers which wrap some inner samplers, such as a mixture of samplers. In the next section, we will see how getparams and setparams!! can be used to implement a MixtureSampler.","category":"page"},{"location":"api/#Example:-MixtureSampler","page":"API","title":"Example: MixtureSampler","text":"","category":"section"},{"location":"api/","page":"API","title":"API","text":"In a MixtureSampler we need two things:","category":"page"},{"location":"api/","page":"API","title":"API","text":"components: collection of samplers.\nweights: collection of weights representing the probability of choosing the corresponding sampler.","category":"page"},{"location":"api/","page":"API","title":"API","text":"struct MixtureSampler{W,C} <: AbstractMCMC.AbstractSampler\n components::C\n weights::W\nend","category":"page"},{"location":"api/","page":"API","title":"API","text":"To implement the state, we need to keep track of a couple of things:","category":"page"},{"location":"api/","page":"API","title":"API","text":"index: the index of the sampler used in this step.\nstates: the current states of all the components.","category":"page"},{"location":"api/","page":"API","title":"API","text":"We need to keep track of the states of all components rather than just the state for the sampler we used previously. The reason is that lots of samplers keep track of more than just the previous realizations of the variables, e.g. in AdvancedHMC.jl we keep track of the momentum used, the metric used, etc.","category":"page"},{"location":"api/","page":"API","title":"API","text":"struct MixtureState{S}\n index::Int\n states::S\nend","category":"page"},{"location":"api/","page":"API","title":"API","text":"The step for a MixtureSampler is defined by the following generative process","category":"page"},{"location":"api/","page":"API","title":"API","text":"beginaligned\ni sim mathrmCategorical(w_1 dots w_k) \nX_t sim mathcalK_i(cdot mid X_t - 1)\nendaligned","category":"page"},{"location":"api/","page":"API","title":"API","text":"where mathcalK_i denotes the i-th kernel/sampler, and w_i denotes the weight/probability of choosing the i-th sampler. AbstractMCMC.getparams and AbstractMCMC.setparams!! comes into play in defining/computing mathcalK_i(cdot mid X_t - 1) since X_t - 1 could be coming from a different sampler.","category":"page"},{"location":"api/","page":"API","title":"API","text":"If we let state be the current MixtureState, i the current component, and i_prev is the previous component we sampled from, then this translates into the following piece of code:","category":"page"},{"location":"api/","page":"API","title":"API","text":"# Update the corresponding state, i.e. `state.states[i]`, using\n# the state and transition from the previous iteration.\nstate_current = AbstractMCMC.setparams!!(\n state.states[i], \n AbstractMCMC.getparams(state.states[i_prev]),\n)\n\n# Take a `step` for this sampler using the updated state.\ntransition, state_current = AbstractMCMC.step(\n rng, model, sampler_current, sampler_state;\n kwargs...\n)","category":"page"},{"location":"api/","page":"API","title":"API","text":"The full AbstractMCMC.step implementation would then be something like:","category":"page"},{"location":"api/","page":"API","title":"API","text":"function AbstractMCMC.step(rng, model::AbstractMCMC.AbstractModel, sampler::MixtureSampler, state; kwargs...)\n # Sample the component to use in this `step`.\n i = rand(Categorical(sampler.weights))\n sampler_current = sampler.components[i]\n\n # Update the corresponding state, i.e. `state.states[i]`, using\n # the state and transition from the previous iteration.\n i_prev = state.index\n state_current = AbstractMCMC.setparams!!( \n state.states[i], \n AbstractMCMC.getparams(state.states[i_prev]), \n )\n\n # Take a `step` for this sampler using the updated state.\n transition, state_current = AbstractMCMC.step(\n rng, model, sampler_current, state_current;\n kwargs...\n )\n\n # Create the new states.\n # NOTE: Code below will result in `states_new` being a `Vector`.\n # If we wanted to allow usage of alternative containers, e.g. `Tuple`,\n # it would be better to use something like `@set states[i] = state_current`\n # where `@set` is from Setfield.jl.\n states_new = map(1:length(state.states)) do j\n if j == i\n # Replace the i-th state with the new one.\n state_current\n else\n # Otherwise we just carry over the previous ones.\n state.states[j]\n end\n end\n\n # Create the new `MixtureState`.\n state_new = MixtureState(i, states_new)\n\n return transition, state_new\nend","category":"page"},{"location":"api/","page":"API","title":"API","text":"And for the initial AbstractMCMC.step we have:","category":"page"},{"location":"api/","page":"API","title":"API","text":"function AbstractMCMC.step(rng, model::AbstractMCMC.AbstractModel, sampler::MixtureSampler; kwargs...)\n # Initialize every state.\n transitions_and_states = map(sampler.components) do spl\n AbstractMCMC.step(rng, model, spl; kwargs...)\n end\n\n # Sample the component to use this `step`.\n i = rand(Categorical(sampler.weights))\n # Extract the corresponding transition.\n transition = first(transitions_and_states[i])\n # Extract states.\n states = map(last, transitions_and_states)\n # Create new `MixtureState`.\n state = MixtureState(i, states)\n\n return transition, state\nend","category":"page"},{"location":"api/","page":"API","title":"API","text":"Suppose we then wanted to use this with some of the packages which implements AbstractMCMC.jl's interface, e.g. AdvancedMH.jl, then we'd simply have to implement getparams and setparams!!.","category":"page"},{"location":"api/","page":"API","title":"API","text":"To use MixtureSampler with two samplers sampler1 and sampler2 from AdvancedMH.jl as components, we'd simply do","category":"page"},{"location":"api/","page":"API","title":"API","text":"sampler = MixtureSampler([sampler1, sampler2], [0.1, 0.9])\ntransition, state = AbstractMCMC.step(rng, model, sampler)\nwhile ...\n transition, state = AbstractMCMC.step(rng, model, sampler, state)\nend","category":"page"},{"location":"design/#Design","page":"Design","title":"Design","text":"","category":"section"},{"location":"design/","page":"Design","title":"Design","text":"This page explains the default implementations and design choices of AbstractMCMC. It is not intended for users but for developers that want to implement the AbstractMCMC interface for Markov chain Monte Carlo sampling. The user-facing API is explained in API.","category":"page"},{"location":"design/#Overview","page":"Design","title":"Overview","text":"","category":"section"},{"location":"design/","page":"Design","title":"Design","text":"AbstractMCMC provides a default implementation of the user-facing interface described in API. You can completely neglect these and define your own implementation of the interface. However, as described below, in most use cases the default implementation allows you to obtain support of parallel sampling, progress logging, callbacks, iterators, and transducers for free by just defining the sampling step of your inference algorithm, drastically reducing the amount of code you have to write. In general, the docstrings of the functions described below might be helpful if you intend to make use of the default implementations.","category":"page"},{"location":"design/#Basic-structure","page":"Design","title":"Basic structure","text":"","category":"section"},{"location":"design/","page":"Design","title":"Design","text":"The simplified structure for regular sampling (the actual implementation contains some additional error checks and support for progress logging and callbacks) is","category":"page"},{"location":"design/","page":"Design","title":"Design","text":"StatsBase.sample(\n rng::Random.AbstractRNG,\n model::AbstractMCMC.AbstractModel,\n sampler::AbstractMCMC.AbstractSampler,\n nsamples::Integer;\n chain_type = ::Type{Any},\n kwargs...\n)\n # Obtain the initial sample and state.\n sample, state = AbstractMCMC.step(rng, model, sampler; kwargs...)\n\n # Save the sample.\n samples = AbstractMCMC.samples(sample, model, sampler, N; kwargs...)\n samples = AbstractMCMC.save!!(samples, sample, 1, model, sampler, N; kwargs...)\n\n # Step through the sampler.\n for i in 2:N\n # Obtain the next sample and state.\n sample, state = AbstractMCMC.step(rng, model, sampler, state; kwargs...)\n\n # Save the sample.\n samples = AbstractMCMC.save!!(samples, sample, i, model, sampler, N; kwargs...)\n end\n\n return AbstractMCMC.bundle_samples(samples, model, sampler, state, chain_type; kwargs...)\nend","category":"page"},{"location":"design/","page":"Design","title":"Design","text":"All other default implementations make use of the same structure and in particular call the same methods.","category":"page"},{"location":"design/#Sampling-step","page":"Design","title":"Sampling step","text":"","category":"section"},{"location":"design/","page":"Design","title":"Design","text":"The only method for which no default implementation is provided (and hence which downstream packages have to implement) is AbstractMCMC.step. It defines the sampling step of the inference method.","category":"page"},{"location":"design/","page":"Design","title":"Design","text":"AbstractMCMC.step","category":"page"},{"location":"design/#AbstractMCMC.step","page":"Design","title":"AbstractMCMC.step","text":"step(rng, model, sampler[, state; kwargs...])\n\nReturn a 2-tuple of the next sample and the next state of the MCMC sampler for model.\n\nSamples describe the results of a single step of the sampler. As an example, a sample might include a vector of parameters sampled from a prior distribution.\n\nWhen sampling using sample, every step call after the first has access to the current state of the sampler.\n\n\n\n\n\n","category":"function"},{"location":"design/","page":"Design","title":"Design","text":"If one also has some special handling of the warmup-stage of sampling, then this can be specified by overloading","category":"page"},{"location":"design/","page":"Design","title":"Design","text":"AbstractMCMC.step_warmup","category":"page"},{"location":"design/#AbstractMCMC.step_warmup","page":"Design","title":"AbstractMCMC.step_warmup","text":"step_warmup(rng, model, sampler[, state; kwargs...])\n\nReturn a 2-tuple of the next sample and the next state of the MCMC sampler for model.\n\nWhen sampling using sample, this takes the place of AbstractMCMC.step in the first num_warmup number of iterations, as specified by the num_warmup keyword to sample. This is useful if the sampler has an initial \"warmup\"-stage that is different from the standard iteration.\n\nBy default, this simply calls AbstractMCMC.step.\n\n\n\n\n\n","category":"function"},{"location":"design/","page":"Design","title":"Design","text":"which will be used for the first num_warmup iterations, as specified as a keyword argument to AbstractMCMC.sample. Note that this is optional; by default it simply calls AbstractMCMC.step from above.","category":"page"},{"location":"design/#Collecting-samples","page":"Design","title":"Collecting samples","text":"","category":"section"},{"location":"design/","page":"Design","title":"Design","text":"note: Note\nThis section does not apply to the iterator and transducer interface.","category":"page"},{"location":"design/","page":"Design","title":"Design","text":"After the initial sample is obtained, the default implementations for regular and parallel sampling (not for the iterator and the transducer since it is not needed there) create a container for all samples (the initial one and all subsequent samples) using AbstractMCMC.samples.","category":"page"},{"location":"design/","page":"Design","title":"Design","text":"AbstractMCMC.samples","category":"page"},{"location":"design/#AbstractMCMC.samples","page":"Design","title":"AbstractMCMC.samples","text":"samples(sample, model, sampler[, N; kwargs...])\n\nGenerate a container for the samples of the MCMC sampler for the model, whose first sample is sample.\n\nThe method can be called with and without a predefined number N of samples.\n\n\n\n\n\n","category":"function"},{"location":"design/","page":"Design","title":"Design","text":"In each step, the sample is saved in the container by AbstractMCMC.save!!. The notation !! follows the convention of the package BangBang.jl which is used in the default implementation of AbstractMCMC.save!!. It indicates that the sample is pushed to the container but a \"widening\" fallback is used if the container type does not allow to save the sample. Therefore AbstractMCMC.save!! always has to return the container.","category":"page"},{"location":"design/","page":"Design","title":"Design","text":"AbstractMCMC.save!!","category":"page"},{"location":"design/#AbstractMCMC.save!!","page":"Design","title":"AbstractMCMC.save!!","text":"save!!(samples, sample, iteration, model, sampler[, N; kwargs...])\n\nSave the sample of the MCMC sampler at the current iteration in the container of samples.\n\nThe function can be called with and without a predefined number N of samples. By default, AbstractMCMC uses push!! from the Julia package BangBang to append to the container, and widen its type if needed.\n\n\n\n\n\n","category":"function"},{"location":"design/","page":"Design","title":"Design","text":"For most use cases the default implementation of AbstractMCMC.samples and AbstractMCMC.save!! should work out of the box and hence need not to be overloaded in downstream code.","category":"page"},{"location":"design/#Creating-chains","page":"Design","title":"Creating chains","text":"","category":"section"},{"location":"design/","page":"Design","title":"Design","text":"note: Note\nThis section does not apply to the iterator and transducer interface.","category":"page"},{"location":"design/","page":"Design","title":"Design","text":"At the end of the sampling procedure for regular and paralle sampling we transform the collection of samples to the desired output type by calling AbstractMCMC.bundle_samples.","category":"page"},{"location":"design/","page":"Design","title":"Design","text":"AbstractMCMC.bundle_samples","category":"page"},{"location":"design/#AbstractMCMC.bundle_samples","page":"Design","title":"AbstractMCMC.bundle_samples","text":"bundle_samples(samples, model, sampler, state, chain_type[; kwargs...])\n\nBundle all samples that were sampled from the model with the given sampler in a chain.\n\nThe final state of the sampler can be included in the chain. The type of the chain can be specified with the chain_type argument.\n\nBy default, this method returns samples.\n\n\n\n\n\n","category":"function"},{"location":"design/","page":"Design","title":"Design","text":"The default implementation should be fine in most use cases, but downstream packages could, e.g., save the final state of the sampler as well if they overload AbstractMCMC.bundle_samples.","category":"page"},{"location":"#AbstractMCMC.jl","page":"Home","title":"AbstractMCMC.jl","text":"","category":"section"},{"location":"","page":"Home","title":"Home","text":"Abstract types and interfaces for Markov chain Monte Carlo methods.","category":"page"},{"location":"","page":"Home","title":"Home","text":"AbstractMCMC defines an interface for sampling and combining Markov chains. It comes with a default sampling algorithm that provides support of progress bars, parallel sampling (multithreaded and multicore), and user-provided callbacks out of the box. Typically developers only have to define the sampling step of their inference method in an iterator-like fashion to make use of this functionality. Additionally, the package defines an iterator and a transducer for sampling Markov chains based on the interface.","category":"page"}] }