Baytes.jl is a sampling library to perform Markov Chain and Sequential Monte Carlo proposal steps. It consists of several sub-libraries, such as BaytesMCMC.jl, BaytesFilters.jl, BaytesPMCMC.jl and BaytesSMC.jl, and provides an interface to combine kernels from these libraries.

In order to start, we have to define parameter and an objective function first. Let us use the model initially defined in the ModelWrappers.jl introduction:

```
using ModelWrappers, Baytes
using Distributions, Random, UnPack
_rng = Random.GLOBAL_RNG
#Create initial model and data
myparameter = (μ = Param(Normal(), 2.0), σ = Param(Gamma(), 3.0))
mymodel = ModelWrapper(myparameter)
data = randn(1000)
#Create objective for both μ and σ and define a target function for it
myobjective = Objective(mymodel, data, (:μ, :σ))
function (objective::Objective{<:ModelWrapper{BaseModel}})(θ::NamedTuple)
@unpack data = objective
lprior = Distributions.logpdf(Distributions.Normal(),θ.μ) + Distributions.logpdf(Distributions.Exponential(), θ.σ)
llik = sum(Distributions.logpdf( Distributions.Normal(θ.μ, θ.σ), data[iter] ) for iter in eachindex(data))
return lprior + llik
end
```

Sampling this model is straightforward. For instance, we can jointly estimate μ and σ via NUTS:

`trace1, algorithm1 = sample(_rng, mymodel, data, NUTS((:μ, :σ)))`

`Trace.val`

contains samples stored as `NamedTuple`

. `Trace.diagnostics`

contains diagnostics that were returned when sampling the corresponding parameter. `Trace.info`

contains useful summary information printing and summarizing the parameter estimates. `Algorithm`

returns the kernel that was used and tuned during the sampling process. Note that a new kernel is initiated for each chain separately.

Alternatively, you might want to sample parameter with different kernels. This is usually useful when working with state space models.

`trace2, algorithm2 = sample(_rng, mymodel, data, NUTS((:μ, )), Metropolis( (:σ,) ))`

Similar to other Baytes packages, sampling arguments may be tweaked via a `Default`

struct.

```
sampledefault = SampleDefault(;
dataformat=Batch(),
tempering=IterationTempering(Float64, UpdateFalse(), 1.0, 1000),
chains=4,
iterations=2000,
burnin=max(1, Int64(floor(2000/10))),
thinning = 1,
safeoutput=false,
printoutput=true,
printdefault=PrintDefault(),
report=ProgressReport(),
)
trace3, algorithm3 = sample(_rng, mymodel, data, NUTS((:μ, :σ)); default = sampledefault)
```

Note that hyperparameter that are specific to any kernel will have to be assigned in the MCMC constructor itself, i.e.:

```
mcmc4 = HMC((:μ,); proposal = ConfigProposal(; metric = MDense()), GradientBackend = :ReverseDiff,)
trace4, algorithm4 = sample(_rng, mymodel, data, mcmc4; default = sampledefault)
```

You can reuse returned `algorithm`

container to sample again with the pre-tuned kernels. In this this case, on can call `sample!`

. The information in `trace`

will assure that sampling is continued with the correct specifications. After `sample!`

is finished, a new trace is returned that contains sampling information.

```
iterations = 10^3
trace5, algorithm4 = sample!(iterations, _rng, mymodel, data, trace4, algorithm4)
```

Per default, `sample`

and `sample!`

return summary information of the chain and diagnostics using MCMCDiagnosticTools.jl, unless `printdefault = false`

. For further inference, one can manually convert `trace.val`

into a 3D-array that is compatible with MCMCChains.jl:

```
burnin = 0
thinning = 1
tagged = Tagged(mymodel, (:μ,:σ) )
tracetransform = TraceTransform(trace5, mymodel, tagged)
array_3dim = Baytes.trace_to_3DArray(trace5, tracetransform)
using MCMCChains
MCMCChains.Chains(array_3dim, trace5.info.sampling.paramnames)
```

This package is still highly experimental - suggestions and comments are always welcome!