Source code for gamspy.formulations.sddp.policy
from __future__ import annotations
from dataclasses import dataclass
from typing import Any
[docs]
@dataclass
class PolicyResult:
"""The trained policy's decision at a single point.
Returned by `SDDP.policy`. Answers the operational question
*"I'm standing in `stage`, my state came in at `incoming_state`, the
noise for this stage realised as `noise`. What should I do, and what
does it cost me from here on?"*
Attributes
----------
stage : str
The stage label that was queried (e.g. ``"mar"`` or ``"w17"``).
incoming_state : float | dict[str, float]
The state value entering the stage.
noise : float
The realised noise value injected for the stage.
approx_cost_to_go : float
``acost.l`` from the point solve: the immediate stage cost **plus**
the cut-approximated expected future cost.
decisions : dict[str, Any]
``{variable_name: level}`` for each reported variable, evaluated at
the stage's last time step. The value shape depends on the
variable's domain:
- Variables with domain ``[time_set]`` give a ``float``.
- Variables with domain ``[time_set, other_dim]`` give a
``dict[str, float]`` keyed by the non-time dimension's label
(e.g. ``{"Hydro": 100.0, "HardCoal": 200.0}``).
- Variables with domain ``[time_set, dim1, dim2, ...]`` (3+-D)
give a ``dict[tuple[str, ...], float]`` keyed by a tuple of
the non-time dim labels in declaration order.
"""
stage: str
incoming_state: float | dict[str, float]
noise: float
approx_cost_to_go: float
decisions: dict[str, Any]
def __repr__(self) -> str:
parts = []
for k, v in self.decisions.items():
if isinstance(v, dict):
inner = ", ".join(f"{ik}={iv:,.3f}" for ik, iv in v.items())
parts.append(f"{k}={{{inner}}}")
else:
parts.append(f"{k}={v:,.3f}")
d = ", ".join(parts)
if isinstance(self.incoming_state, dict):
inner = ", ".join(f"{k}={v:,.3f}" for k, v in self.incoming_state.items())
incoming_str = f"{{{inner}}}"
else:
incoming_str = f"{self.incoming_state:,.3f}"
return (
f"PolicyResult(stage={self.stage!r}, "
f"incoming_state={incoming_str}, "
f"noise={self.noise:,.3f}, "
f"approx_cost_to_go={self.approx_cost_to_go:,.3f}, "
f"decisions={{{d}}})"
)