Skip to content

Add Deterministic and Joint#70

Open
gvcallen wants to merge 2 commits into
lockwo:mainfrom
gvcallen:deterministic_and_joint
Open

Add Deterministic and Joint#70
gvcallen wants to merge 2 commits into
lockwo:mainfrom
gvcallen:deterministic_and_joint

Conversation

@gvcallen

@gvcallen gvcallen commented Apr 4, 2026

Copy link
Copy Markdown
Contributor

Adds a Deterministic (point mass) and Joint distribution over pytrees. Reference code is from distrax (Deterministic and Joint)

@gvcallen gvcallen changed the title Add deterministic and joint distributions Add Deterministic and Joint Apr 4, 2026
Deterministic places all probability mass on a single point (with an
atol/rtol tolerance window for closeness comparisons). Joint composes a
pytree of statistically independent distributions, summing
log-probabilities/entropies/KL divergences over the tree. Ported from
distrax as reference.
@gvcallen gvcallen force-pushed the deterministic_and_joint branch from c177f9a to c88707d Compare July 1, 2026 20:43
point (the `loc`).
"""

loc: Array

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can refine types?

atol: Array
rtol: Array

def __init__(self, loc: Array | float, atol: float = 0.0, rtol: float = 0.0):

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can we do with fields or would look bad here?

- `distributions`: A PyTree of `distreqx` distributions.
"""
# Ensure there is at least one distribution in the tree
leaves = jax.tree_util.tree_leaves(distributions, is_leaf=_is_dist)

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

jax.tree.

lambda dist: dist.entropy(), self.distributions, is_leaf=_is_dist
)
entropies_summed = jax.tree_util.tree_map(jnp.sum, entropies)
return jnp.sum(jnp.asarray(jax.tree_util.tree_leaves(entropies_summed)))

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this seems similar to independent which also does this reduction over leaves? return _reduce_helper(self.distribution.entropy())

what is the key distinction here between them?

@gvcallen gvcallen Jul 10, 2026

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

They are very similar, but I think the main difference is:

  • Independent treats the underlying distributions as homogeneous (e.g. all Normal) and transforms the underlying distributions as to treat the resultant event as a single concept (for example, log prob returns a single number)
  • Joint simply "groups" multiple heterogenous distributions/events (e.g. Normal, Uniform etc.) together (so you get multiple log probs representing that same event shape e.g. a pytree)

For general PyTree grouping of distributions, Joint is used (the exact converse to the Leafwise bijector) whereas to create e.g. multidimensional, independent normals you would use Independent (a distribution-specific concept).

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ah this makes sense, joint is over different distributions

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should document this more in the class docstring

lambda dist: dist.entropy(), self.distributions, is_leaf=_is_dist
)
entropies_summed = jax.tree_util.tree_map(jnp.sum, entropies)
return jnp.sum(jnp.asarray(jax.tree_util.tree_leaves(entropies_summed)))

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ah this makes sense, joint is over different distributions

lambda dist: dist.entropy(), self.distributions, is_leaf=_is_dist
)
entropies_summed = jax.tree_util.tree_map(jnp.sum, entropies)
return jnp.sum(jnp.asarray(jax.tree_util.tree_leaves(entropies_summed)))

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should document this more in the class docstring

self.atol = jnp.asarray(atol)
self.rtol = jnp.asarray(rtol)

if self.loc.ndim != 0:

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In principle this could be non scalar? we can refine the type hints/docstring to clarify either way

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants