# Representing Probability Distributions¶

## Introduction¶

Probability distributions such as prior distributions over model parameters
are reprented in QInfer by objects of type `Distribution`

that are
responsible for producing samples according to those distributions. This is
especially useful, for instance, when drawing initial particles for use with
an `SMCUpdater`

.

The approach to representing distributions taken by QInfer is somewhat
different to that taken by, for example, `scipy.stats`

, in that
a QInfer `Distribution`

is a class that produces samples according to
that distribution. This means that QInfer `Distribution`

objects provide much
less information than do those represented by objects in `scipy.stats`

,
but that they are much easier to write and combine.

## Sampling Pre-made Distributions¶

QInfer comes along with several distributions, listed in
Specific Distributions. Each of these is a subclass of
`Distribution`

, and hence has a method `sample()`

that produces an array of samples.

```
>>> from qinfer.distributions import NormalDistribution
>>> dist = NormalDistribution(0, 1)
>>> samples = dist.sample(n=5)
>>> print samples.shape
(5, 1)
```

## Combining Distributions¶

Distribution objects can be combined using other distribution objects. For
instance, if \(a \sim \mathcal{N}(0, 1)\) and \(b \sim \text{Uni}(0, 1)\),
then the product distribution on \((a,b)\) can be produced by using
`ProductDistribution`

:

```
>>> from qinfer.distributions import UniformDistribution, ProductDistribution
>>> a = NormalDistribution(0, 1)
>>> b = UniformDistribution([0, 1])
>>> ab = ProductDistribution(a, b)
>>> samples = ab.sample(n=5)
>>> print samples.shape
(5, 2)
```

## Making Custom Distributions¶

To make a custom distribution, one need only implement
`sample()`

and set the property `n_rvs`

to indicate how many random variables the new distribution class represents.

For example, to implement a distribution over \(x\) and \(y\) such that \(\sqrt{x^2 + y^2} \sim \mathcal{N}(1, 0.1)\) and such that the angle between \(x\) and \(y\) is drawn from \(\text{Uni}(0, 2 \pi)\):

```
import numpy as np
from qinfer.distributions import Distribution
class RingDistribution(Distribution):
@property
def n_rvs(self):
return 2
def sample(self, n=1):
r = np.random.randn(n, 1) * 0.1 + 1
th = np.random.random((n, 1)) * 2 * np.pi
x = r * np.cos(th)
y = r * np.sin(th)
return np.concatenate([x, y], axis=1)
```