# Transforms#

## Introduction#

Random variables in an Aesara model graph can be transformed by AePPL in multiple ways.

One way is by explicitly constructing a transform using Aesara Ops within a model graph:

A_rv = at.random.normal(0, 1.0, name="A")
Z_rv = at.exp(A_rv)
Z_rv.name = "Z"

logp, (z_vv,) = joint_logprob(Z_rv)


The resulting log-density should reflect the “change-of-variables” implied by taking the exponential of a normal random variable:

>>> print(aesara.pprint(logp))
((-0.9189385332046727 + (-0.5 * (log(Z_vv) ** 2))) + (-1.0 * log(Z_vv)))


Transforms can also be applied implicitly through the use of TransformValuesRewrite:

A_rv = at.random.normal(0, 1.0, name="A")
B_rv = at.random.normal(A_rv, 1.0, name="B")

logp, (a_vv, b_vv,) = joint_logprob(
A_rv,
B_rv,
extra_rewrites=TransformValuesRewrite(
{A_rv: ExpTransform()}
),
)


This approach will apply the designated transforms to all occurrences of their associated variables and their values:

>>> print(aesara.pprint(logp))
sum([((-0.9189385332046727 + (-0.5 * (log(A_vv-trans) ** 2))) + (-1.0 * log(A_vv-trans))),
(-0.9189385332046727 + (-0.5 * ((B_vv - log(A_vv-trans)) ** 2)))], axis=None)


## TransformValuesRewrite#

class aeppl.transforms.TransformValuesRewrite(rvs_to_transforms)[source]#

Transforms measurable variables.

This transformation can be used to replace all occurrences of a measurable variable and its values within a model graph with a transformed version of itself (e.g. for the purposes of sampling on “unconstrained” ranges).

Example

A_rv = at.random.normal(0, 1.0, name="A")
B_rv = at.random.normal(A_rv, 1.0, name="B")

logp, (a_vv, b_vv) = joint_logprob(
A_rv,
B_rv,
extra_rewrites=TransformValuesRewrite(
{A_rv: ExpTransform()}
),
)

>>> print(aesara.pprint(logp))
sum([((-0.9189385332046727 + (-0.5 * (log(A_vv-trans) ** 2))) + (-1.0 * log(A_vv-trans))),
(-0.9189385332046727 + (-0.5 * ((B_vv - log(A_vv-trans)) ** 2)))], axis=None)

Parameters:

rvs_to_transforms (Dict[TensorVariable, Union[RVTransform, DefaultTransformSentinel, None]]) –

## Invertible transforms#

AePPL currently supports transforms using the following (invertible) Aesara operators. This means that AePPL can compute the log-probability of a random variable that is the result of one of the following transformations applied to another random variable:

• aesara.tensor.add

• aesara.tensor.sub

• aesara.tensor.mul

• aesara.tensor.true_divide

• aesara.tensor.exponential

• aesara.tensor.exp

• aesara.tensor.log

One can also apply the following transforms directly:

class aeppl.transforms.LocTransform(transform_args_fn)[source]#
class aeppl.transforms.ScaleTransform(transform_args_fn)[source]#
class aeppl.transforms.LogTransform[source]#
class aeppl.transforms.ExpTransform[source]#
class aeppl.transforms.ReciprocalTransform[source]#
class aeppl.transforms.IntervalTransform(args_fn)[source]#
Parameters:
class aeppl.transforms.LogOddsTransform[source]#
class aeppl.transforms.SimplexTransform[source]#
class aeppl.transforms.CircularTransform[source]#

These transformations can be chained using:

class aeppl.transforms.ChainedTransform(transform_list, base_op)[source]#

## Censoring#

AePPL can compute the log-density of aesara.tensor.clip applied to a random variable:

aeppl.censoring.clip_logprob(op, values, base_rv, lower_bound, upper_bound, **kwargs)[source]#

Logprob of a clipped censored distribution

The probability is given by

$\begin{split}\begin{cases} 0 & \text{for } x < lower, \\ \text{CDF}(lower, dist) & \text{for } x = lower, \\ \text{P}(x, dist) & \text{for } lower < x < upper, \\ 1-\text{CDF}(upper, dist) & \text {for} x = upper, \\ 0 & \text{for } x > upper, \end{cases}\end{split}$

## Rounding#

AePPL can compute the log-density of aesara.tensor.ceil, aesara.tensor.floor, or aesara.tensor.round_half_to_even applied to a random variable:

aeppl.censoring.round_logprob(op, values, base_rv, **kwargs)[source]#

Logprob of a rounded censored distribution

The probability of a distribution rounded to the nearest integer is given by

$\begin{split}\begin{cases} \text{CDF}(x+\frac{1}{2}, dist) - \text{CDF}(x-\frac{1}{2}, dist) & \text{for } x \in \mathbb{Z}, \\ 0 & \text{otherwise}, \end{cases}\end{split}$

The probability of a distribution rounded up is given by

$\begin{split}\begin{cases} \text{CDF}(x, dist) - \text{CDF}(x-1, dist) & \text{for } x \in \mathbb{Z}, \\ 0 & \text{otherwise}, \end{cases}\end{split}$

The probability of a distribution rounded down is given by

$\begin{split}\begin{cases} \text{CDF}(x+1, dist) - \text{CDF}(x, dist) & \text{for } x \in \mathbb{Z}, \\ 0 & \text{otherwise}, \end{cases}\end{split}$