Mutation

Functions that mutate probability expressions.

canonicalize(expression: Expression, ordering: Sequence[str | Variable] | None = None) Expression[source]

Canonicalize an expression that meets the markov condition with respect to the given ordering.

Parameters:
  • expression – An expression to canonicalize

  • ordering – A toplogical ordering. If none is given, it is assigned by sort order of the variable names.

Returns:

A canonical expression

canonical_expr_equal(left: Expression, right: Expression) bool[source]

Return True if two expressions are equal after canonicalization.

chain_expand(p: Probability, *, reorder: bool = True, ordering: Iterable[str | Variable] | None = None) Expression[source]

Expand a probability distribution to a product of conditional probabilities on single variables.

Parameters:
  • p – The given probability expression

  • reorder – Should the variables be reordered with respect to the ordering before expanding? This is important because there are a variety of equivalent expressions that can’t be directly matched.

  • ordering – An ordering to be used if reorder is true. If none, automatically generates a canonical ordering using y0.dsl.ensure_ordering().

Returns:

A product representing the expanded distribution, in which each probability term is a markov kernel

Raises:

ValueError – if the ordering is passed explicitly and it does not cover all variables

Two variables:

\[P(X,Y)=P(X|Y)*P(Y)\]
>>> from y0.dsl import P, X, Y
>>> assert chain_expand(P(X, Y)) == P(X | Y) * P(Y)

The recurrence relation for many variables is defined as:

\[P(X_n,\dots,X_1) = P(X_n|X_{n-1},\dots,X_1) \times P(X_{n-1},\dots,X_1)\]
>>> from y0.dsl import P, A, X, Y, Z
>>> assert chain_expand(P(X, Y, Z)) == P(X | Y, Z) * P(Y | Z) * P(Z)

Extra conditions come along for the ride.

>>> assert chain_expand(P(X, Y, Z | A)) == P(X | Y, Z, A) * P(Y | Z, A) * P(Z | A)
fraction_expand(p: Probability) Expression[source]

Expand a probability distribution with fractions.

Parameters:

p – The given probability expression

Returns:

A fraction representing the joint distribution

The simple case has one child variable (\(A\)) and one parent variable (\(B\)):

\[P(A | B) = \frac{P(A,B)}{P(B)}\]
>>> from y0.dsl import P, A, B, Sum
>>> from y0.mutate.chain import fraction_expand
>>> assert fraction_expand(P(A | B)) == P(A, B) / P(B)

If there are no conditions (i.e., parents), then the probability is returned without modification.

>>> assert fraction_expand(P(A, B)) == P(A, B)

In general, with many children \(Y_i\) and many parents \(X_i\):

\[P(Y_1,\dots,Y_n | X_1, \dots, X_m) = \frac{P(Y_1,\dots,Y_n,X_1,\dots,X_m)}{P(X_1,\dots,X_m)}\]
bayes_expand(p: Probability) Expression[source]

Expand a probability distribution using Bayes’ theorem.

Parameters:

p – The given probability expression, with arbitrary number of children and parents

Returns:

A fraction representing the joint distribution

\[P(Y_1,\dots,Y_n|X_1,\dots,X_m) = \frac{P(Y_1,\dots,Y_n,X_1,\dots,X_m)}{\sum_{Y_1,\dots,Y_n} P(Y_1,\dots,Y_n,X_1,\dots,X_m)}\]
>>> from y0.dsl import P, A, B, C, Sum
>>> from y0.mutate.chain import bayes_expand
>>> assert bayes_expand(P(A | B)) == P(A, B) / Sum[A](P(A, B)

If there are no conditions (i.e., parents), then the probability is returned without modification.

>>> assert bayes_expand(P(A, B)) == P(A, B)

Note

This expansion will create a different but equal expression to fraction_expand().