Source code for bayesflow.simulators.sequential_simulator
from collections.abc import Sequence
import numpy as np
from bayesflow.types import Shape
from bayesflow.utils.decorators import allow_batch_size
from .simulator import Simulator
[docs]
class SequentialSimulator(Simulator):
"""Combines multiple simulators into one, sequentially."""
def __init__(self, simulators: Sequence[Simulator], expand_outputs: bool = True):
"""
Initialize a SequentialSimulator.
Parameters
----------
simulators : Sequence[Simulator]
A sequence of simulator instances to be executed sequentially. Each simulator should
return dictionary outputs and may depend on outputs from previous simulators.
expand_outputs : bool, optional
If True, 1D output arrays are expanded with an additional dimension at the end.
Default is True.
"""
self.simulators = simulators
self.expand_outputs = expand_outputs
[docs]
@allow_batch_size
def sample(self, batch_shape: Shape, **kwargs) -> dict[str, np.ndarray]:
"""
Sample sequentially from the internal simulator.
Parameters
----------
batch_shape : Shape
The shape of the batch to sample. Typically, a tuple indicating the number of samples,
but it also accepts an int.
**kwargs
Additional keyword arguments passed to each simulator. These may include previously
sampled outputs used as inputs for subsequent simulators.
Returns
-------
data : dict of str to np.ndarray
A dictionary containing the combined outputs from all simulators. Keys are output names
and values are sampled arrays. If `expand_outputs` is True, 1D arrays are expanded to
have shape (..., 1).
"""
data = {}
for simulator in self.simulators:
data |= simulator.sample(batch_shape, **(kwargs | data))
if self.expand_outputs:
data = {
key: np.expand_dims(value, axis=-1) if np.ndim(value) == 1 else value for key, value in data.items()
}
return data