# Type Hierarchy

All samplers and distributions provided in this package are organized into a type hierarchy described as follows.

## Sampleable

The root of this type hierarchy is `Sampleable`

. The abstract type `Sampleable`

subsumes any types of objects from which one can draw samples, which particularly includes *samplers* and *distributions*. Formally, `Sampleable`

is defined as

`abstract type Sampleable{F<:VariateForm,S<:ValueSupport} end`

It has two type parameters that define the kind of samples that can be drawn therefrom.

### VariateForm

`F <: VariateForm`

specifies the form of the variate, which can be one of the following:

Type | A single sample | Multiple samples |
---|---|---|

`Univariate` | a scalar number | A numeric array of arbitrary shape, each element being a sample |

`Multivariate` | a numeric vector | A matrix, each column being a sample |

`Matrixvariate` | a numeric matrix | An array of matrices, each element being a sample matrix |

### ValueSupport

`S <: ValueSupport`

specifies the support of sample elements, which can be either of the following:

Type | Element type | Descriptions |
---|---|---|

`Discrete` | `Int` | Samples take discrete values |

`Continuous` | `Float64` | Samples take continuous real values |

Multiple samples are often organized into an array, depending on the variate form.

The basic functionalities that a sampleable object provides is to *retrieve information about the samples it generates* and to *draw samples*. Particularly, the following functions are provided for sampleable objects:

`Base.length`

— Method.`length(s::Sampleable)`

The length of each sample. Always returns `1`

when `s`

is univariate.

`Base.size`

— Method.`size(s::Sampleable)`

The size (i.e. shape) of each sample. Always returns `()`

when `s`

is univariate, and `(length(s),)`

when `s`

is multivariate.

`Distributions.nsamples`

— Method.`nsamples(s::Sampleable)`

The number of values contained in one sample of `s`

. Multiple samples are often organized into an array, depending on the variate form.

`Base.eltype`

— Method.`eltype(s::Sampleable)`

The default element type of a sample. This is the type of elements of the samples generated by the `rand`

method. However, one can provide an array of different element types to store the samples using `rand!`

.

`Base.rand`

— Method.`rand(s::Sampleable)`

Generate one sample for `s`

.

`rand(s::Sampleable, n::Int)`

Generate `n`

samples from `s`

. The form of the returned object depends on the variate form of `s`

:

- When
`s`

is univariate, it returns a vector of length`n`

. - When
`s`

is multivariate, it returns a matrix with`n`

columns. - When
`s`

is matrix-variate, it returns an array, where each element is a sample matrix.

`Random.rand!`

— Method.`rand!(s::Sampleable, A::AbstractArray)`

Generate one or multiple samples from `s`

to a pre-allocated array `A`

. `A`

should be in the form as specified above. The rules are summarized as below:

- When
`s`

is univariate,`A`

can be an array of arbitrary shape. Each element of`A`

will be overriden by one sample. - When
`s`

is multivariate,`A`

can be a vector to store one sample, or a matrix with each column for a sample. - When
`s`

is matrix-variate,`A`

can be a matrix to store one sample, or an array of matrices with each element for a sample matrix.

## Distributions

We use `Distribution`

, a subtype of `Sampleable`

as defined below, to capture probabilistic distributions. In addition to being sampleable, a *distribution* typically comes with an explicit way to combine its domain, probability density functions, among many other quantities.

`abstract type Distribution{F<:VariateForm,S<:ValueSupport} <: Sampleable{F,S} end`

To simplify the use in practice, we introduce a series of type alias as follows:

```
const UnivariateDistribution{S<:ValueSupport} = Distribution{Univariate,S}
const MultivariateDistribution{S<:ValueSupport} = Distribution{Multivariate,S}
const MatrixDistribution{S<:ValueSupport} = Distribution{Matrixvariate,S}
const NonMatrixDistribution = Union{UnivariateDistribution, MultivariateDistribution}
const DiscreteDistribution{F<:VariateForm} = Distribution{F,Discrete}
const ContinuousDistribution{F<:VariateForm} = Distribution{F,Continuous}
const DiscreteUnivariateDistribution = Distribution{Univariate, Discrete}
const ContinuousUnivariateDistribution = Distribution{Univariate, Continuous}
const DiscreteMultivariateDistribution = Distribution{Multivariate, Discrete}
const ContinuousMultivariateDistribution = Distribution{Multivariate, Continuous}
const DiscreteMatrixDistribution = Distribution{Matrixvariate, Discrete}
const ContinuousMatrixDistribution = Distribution{Matrixvariate, Continuous}
```

All methods applicable to `Sampleable`

also applies to `Distribution`

. The API for distributions of different variate forms are different (refer to univariates, multivariates, and matrix for details).