Source code for policy_utils
"""Policy and scenario loading utilities for the MAIS simulation.
This module provides functions for loading simulation scenario definitions
from CSV files and converting them to dictionaries that can drive per-day
policy changes (such as contact-layer weight adjustments) during a run.
"""
import pickle
import click
import pandas as pd
[docs]
def load_scenario_dict(filename: str, sep=',', return_data='list'):
"""Load a scenario definition from a CSV file and return it as a dictionary.
The CSV file is expected to have at minimum an ``id`` column, a ``name``
column, and one or more numeric day-columns. Each day-column represents a
particular simulation day, and the rows represent the layers (or other
entities) whose weights/values are being specified for that day.
Args:
filename (str): Path to the CSV file to read.
sep (str, optional): Column delimiter used in the CSV file.
Defaults to ``','``.
return_data (str, optional): Format for the per-day values:
- ``'list'``: Each day maps to a plain Python list of values
ordered by row.
- ``'names'``: Each day maps to a ``{name: value}`` dictionary
keyed by the ``name`` column.
- ``'ids'``: Each day maps to a ``{name: value}`` dictionary
keyed by the ``name`` column (same as ``'names'`` in current
implementation).
Defaults to ``'list'``.
Returns:
dict: Mapping of ``{day (int): output}`` where ``output`` is
formatted according to ``return_data``.
Raises:
ValueError: If ``return_data`` is not one of ``'list'``,
``'names'``, or ``'ids'``.
"""
df = pd.read_csv(filename, sep=sep)
def get_output(series: pd.Series):
l = series.to_list()
if return_data == 'list':
return l
elif return_data == 'names':
return {k: v for k, v in zip(df["name"], l)}
elif return_data == 'ids':
return {k: v for k, v in zip(df["name"], l)}
else:
raise ValueError(f"Unsupported format: {return_data}, valid options are 'list', 'names', 'ids'.")
data_only = df.drop(columns=['id', 'name'])
return {int(k): get_output(data_only[k]) for k in data_only.columns}
@click.command()
@click.argument('filename')
@click.option('--out_path', default=None)
@click.option('--sep', default=',')
@click.option('--return_data', default='list')
def run(filename, out_path, sep, return_data):
"""CLI entry point: load a scenario CSV and optionally serialise it.
Reads the scenario defined in ``filename``, prints the resulting
dictionary to stdout, and if ``--out_path`` is provided, serialises the
dictionary to that path using :mod:`pickle`.
Args:
filename (str): Path to the scenario CSV file (positional argument).
out_path (str or None): Optional file path for the pickled output.
Defaults to ``None`` (no file written).
sep (str): Column delimiter for the CSV. Defaults to ``','``.
return_data (str): Output format passed to
:func:`load_scenario_dict`. Defaults to ``'list'``.
"""
out_dict = load_scenario_dict(filename, sep=sep, return_data=return_data)
if out_path is not None:
with open(out_path, 'wb') as of:
pickle.dump(out_dict, of)
print(out_dict)
if __name__ == "__main__":
run()