## distributions.DistributionRegistry


Registry for probability distribution classes with batch creation


Usage

``` python
distributions.DistributionRegistry()
```


capabilities.

The DistributionRegistry provides a central repository for registering distribution classes and instantiating them from configuration data. This facilitates dynamic creation of distribution objects based on runtime configuration, supporting scenarios like simulation models, statistical analysis, or any application requiring configurable random distributions.

Key features: - Register distribution classes with a simple decorator - Create distribution instances from class names and parameters - Batch create multiple distributions from a dictionary or list - Automatic generation of statistically independent random seeds


## Examples

Register distribution classes:

``` python
>>> @DistributionRegistry.register()
... class Exponential:
...     def __init__(self, mean, random_seed=None):
...         self.rng = np.random.default_rng(random_seed)
...         self.mean = mean
...
...     def sample(self, size=None):
...         return self.rng.exponential(self.mean, size=size)
...
>>> @DistributionRegistry.register("uniform_dist")  # Custom name
... class Uniform:
...     def __init__(self, low, high, random_seed=None):
...         self.rng = np.random.default_rng(random_seed)
...         self.low = low
...         self.high = high
...
...     def sample(self, size=None):
...         return self.rng.uniform(self.low, self.high, size=size)
```

Create a distribution with parameters:

``` python
>>> exp_dist = DistributionRegistry.create("Exponential", mean=2.0)
>>> exp_dist.sample(5)  # Generate 5 samples
```

Create multiple distributions from a flat configuration:

``` python
>>> config = {
...     "arrivals": {
...         "class_name": "Exponential",
...         "params": {"mean": 5.0}
...     },
...     "service_times": {
...         "class_name": "uniform_dist",
...         "params": {"low": 1.0, "high": 3.0}
...     }
... }
>>> distributions = DistributionRegistry.create_batch(config,
...                                                    main_seed=12345)
>>> arrivals = distributions["arrivals"]
>>> service_times = distributions["service_times"]
```

Create distributions from a nested configuration:

``` python
>>> config = {
...     "call": {
...         "C1": {"class_name": "Exponential", "params": {"mean": 10.0}},
...         "C2": {"class_name": "Exponential", "params": {"mean": 8.0}},
...     },
...     "response_time": {
...         "C1": {
...             "class_name": "Lognormal",
...             "params": {"mean": 30.0, "stdev": 5.0},
...         },
...     },
... }
>>> dists = DistributionRegistry.create_batch(
...     config, main_seed=42, preserve_structure=True
... )
>>> dists["call"]["C1"].sample(5)
>>> dists["response_time"]["C1"].sample(5)
```


## Notes

When creating distributions in batch with a main_seed, each distribution receives its own statistically independent seed derived from the main seed. This ensures proper statistical independence between random number streams while maintaining overall reproducibility through the main seed.

When `preserve_structure=True`, the output mirrors the shape of the input configuration, so nested configs produce nested dicts of instances. When `preserve_structure=False` (default), all leaf distributions are flattened into a single dict whose keys are the path components joined by underscores (e.g. `"call_C1"`).

With `sort=True` (default), keys at every nesting level are sorted alphabetically before seeds are assigned. This ensures that seed assignment is stable even if the insertion order of keys in the config dict changes between runs.


## Methods

| Name | Description |
|----|----|
| [create()](#create) | Create a distribution instance by name. |
| [create_batch()](#create_batch) | Create multiple distributions from a configuration dictionary or list. |
| [get()](#get) | Get a distribution class by name. |
| [get_template()](#get_template) | Generate a template configuration containing all registered |
| [register()](#register) | Decorator to register a distribution class in the registry. |

------------------------------------------------------------------------


#### create()


Create a distribution instance by name.


Usage

``` python
create(name, **params)
```


##### Parameters


`name: str`  
Name of the registered distribution class

`**params`  
Parameters to pass to the distribution constructor


##### Returns


`Any`  
Instance of the requested distribution class


------------------------------------------------------------------------


#### create_batch()


Create multiple distributions from a configuration dictionary or list.


Usage

``` python
create_batch(config, main_seed=None, sort=True, preserve_structure=False)
```


Accepts both flat and arbitrarily nested dict configurations. Every leaf must be a dict with exactly the keys `'class_name'` and `'params'`.


##### Parameters


`config: Union[List[Dict], Dict[str, Dict]]`  
One of:

- A **list** of distribution configs, each with `'class_name'` and `'params'`. Returns a list of instances.

- A **flat dict** mapping names to distribution configs:

      {
          "arrivals": {
              "class_name": "Exponential",
              "params": {"mean": 5.0},
          }
      }

- A **nested dict** where intermediate keys group distributions and leaves are distribution configs:

      {
          "call": {
              "C1": {
                  "class_name": "Exponential",
                  "params": {"mean": 10.0},
              }
          }
      }

`main_seed: Optional[int] = None`  
Master seed to generate individual seeds for each distribution. If None, random seeds will still be generated for independence.

`sort: Optional[bool] = ``True`  
If True, keys at every nesting level are sorted alphabetically before seeds are assigned. This ensures deterministic seed assignment even if config key insertion order changes between runs. Not relevant for top-level lists.

`preserve_structure: Optional[bool] = ``False`  
Controls the shape of the returned dict when `config` is a dict.

- `False` (default): all distributions are returned in a single flat dict whose keys are the path components of each leaf joined by underscores, e.g. `"call_C1"`.
- `True`: the returned dict mirrors the nesting of the input config, so `result["call"]["C1"]` gives the distribution directly.

Has no effect when `config` is a list.


##### Returns


`Union[List, Dict]`  
- A list of distribution instances if `config` was a list.
- A flat dict of distribution instances if `config` was a dict and `preserve_structure=False`.
- A nested dict of distribution instances if `config` was a dict and `preserve_structure=True`.


##### Raises


`TypeError`  
If `config` is neither a list nor a dictionary.

`ValueError`  
If any distribution config is malformed, if a required key is missing or an unexpected key is present, or if the config contains values that are neither dicts, lists, nor valid distribution configs.


------------------------------------------------------------------------


#### get()


Get a distribution class by name.


Usage

``` python
get(name)
```


##### Parameters


`name: str`  
Name of the registered distribution class


##### Returns


`type`  
The registered distribution class


##### Raises


`ValueError`  
If the distribution name is not found in the registry


------------------------------------------------------------------------


#### get_template()


Generate a template configuration containing all registered


Usage

``` python
get_template(format="json", indent=2)
```


distributions.

This helper method creates a template that includes all registered distribution types with appropriate dummy parameters. Users can modify this template and pass it directly to [create_batch()](time_dependent.DistributionRegistry.md#sim_tools.time_dependent.DistributionRegistry.create_batch) to instantiate their distributions.


##### Parameters


`format: str = ``"json"`  
Output format: `'dict'` for a Python dictionary or `'json'` for a JSON string.

`indent: int = ``2`  
Indentation for JSON formatting (only used when `format='json'`).


##### Returns


`Union[Dict, str]`  
Either a dictionary (if`format='dict'`) or a JSON string (if `format='json'`) containing template configurations for all registered distributions.


##### Examples

``` python
>>> template = DistributionRegistry.get_template(format='dict')
>>> print(list(template.keys()))
['Exponential_example', 'Normal_example', 'Uniform_example', ...]
```

``` python
>>> template = DistributionRegistry.get_template(format='json')
>>> print(template[:70])
{
  "Exponential_example": {
    "class_name": "Exponential",
    "params": {
```

------------------------------------------------------------------------


#### register()


Decorator to register a distribution class in the registry.


Usage

``` python
register(name=None)
```


##### Parameters


`name: Optional[str] = None`  
Name to register the class under. If None, uses the class name.


##### Returns


`Callable`  
Decorator function that registers the class
