mixle.inference.block_gibbs module

Block-coordinate Gibbs with per-block inference dispatch – a different update method per parameter.

Real models are heterogeneous: some parameters have a conjugate full conditional (sample it in closed form, exactly, no tuning), others do not (fall back to Metropolis), others are best marginalized or optimized. A single global how= wastes the structure. BlockGibbs cycles the blocks and lets each one declare its own conditional update – a closed-form draw where the conditional is conjugate, a Metropolis step where it is not – so the low-cost exact updates run exactly and only the hard blocks pay for sampling. The composition-expressiveness piece: mixed inference across one model.

class BlockGibbs(blocks, init)[source]

Bases: object

Block-coordinate sampler that dispatches each block’s own conditional update each sweep.

Parameters:
run(n_samples=2000, *, burn=500, seed=None, resume=False)[source]

Run the chain; returns {block_name: array of post-burn-in samples}.

Parameters:
  • n_samples (int) – number of post-burn-in draws to retain (exact positive integer).

  • burn (int) – number of burn-in sweeps to discard, during which proposals adapt (exact >= 0).

  • seed (int | None) – RNG seed. With resume=False the same seed reproduces the same chain exactly.

  • resume (bool) – False (default) starts a fresh run – the state returns to init and every block’s per-run adaptation state is reset, so the run is a pure function of (blocks, init, n_samples, burn, seed). True continues from whatever tuning the previous run left behind, for deliberately staged runs; the chain then depends on the run history and is not reproducible from the seed alone.

Raises:
  • TypeError – if n_samples or burn is not an exact integer.

  • ValueError – if n_samples is not positive or burn is negative.

Return type:

dict[str, ndarray]

class ConjugateBlock(name, draw)[source]

Bases: object

A block whose full conditional is conjugate: draw(state, rng) returns an exact closed-form sample.

Parameters:
  • name (str)

  • draw (Callable[[dict, np.random.RandomState], Any])

reset()[source]

Clear per-run state. A conjugate draw carries none – present for a uniform block protocol.

Return type:

None

update(state, rng, in_burn_in=True)[source]

Draw an exact full-conditional sample for this block.

in_burn_in is accepted (and ignored) only to keep a uniform call signature with MetropolisBlock for BlockGibbs’s dispatch loop – a conjugate draw needs no proposal tuning.

Parameters:
Return type:

Any

class MetropolisBlock(name, log_conditional, scale=0.5)[source]

Bases: object

A non-conjugate block updated by a random-walk Metropolis step on its log full-conditional.

log_conditional(value, state) returns the unnormalized log density of this block’s value given the rest of the state; scale sets the proposal width (adapted lightly toward a ~0.4 acceptance rate).

Parameters:
reset()[source]

Restore the proposal scale and acceptance counters this block was constructed with.

Adaptation state is per-run: a fresh BlockGibbs.run() must not inherit the tuning, nor the cumulative acceptance rate, that a previous run happened to leave behind.

Return type:

None

update(state, rng, in_burn_in=True)[source]

Run one random-walk Metropolis update for this block.

in_burn_in gates the scale adaptation below: adapting the proposal after burn-in ends would keep changing the transition kernel during the “stationary” phase the retained samples are drawn from, breaking the chain’s own validity requirement that an adaptive proposal converges before samples are collected – contrary to this class’s own docstring promise (“adapted… toward a ~0.4 acceptance rate” during burn-in specifically).

Parameters:
Return type:

Any

property acceptance_rate: float

Return the realized Metropolis acceptance rate.