Skip to content

ergminer.sim

ergminer.play_out(erg, n=10, sim_time=5000.0, seed=42, output_dir=None, verbose=False)

Simulate erg for n independent replications and return the combined log.

The ERG is serialised to a temporary ERGML file, then each replication is run using ERGPlayback. Each run's events are tagged with _erg_run (1-indexed) so that per-run analysis remains possible on the combined DataFrame.

Parameters:

Name Type Description Default
erg 'ERG'

The ERG object to simulate.

required
n int

Number of independent simulation replications.

10
sim_time float

Simulation horizon (same units as the source log timestamps).

5000.0
seed int

Base random seed. Run i uses seed + i.

42
output_dir Optional[str]

If provided, individual run CSVs and a combined CSV are saved here.

None
verbose bool

Print per-run progress to stdout.

False

Returns:

Type Description
DataFrame

Combined pd.DataFrame with columns

DataFrame

case_id, timestamp, activity_name, resource_id,

DataFrame

_erg_run. Index is reset.

Source code in src\ergminer\sim.py
def play_out(
    erg: 'ERG',
    n: int = 10,
    sim_time: float = 5000.0,
    seed: int = 42,
    output_dir: Optional[str] = None,
    verbose: bool = False,
) -> pd.DataFrame:
    """Simulate *erg* for *n* independent replications and return the combined log.

    The ERG is serialised to a temporary ERGML file, then each replication is
    run using ``ERGPlayback``.  Each run's events are tagged with ``_erg_run``
    (1-indexed) so that per-run analysis remains possible on the combined
    DataFrame.

    Args:
        erg:        The ``ERG`` object to simulate.
        n:          Number of independent simulation replications.
        sim_time:   Simulation horizon (same units as the source log timestamps).
        seed:       Base random seed. Run *i* uses ``seed + i``.
        output_dir: If provided, individual run CSVs and a combined CSV are
                    saved here.
        verbose:    Print per-run progress to stdout.

    Returns:
        Combined ``pd.DataFrame`` with columns
        ``case_id``, ``timestamp``, ``activity_name``, ``resource_id``,
        ``_erg_run``.  Index is reset.
    """
    from .ERGML_converter import erg_to_ergml
    from .erg_playback import ERGPlayback

    # Serialise ERG to a temporary ERGML file
    ergml_xml = erg_to_ergml(erg, sim_time=sim_time)
    tmp_file = tempfile.NamedTemporaryFile(
        suffix='.ergml', delete=False, mode='w', encoding='utf-8'
    )
    try:
        tmp_file.write(ergml_xml)
        tmp_file.close()
        tmp_path = tmp_file.name

        if output_dir is not None:
            out_dir = Path(output_dir)
            out_dir.mkdir(parents=True, exist_ok=True)

        parts = []
        for i in range(n):
            run_seed = seed + i
            sim = ERGPlayback(tmp_path, sim_time=sim_time, seed=run_seed)
            sim.run()
            df = sim.get_event_log()
            df['_erg_run'] = i + 1

            if output_dir is not None:
                run_path = out_dir / f'sim_run_{i + 1}.csv'
                df.to_csv(run_path, index=False)

            parts.append(df)

            if verbose:
                cases = df['case_id'].nunique() if not df.empty else 0
                print(f"  Run {i + 1}/{n} (seed={run_seed}): "
                      f"{len(df)} events, {cases} cases")

    finally:
        try:
            os.remove(tmp_path)
        except OSError:
            pass

    combined = pd.concat(parts, ignore_index=True) if parts else pd.DataFrame(
        columns=['case_id', 'timestamp', 'activity_name', 'resource_id', '_erg_run']
    )

    if output_dir is not None:
        combined.to_csv(out_dir / 'sim_combined.csv', index=False)

    return combined