Source code for gamspy.formulations.sddp.simulation
from __future__ import annotations
from dataclasses import dataclass
import pandas as pd
[docs]
@dataclass
class SimulationResult:
"""Per-path Monte Carlo evaluation of a trained SDDP policy.
All DataFrame attributes are indexed by ``path`` (rows) and ``stage``
(columns) so the standard ClearLake-style pivot is the natural shape.
Attributes
----------
n_paths : int
Number of independent simulation paths.
total_cost : pd.Series
Total realised cost per path, indexed by ``path``.
stage_costs : pd.DataFrame
Per-stage cost, indexed by ``path`` with one column per ``stage``.
noise : pd.DataFrame
Realised noise per (path, stage).
variables : dict[str, pd.DataFrame]
``{variable_name: per (path, stage) levels}`` for each reported
variable.
elapsed : float
Wall-clock simulation time in seconds. By default 0.0.
"""
n_paths: int
total_cost: pd.Series
stage_costs: pd.DataFrame
noise: pd.DataFrame
variables: dict[str, pd.DataFrame]
elapsed: float = 0.0
@property
def summary(self) -> pd.Series:
"""Mean / std / percentiles of ``total_cost`` across paths."""
tc = self.total_cost
return pd.Series(
{
"n_paths": float(self.n_paths),
"mean": float(tc.mean()),
"std": float(tc.std(ddof=1) if len(tc) > 1 else 0.0),
"p5": float(tc.quantile(0.05)),
"p50": float(tc.quantile(0.50)),
"p95": float(tc.quantile(0.95)),
"max": float(tc.max()),
},
name="total_cost",
)
def __repr__(self) -> str:
tc = self.total_cost
std = float(tc.std(ddof=1)) if len(tc) > 1 else 0.0
return (
f"SimulationResult("
f"n_paths={self.n_paths}, "
f"mean={tc.mean():,.3f}, "
f"std={std:,.3f}, "
f"p95={tc.quantile(0.95):,.3f}, "
f"max={tc.max():,.3f})"
)