Algebra

Named-variable distributions multiply and divide according to the chain rule. The free/given metadata on each operand determines the result.

Throughout, start from named xor:

In [1]: from dit import Distribution

In [2]: d = Distribution(['000', '011', '101', '110'], [1/4]*4)

In [3]: d.set_rv_names('XYZ')

Marginal and condition

marginal() keeps the listed free variables; marginalize() drops them. Both accept positional names or a single list:

In [4]: d.marginal('X', 'Y')
Out[4]: <Distribution p(X,Y)>

In [5]: d.marginalize('X', 'Y')
Out[5]: <Distribution p(Z)>

Native condition_on() takes positional variable names and returns a single conditional distribution:

In [6]: p_z_xy = d.condition_on('X', 'Y')

In [7]: p_z_xy
Out[7]: <Distribution p(Z|X,Y)>

In [8]: p_z_xy.is_conditional()
Out[8]: True

Multiplication (chain rule)

Multiplying a marginal by a compatible conditional reconstructs the joint:

\[p(X,Y) \cdot p(Z \mid X,Y) = p(X,Y,Z)\]
In [9]: p_xy = d.marginal('X', 'Y')

In [10]: rebuilt = p_xy * p_z_xy

In [11]: rebuilt
Out[11]: <Distribution p(X,Y,Z)>

In [12]: rebuilt.is_approx_equal(d)
Out[12]: True

Partial application leaves unmatched given variables given:

\[p(X) \cdot p(Z \mid X,Y) = p(X,Z \mid Y)\]
In [13]: d.marginal('X') * p_z_xy
Out[13]: <Distribution p(X,Z|Y)>

The free variables of the two operands must be disjoint. Distribution.from_factors() is the named constructor for the same product.

Division (conditioning)

Dividing a joint by a marginal conditions on the marginal’s free variables:

\[p(X,Y) / p(X) = p(Y \mid X)\]
In [14]: p_xy / d.marginal('X')
Out[14]: <Distribution p(Y|X)>

Numeric-outcome * is different

On unnamed one-dimensional numeric distributions, +, *, %, and friends transform outcomes (two dice, scaling a die, …). See Numeric Outcomes. Named-variable * is always the chain rule.

Compatibility condition_on

Passing a list, or the crvs / rvs keywords, uses the older dit-compatible return format (marginal, list_of_slices) — one distribution per outcome of the conditioning variables. Prefer the native form above; the tuple form is still used by some algorithms.

In [15]: marg, cdists = d.condition_on(['X', 'Y'], rvs=['Z'])

In [16]: marg
Out[16]: <Distribution p(X,Y)>

In [17]: len(cdists)
Out[17]: 4

API

Distribution.marginal(*args)[source]

Marginalise to keep only the specified free variables.

Given (conditioned) variables are always kept.

Supports two call signatures:

  • marginal('X', 'Y') – positional variable names

  • marginal(['X', 'Y']) – list of names (or integer indices)

Parameters:

*args (str, or a single list/tuple) – The free variable names to keep. Integer indices are auto-resolved to dimension names.

Returns:

result

Return type:

Distribution

Distribution.marginalize(*args)[source]

Marginalise out (remove) the specified free variables.

Supports two call signatures:

  • marginalize('X') – positional variable names

  • marginalize(['X']) – list of names (or integer indices)

Parameters:

*args (str, or a single list/tuple) – The free variable names to remove.

Returns:

result

Return type:

Distribution

Distribution.condition_on(*cond_vars, rvs=None, crvs=None)[source]

Condition on the specified free variables.

Supports two call signatures:

  • Native: condition_on('X', 'Y') – positional var names. Returns a single conditional Distribution.

  • dit-compat: any of these forms triggers the dit-compatible return format (marginal, list_of_conditionals):

    • condition_on(crvs=['X'], rvs=['Y'])

    • condition_on(['X'], rvs=['Y']) (positional crvs)

    • condition_on(crvs=['X'])

    The returned list contains one Distribution per outcome of the conditioning variable.

Parameters:
  • *cond_vars (str, or a single list/tuple) – Variable names to condition on. If a single list/tuple is passed and rvs is provided, it is interpreted as crvs (dit-compat positional form).

  • rvs (list, optional) – Variables to keep in the conditional (dit-compat API).

  • crvs (list, optional) – Variables to condition on (dit-compat API).

Returns:

result – A single conditional distribution (native), or a (marginal, list_of_Distributions) tuple (dit-compat).

Return type:

Distribution or tuple

Examples

>>> p_xyz.condition_on('Z')   # native: returns p(X,Y|Z)
>>> p_xyz.condition_on('X', 'Y')  # native: returns p(Z|X,Y)
>>> marg, cdists = p_xyz.condition_on(crvs=['Z'])  # dit-compat
>>> marg, cdists = p_xyz.condition_on(['Z'], rvs=['X'])  # dit-compat
Distribution.coalesce(rvs, extract=False)[source]

Return a new distribution after coalescing random variables.

Each inner sequence in rvs defines one new random variable as a combination of original variables. The result is a joint Distribution over len(rvs) new random variables whose outcomes are tuples (or the inner values when extract=True with a single group).

Parameters:
  • rvs (sequence of sequences) – Each inner sequence contains variable names (or integer indices).

  • extract (bool) – If True and len(rvs) == 1, the single group’s values are used directly as outcomes instead of being wrapped in 1-tuples.

Returns:

d

Return type:

Distribution