mbi.extensions package
Submodules
mbi.extensions.message_passing module
Extension message-passing oracles with efficient constraint handling.
Alternative implementations of the Shafer-Shenoy and implicit message-passing
oracles from mbi.marginal_oracles. Key differences:
More efficient constraint handling. For deterministic (mapping) constraints, messages are routed through the constraint in O(|fine|) time via
coarsen/refineoperations, avoiding the full O(|fine| × |coarse|) potential materialization used by the core oracles.AI-written, less well-tested. These implementations were developed with AI assistance and have narrower test coverage than the core oracles. They are kept separate until they mature enough to replace the originals.
Usage:
from mbi.extensions.message_passing import shafer_shenoy, implicit
- mbi.extensions.message_passing.coarsen(factor, constraint)[source]
Log-space fine-to-coarse aggregation via segment-logsumexp.
- mbi.extensions.message_passing.default_oracle(cliques: tuple[tuple[str, ...], ...] | None = None, domain: Domain | None = None, backend: str | None = None) MarginalOracle[source]
Select the best constraint-aware oracle for the given setting.
When constraints are present, this oracle uses the extensions implementations which route messages through deterministic constraints efficiently. When no constraints are passed at call time, behavior is identical to the core
marginal_oracles.default_oracle.The selection heuristic mirrors the core oracle:
CPU:
shafer_shenoy(XLA compiler less effective on CPU).GPU/TPU, large cliques (>= 1M):
implicit.GPU/TPU, small cliques:
shafer_shenoy.
- mbi.extensions.message_passing.implicit(potentials: CliqueVector, total: float = 1, jtree: Graph | None = None, *, constraints: Sequence[Constraint] = (), contraction: Callable = <function einsum_materialized>) CliqueVector[source]
Hybrid message passing: implicit for standard cliques, SS for constraints.
Uses the memory-efficient implicit contraction for cliques that do not involve deterministic constraints, and falls back to Shafer-Shenoy style constraint routing for pure and embedded constraint cliques. General (valid/invalid) constraints are folded in as materialized potentials.
- Parameters:
potentials – The (log-space) potentials of a graphical model.
total – The normalization factor.
jtree – An optional junction tree.
constraints – Structural constraints to handle.
contraction – Contraction function for log-space sum-product.
- Returns:
The marginals of the graphical model.
- mbi.extensions.message_passing.project_to_coarse(factor, constraint)[source]
Probability-space fine-to-coarse aggregation via segment-sum.
- mbi.extensions.message_passing.refine(factor, constraint)[source]
Log-space coarse-to-fine scatter via indexing.
- mbi.extensions.message_passing.shafer_shenoy(potentials: CliqueVector, total: float = 1, jtree: Graph | None = None, constraints: Sequence[Constraint] = ()) CliqueVector[source]
Compute marginals using Shafer-Shenoy with constraint-aware shortcuts.
Deterministic (mapping) constraints are routed through efficient O(|fine|) coarsen/refine operations. General (valid/invalid) constraints are folded into potentials as materialized
-inf/0factors.- Parameters:
potentials – The (log-space) potentials of a graphical model.
total – The normalization factor.
jtree – An optional junction tree that defines the message passing order.
constraints – Structural constraints to handle.
- Returns:
The marginals of the graphical model.
mbi.extensions.mixture_of_products module
Mixture-of-products estimation for discrete distributions.
Inspired by RAP (https://arxiv.org/abs/2103.06641) and RAP^{softmax} (https://arxiv.org/abs/2106.07153). Instead of parameterizing via a graphical model with potentials, the distribution is represented as a mixture of K product distributions optimized via gradient descent with optax.
This is a cleaned-up, optimized replacement for
mbi.experimental.mixture_of_products.
- class mbi.extensions.mixture_of_products.MixtureOfProducts(_logits: dict[str | int, Array], domain: Domain, total: float)[source]
Bases:
objectA discrete distribution as a mixture of product distributions.
- property num_components: int
Number of mixture components K.
- property products: dict[str | int, Array]
Per-attribute categorical probabilities (softmax of logits).
- project(attrs: str | int | Sequence[str | int]) Factor[source]
Compute the marginal over
attrsvia einsum.
- classmethod random(domain: Domain, total: float, num_components: int = 100, seed: int = 0, scale: float = 0.25) MixtureOfProducts[source]
Initialize with random logits.
- supports(attrs: str | int | Sequence[str | int]) bool[source]
Any subset of domain attributes is supported.
- total: float
- class mbi.extensions.mixture_of_products.MixtureOfProductsEstimator(*, marginal_oracle: marginal_oracles.MarginalOracle | None = None, optimizer: optax.GradientTransformation, num_components: int = 100, seed: int = 0)[source]
Bases:
EstimatorEstimates a distribution as a mixture of product distributions.
Inspired by RAP (https://arxiv.org/abs/2103.06641) and RAP^{softmax} (https://arxiv.org/abs/2106.07153). Instead of parameterizing via a graphical model with potentials, the distribution is represented as a mixture of K product distributions optimized via gradient descent.
- num_components
Number of mixture components K.
- Type:
int
- optimizer
An optax optimizer (e.g.
optax.adam(0.1)).- Type:
optax._src.base.GradientTransformation
- seed
Random seed for parameter initialization.
- Type:
int
- num_components: int = 100
- optimizer: GradientTransformation
- seed: int = 0
- class mbi.extensions.mixture_of_products.MixtureOfProductsState(model: MixtureOfProducts, opt_state: optax.OptState)[source]
Bases:
NamedTupleOptimization state for MixtureOfProductsEstimator.
Create new instance of MixtureOfProductsState(model, opt_state)
- model: MixtureOfProducts
Alias for field number 0
- opt_state: optax.OptState
Alias for field number 1
mbi.extensions.precompute_marginals module
Precompute all marginals from a dataset using JIT-compiled bincount.
Computes a CliqueVector of marginals from raw data by JIT-compiling a
jnp.bincount kernel per unique shape. Three optimizations reduce
compilation overhead for heterogeneous domains:
Power-of-2 bucketing: Domain sizes are rounded up to the next power of 2, so attributes with similar cardinalities share a compiled program.
Canonical shape ordering: Within each clique, attributes are sorted so that padded sizes are non-decreasing. This halves the number of unique shapes for 2-way marginals.
Background precompilation: Unique shapes are sorted by workload (descending number of cliques), and all compilations are submitted upfront so they overlap with execution.
- mbi.extensions.precompute_marginals.precompute_marginals(dataset: Dataset | JaxDataset, cliques: Sequence[tuple[str | int, ...]], *, transpose: bool = True) CliqueVector[source]
Compute all marginals from a dataset using JIT-compiled bincount.
Compiles one
jnp.bincountprogram per unique padded shape (after power-of-2 bucketing and canonical reordering) and executes it for every clique that maps to that shape. All compilations are submitted to a background thread upfront so they overlap with execution.Accepts both
Dataset(numpy-backed) andJaxDataset(JAX-backed). Numpy arrays are converted to JAX arrays internally.- Parameters:
dataset – The dataset to compute marginals from.
cliques – Cliques (tuples of attribute names) to compute.
transpose – If
True(default), transpose each marginal so its axes match the original clique attribute order. Set toFalseto skip the transpose and keep the canonical sorted order.
- Returns:
A
CliqueVectormapping each clique to its marginalFactor.
mbi.extensions.reweighted_dataset module
Reweighted dataset estimation for discrete distributions.
Inspired by PMW^Pub (https://arxiv.org/abs/2102.08598). Given a seed set of records, the distribution is represented by learning a weight for each record to minimize the marginal loss. The weights are parameterized in log-space with softmax normalization to guarantee non-negativity.
- class mbi.extensions.reweighted_dataset.ReweightedDatasetEstimator(seed_data: Dataset, optimizer: optax.GradientTransformation, *, marginal_oracle: marginal_oracles.MarginalOracle | None = None)[source]
Bases:
EstimatorEstimates a distribution by reweighting seed records.
Inspired by PMW^Pub (https://arxiv.org/abs/2102.08598). Given a seed set of records, the distribution is represented by learning a weight for each record to minimize the marginal loss.
- seed_data
A Dataset of seed records to reweight.
- Type:
- optimizer
An optax optimizer (e.g.
optax.adam(0.1)).- Type:
optax._src.base.GradientTransformation
- optimizer: GradientTransformation
- class mbi.extensions.reweighted_dataset.ReweightedDatasetState(log_weights: jax.Array, opt_state: optax.OptState)[source]
Bases:
NamedTupleOptimization state for ReweightedDatasetEstimator.
Create new instance of ReweightedDatasetState(log_weights, opt_state)
- log_weights: jax.Array
Alias for field number 0
- opt_state: optax.OptState
Alias for field number 1
mbi.extensions.synthetic_data module
JAX-accelerated synthetic data generation with async precompilation.
- mbi.extensions.synthetic_data.precompile(domain: Domain, cliques: Sequence[tuple[str | int, ...]], rows: int, constraints: Sequence[Constraint] = ()) Future[source]
Warm the JIT cache for
synthetic_dataasynchronously.Only requires domain and clique structure — both available after measurement selection. Fire and forget;
synthetic_databenefits from whatever has compiled so far.No concrete arrays are allocated (except a PRNG key); all inputs use abstract
ShapeDtypeStructvalues viaFactor.abstractso the compiler sees shapes and dtypes without materializing memory.- Parameters:
domain – The Domain over which the model is defined.
cliques – The cliques of the model (known after measurement selection).
rows – Number of records that will be generated.
constraints – Structural constraints the model is fit under. Their cliques are added to the plan so the warmed JIT cache matches the constraint-aware
synthetic_datacall.
- mbi.extensions.synthetic_data.synthetic_data(model: MarkovRandomField, rows: int, seed: int = 0) Dataset[source]
Generate synthetic data from a fitted model using Gumbel rounding.
Output marginals match the model within ±2 counts per cell. If
precompilewas called earlier with matching domain, cliques, androws, the JIT cache will be warm and this call is fast.- Parameters:
model – A fitted
MarkovRandomField.rows – Number of records to generate.
seed – Random seed for the JAX PRNG.
- Returns:
A
Datasetwhose marginals closely match the model.
Module contents
Extensions for mbi providing alternative estimation approaches.
- class mbi.extensions.MixtureOfProducts(_logits: dict[str | int, Array], domain: Domain, total: float)[source]
Bases:
objectA discrete distribution as a mixture of product distributions.
- property num_components: int
Number of mixture components K.
- property products: dict[str | int, Array]
Per-attribute categorical probabilities (softmax of logits).
- project(attrs: str | int | Sequence[str | int]) Factor[source]
Compute the marginal over
attrsvia einsum.
- classmethod random(domain: Domain, total: float, num_components: int = 100, seed: int = 0, scale: float = 0.25) MixtureOfProducts[source]
Initialize with random logits.
- supports(attrs: str | int | Sequence[str | int]) bool[source]
Any subset of domain attributes is supported.
- total: float
- class mbi.extensions.MixtureOfProductsEstimator(*, marginal_oracle: marginal_oracles.MarginalOracle | None = None, optimizer: optax.GradientTransformation, num_components: int = 100, seed: int = 0)[source]
Bases:
EstimatorEstimates a distribution as a mixture of product distributions.
Inspired by RAP (https://arxiv.org/abs/2103.06641) and RAP^{softmax} (https://arxiv.org/abs/2106.07153). Instead of parameterizing via a graphical model with potentials, the distribution is represented as a mixture of K product distributions optimized via gradient descent.
- num_components
Number of mixture components K.
- Type:
int
- optimizer
An optax optimizer (e.g.
optax.adam(0.1)).- Type:
optax._src.base.GradientTransformation
- seed
Random seed for parameter initialization.
- Type:
int
- num_components: int = 100
- optimizer: GradientTransformation
- seed: int = 0
- class mbi.extensions.ReweightedDatasetEstimator(seed_data: Dataset, optimizer: optax.GradientTransformation, *, marginal_oracle: marginal_oracles.MarginalOracle | None = None)[source]
Bases:
EstimatorEstimates a distribution by reweighting seed records.
Inspired by PMW^Pub (https://arxiv.org/abs/2102.08598). Given a seed set of records, the distribution is represented by learning a weight for each record to minimize the marginal loss.
- seed_data
A Dataset of seed records to reweight.
- Type:
- optimizer
An optax optimizer (e.g.
optax.adam(0.1)).- Type:
optax._src.base.GradientTransformation
- optimizer: GradientTransformation
- mbi.extensions.precompile(domain: Domain, cliques: Sequence[tuple[str | int, ...]], rows: int, constraints: Sequence[Constraint] = ()) Future[source]
Warm the JIT cache for
synthetic_dataasynchronously.Only requires domain and clique structure — both available after measurement selection. Fire and forget;
synthetic_databenefits from whatever has compiled so far.No concrete arrays are allocated (except a PRNG key); all inputs use abstract
ShapeDtypeStructvalues viaFactor.abstractso the compiler sees shapes and dtypes without materializing memory.- Parameters:
domain – The Domain over which the model is defined.
cliques – The cliques of the model (known after measurement selection).
rows – Number of records that will be generated.
constraints – Structural constraints the model is fit under. Their cliques are added to the plan so the warmed JIT cache matches the constraint-aware
synthetic_datacall.
- mbi.extensions.precompute_marginals(dataset: Dataset | JaxDataset, cliques: Sequence[tuple[str | int, ...]], *, transpose: bool = True) CliqueVector[source]
Compute all marginals from a dataset using JIT-compiled bincount.
Compiles one
jnp.bincountprogram per unique padded shape (after power-of-2 bucketing and canonical reordering) and executes it for every clique that maps to that shape. All compilations are submitted to a background thread upfront so they overlap with execution.Accepts both
Dataset(numpy-backed) andJaxDataset(JAX-backed). Numpy arrays are converted to JAX arrays internally.- Parameters:
dataset – The dataset to compute marginals from.
cliques – Cliques (tuples of attribute names) to compute.
transpose – If
True(default), transpose each marginal so its axes match the original clique attribute order. Set toFalseto skip the transpose and keep the canonical sorted order.
- Returns:
A
CliqueVectormapping each clique to its marginalFactor.
- mbi.extensions.synthetic_data(model: MarkovRandomField, rows: int, seed: int = 0) Dataset[source]
Generate synthetic data from a fitted model using Gumbel rounding.
Output marginals match the model within ±2 counts per cell. If
precompilewas called earlier with matching domain, cliques, androws, the JIT cache will be warm and this call is fast.- Parameters:
model – A fitted
MarkovRandomField.rows – Number of records to generate.
seed – Random seed for the JAX PRNG.
- Returns:
A
Datasetwhose marginals closely match the model.