Cobre
Open infrastructure for power system computation.
Cobre is an ecosystem of Rust crates for power system analysis and optimization. The name comes from the Portuguese word for copper — the metal that conducts electricity. The project is licensed under Apache-2.0.
This site is the methodology reference
This site documents the theory, design specifications, and roadmap behind Cobre. It is written for researchers, algorithm designers, and contributors who need to understand why the system works the way it does.
What you will find here:
- Theory — The mathematical foundations: SDDP and Benders decomposition, stochastic inflow modeling with PAR(p), cut management strategies, and risk measures including CVaR.
- Specifications archive — The design-phase artifacts that governed each implementation phase: data model schemas, architectural trait contracts, HPC communication patterns, and testing contracts.
- Roadmap — Planned features and deferred variants, with rationale for what was prioritized in the minimal viable solver.
- Reference — Glossary of domain terms, notation conventions, and bibliography.
Software Book
For installation instructions, tutorials, user guides, CLI reference, and per-crate API documentation, see the Software Book.
The software book describes what the software does today. This site describes the theory and design decisions behind it.
Quick links
| GitHub | github.com/cobre-rs/cobre |
| Software Book | cobre-rs.github.io/cobre |
| API docs (rustdoc) | docs.rs/cobre-core |
| License | Apache-2.0 |
Go to the Software Book >>
Go to the Software Book >>
SDDP Theory
Stochastic Dual Dynamic Programming (SDDP) is the core optimization algorithm behind Cobre’s hydrothermal dispatch solver. This page provides a practical overview of how the algorithm works. For the complete formal specification, see SDDP Algorithm (spec).
What problem does SDDP solve?
Power system operators must decide how much water to release from reservoirs and how much thermal generation to dispatch at each time step over a multi-month or multi-year horizon. The challenge is uncertainty: future river inflows are unknown, and using too much water now risks expensive thermal generation later, while hoarding water risks spilling it.
SDDP finds the least-cost generation schedule that accounts for this uncertainty across all stages simultaneously. The decision at each stage depends on the current reservoir levels, recent inflow history, and a probabilistic model of future inflows.
How SDDP works: forward and backward passes
SDDP is an iterative algorithm. Each iteration has two phases:
Forward pass. The algorithm simulates the system forward in time, from stage 1 to stage . At each stage it samples a random inflow scenario, solves a linear program (LP) to determine optimal generation and reservoir operations, and records the resulting reservoir levels. These recorded states are called trial points. Multiple independent trajectories are simulated in parallel.
Backward pass. Walking backward from stage to stage 1, the algorithm re-solves each stage LP at the trial points collected during the forward pass – but now for every inflow scenario in the scenario set. From each solve it extracts dual variables (shadow prices) that measure how sensitive the future cost is to changes in reservoir levels. These sensitivities are assembled into Benders cuts: linear constraints that approximate the future cost function.
Each iteration adds new cuts, progressively tightening the approximation of future costs. The forward pass uses the latest cuts to make better decisions; the backward pass generates cuts at the states actually visited.
Lower and upper bounds
SDDP produces two bounds that bracket the true optimal cost:
Lower bound. The first-stage LP objective (including the cut-based future cost approximation) provides a deterministic lower bound . Because cuts can only tighten the approximation, this bound increases monotonically across iterations.
Upper bound. The average total cost across all forward pass trajectories provides a statistical upper bound . This estimate has sampling noise, so it is typically reported with a confidence interval.
Convergence
The algorithm monitors the optimality gap between the bounds:
When the gap falls below a threshold, or the lower bound stalls, the algorithm terminates. The resulting set of cuts defines the operational policy: at any future state, solving the LP with these cuts yields the recommended dispatch.
For detailed stopping criteria, see Convergence and Stopping Rules (spec).
Policy graphs
SDDP organizes stages into a policy graph – a directed graph where nodes are decision stages and arcs represent transitions.
Finite horizon. The standard setup is a linear chain of stages (e.g., 60 monthly stages for a 5-year study). The terminal stage has zero future cost.
Infinite horizon. For long-term planning, the last stage can loop back to the first, creating a cyclic graph. A discount factor on the cycle arc ensures convergence. Cuts at equivalent positions in the cycle are shared.
See SDDP Algorithm (spec) – Policy Graph Structure for details.
State variables
The state at each stage captures everything the future cost depends on. In Cobre, state variables are:
- Reservoir storage volumes (): one per hydro plant, representing end-of-stage water levels
- Autoregressive inflow lags (): past inflow values needed by the PAR(p) stochastic model to generate current-stage inflows
Together, these can reach approximately 2000 dimensions for a system with 160+ hydro plants and multi-lag inflow models.
The Markov property – future costs depend only on the current state, not on the path that led to it – is what makes cut generation mathematically valid. The AR lags are included as state variables precisely to preserve this property.
Single-cut formulation
Cobre uses the single-cut formulation by default: at each iteration, the per-scenario cut coefficients are averaged into one aggregated cut per stage. This keeps the LP small and solve times fast, at the cost of potentially needing more iterations. A multi-cut variant (one cut per scenario) is planned for future releases.
Further reading
- SDDP Algorithm (spec) – Complete formal specification with all formulas, edge cases, and design rationale
- Benders Decomposition – The decomposition technique underlying cut generation
- Forward and Backward Passes – Detailed pass mechanics
- Convergence – Bound computation and stopping criteria
- Cut Management – Cut selection, deletion, and storage strategies
- Single-Cut vs Multi-Cut – Trade-offs between aggregation strategies
See also: For implementation details and usage, see the SDDP crate documentation in the software book.
Benders Decomposition
Overview
Stochastic Dual Dynamic Programming (SDDP) solves large multistage stochastic optimization problems by decomposing them into smaller single-stage subproblems. This decomposition is rooted in Benders decomposition (also known as the L-shaped method), which splits a monolithic problem into a master problem and subproblems connected through linear inequalities called cuts.
In the hydrothermal dispatch context, a direct formulation over all stages, scenarios, and equipment would produce an LP with millions of variables and constraints. Benders decomposition breaks this into stage subproblems, each solved independently for a given incoming state and scenario realization.
The Stage Subproblem
Each stage solves an LP of the form:
where is the incoming state (reservoir volumes, AR inflow lags) fixed from the previous stage, captures the immediate cost (thermal generation, penalties, regularization), and approximates the expected future cost from stages through .
The full LP structure — objective terms, constraint families, slack variables, and variable bounds — is described in LP Formulation.
How Cuts Approximate Future Cost
The true future cost function is convex but unknown. SDDP builds a piecewise-linear lower approximation through iterative cut generation:
Each cut is a supporting hyperplane derived from dual variables of the backward pass. When the stage subproblem is solved at a trial state under scenario , the optimal dual multipliers of the state-linking constraints yield:
- Slope: (sensitivity of future cost to incoming state)
- Intercept:
Notation note: The matrix form above is the standard Benders decomposition notation from the stochastic programming literature. In Cobre’s formal specs, the cut coefficients are expressed directly in terms of LP dual variables: (the storage fixing constraint dual) and (the lag-fixing constraint dual), without explicit technology matrices. Both conventions are mathematically equivalent — the matrix form is compact for general derivations, while the direct-dual form is more practical for implementation. See Cut Coefficient Derivation below.
In the hydrothermal problem, the state variables are reservoir storage volumes and AR inflow lags , so the cut coefficients come from the storage fixing dual and the lag-fixing constraint dual .
Cut Coefficient Derivation
The key insight is how dual variables map to cut coefficients. Cobre introduces an explicit incoming-state LP variable for each state dimension, fixed to the trial value via an equality constraint:
By the LP envelope theorem, the dual of each fixing constraint equals the total derivative of the optimal objective with respect to the fixed value, accounting for all downstream effects:
| Fixing constraint | Dual | Cut coefficient |
|---|---|---|
For storage, the dual captures contributions from the water balance, FPHA hyperplane constraints, and any generic constraints that reference incoming storage — all aggregated automatically by the LP solver through the single incoming-storage variable. No manual dual combination is required.
The cut intercept ensures the cut passes exactly through the trial point:
where is the optimal stage objective value.
Single-Cut Aggregation
In the backward pass, each trial state is evaluated against all scenario realizations. The resulting per-scenario cuts are aggregated into one cut per trial point using probability-weighted expectation:
where is the probability of scenario (uniform for the fixed opening tree: ). The aggregated cut is added to stage ’s cut pool. This single-cut formulation keeps the LP compact: after iterations the LP has cuts, regardless of the number of scenarios per iteration.
The Forward-Backward Iteration
SDDP alternates between two passes:
-
Forward pass: Simulate scenario paths from stage 1 to , solving each stage LP with the current cut approximation. This produces trial states and a statistical upper bound on optimal cost.
-
Backward pass: Traverse from stage back to stage 1. At each stage, solve subproblems for all scenario realizations at each trial state, extract dual multipliers, aggregate them into new cuts, and add each cut to the stage’s cut pool. The first-stage objective (including ) provides a deterministic lower bound.
Cuts accumulate over iterations, progressively tightening toward the true . The algorithm converges when the gap between lower and upper bounds falls below a tolerance.
Why the LP Formulation Matters
The quality of Benders cuts depends directly on the LP formulation:
- Recourse slacks (deficit, excess) guarantee feasibility for every scenario, ensuring duals always exist. Without relatively complete recourse, the backward pass would encounter infeasible subproblems.
- Penalty magnitudes shape the value function. Correct priority ordering ensures that cuts propagate economically meaningful signals across stages.
- State variable identification determines which dual multipliers contribute to cut coefficients. Every constraint linking the current stage to the incoming state produces a component of .
Related Topics
- LP Formulation — complete stage subproblem: objective, constraints, penalties, and Benders cut interface
- Cut Management — cut selection, deletion, and storage strategies
- SDDP Theory — the iterative algorithm structure
- Forward-Backward Pass — detailed mechanics of the forward simulation and backward cut generation passes
Further Reading
- Pereira, M. V. F. and Pinto, L. M. V. G. (1991). “Multi-stage stochastic optimization applied to energy planning.” Mathematical Programming, 52(1-3), 359-375.
- Benders, J. F. (1962). “Partitioning procedures for solving mixed-variables programming problems.” Numerische Mathematik, 4(1), 238-252.
- Birge, J. R. and Louveaux, F. V. (2011). Introduction to Stochastic Programming. Springer, 2nd edition.
- SDDP.jl documentation: https://sddp.dev/stable/
- Cut Management (spec): ../specs/math/cut-management.md
Forward and Backward Passes
SDDP iterates between two complementary phases: a forward pass that simulates the system under the current policy, and a backward pass that improves the policy by generating new Benders cuts. This page summarizes how the two passes work together. For the complete specification, see SDDP Algorithm (spec).
Forward pass
The forward pass simulates the system from stage 1 to stage , producing trial points – the reservoir states that the backward pass will use to build cuts.
For each of independent trajectories:
- Start from the known initial state (reservoir volumes and inflow history).
- At each stage , sample an inflow scenario from the opening tree and solve the stage LP with the incoming state and the sampled scenario. The LP includes all Benders cuts accumulated so far, so the future cost variable reflects the best available approximation of costs from stage onward.
- Record the optimal outgoing state (end-of-stage storage volumes and updated autoregressive lags) as the trial point for stage .
- Pass as the incoming state to stage and repeat.
The forward pass also records each trajectory’s total cost, which feeds the statistical upper bound estimate (see Convergence).
Backward pass
The backward pass walks stages in reverse order, from down to 1, generating new cuts that tighten the future cost approximation.
At each stage , for each trial point collected during the forward pass:
- Solve the stage LP for every scenario in the opening tree, using as the incoming state. This is called backward branching: unlike the forward pass which samples one scenario per stage, the backward pass evaluates all of them.
- From each LP solution, extract the optimal objective value and the dual multipliers of the state-linking constraints (water balance, autoregressive lag fixing). These duals measure how sensitive the future cost is to small changes in the incoming state.
- Compute per-scenario cut coefficients from the duals and trial point.
- Aggregate the per-scenario coefficients into a single cut via probability-weighted averaging (the single-cut formulation).
- Add the new cut to stage ’s problem.
Each iteration adds one cut per stage per trial point, progressively tightening the piecewise-linear lower approximation of the true cost-to-go function.
How the passes work together
The two passes form a feedback loop:
- The forward pass uses the current cut set to make decisions. Better cuts lead to better trial points.
- The backward pass generates cuts at the states actually visited. More representative trial points lead to more useful cuts.
Over iterations, the cuts converge toward the true value function, and the forward pass policy converges toward the optimal dispatch schedule.
Parallelization
Both passes offer natural parallelism:
- Forward pass: The trajectories are independent. Cobre distributes them across MPI ranks and OpenMP threads.
- Backward pass: Within each stage, the branching solves across scenarios can run in parallel. However, there is a synchronization barrier at each stage boundary – all threads must finish generating cuts at stage before any thread moves to stage , because the newly generated cuts must be available when solving stage .
The forward pass LP solution at each stage also provides a warm-start basis for the corresponding backward pass solves, significantly reducing solver time.
For the full specification of the forward and backward pass mechanics, including scenario sampling schemes, feasibility guarantees, and the thread-trajectory affinity model, see SDDP Algorithm (spec).
Related topics
- SDDP Theory – High-level overview of the algorithm
- Benders Decomposition – The decomposition technique behind cut generation
- Convergence – How the bounds produced by these passes are used to monitor convergence
- Scenario Generation – How scenarios are sampled for forward and backward passes
- Solver Workspaces (spec) – Solver state management, basis persistence, and warm-starting across forward and backward passes
See also: For implementation details and usage, see the SDDP crate documentation in the software book.
Convergence
SDDP is an iterative algorithm, so it needs well-defined criteria for when to stop. This page explains how convergence is monitored through bounds, what the five available stopping rules are and how their formulas work, and how to obtain a deterministic upper bound independent of the risk measure.
Lower Bound
The first-stage LP objective — immediate cost plus the cut-based approximation of future cost — provides a deterministic lower bound at iteration :
Because each iteration adds new cuts that can only tighten the approximation, the lower bound increases monotonically. It never decreases, making it a reliable progress indicator.
Statistical Upper Bound
The average total cost across all forward pass trajectories provides a statistical upper bound :
This is a Monte Carlo estimate of the true policy cost, so it carries sampling noise. It is typically reported with a confidence interval based on the sample standard deviation across trajectories.
For risk-averse problems (e.g., CVaR objectives), the statistical upper bound is not valid in the classical sense — the sample average is not a valid upper bound on a risk measure. In such cases, the deterministic upper bound described below is necessary.
Deterministic Upper Bound via Inner Approximation
For a convergence certificate valid under any risk measure, Cobre supports a deterministic upper bound through inner approximation (SIDP). The idea is to build a concave piecewise-linear overestimate of the value function from the inside, complementing the convex piecewise-linear underestimate built by cuts from the outside.
The inner approximation stores vertices — visited state-value pairs collected during forward passes. At any query state , the upper bound is interpolated via the Lipschitz condition:
where is the Lipschitz constant for stage , computed backward from the maximum penalty coefficient:
This formula uses the largest penalty cost (the dominant term in the objective) as a bound on how fast the value function can change per unit change in state. The upper bound at stage 1 then gives:
As iterations proceed, more vertices are collected and the inner approximation tightens. Both bounds converge to the same value, and the gap goes to zero.
Optimality Gap
The gap between the bounds measures how far the current policy may be from optimal:
A small gap means the cut approximation is close to the true value function and the policy is near-optimal. In practice, the gap is monitored over iterations and used by the stopping rules described below.
Stopping Rules
Cobre supports five stopping criteria, evaluated at the end of each iteration. Multiple rules can be combined with OR logic (stop when any rule triggers) or AND logic (stop when all rules trigger simultaneously).
Iteration Limit
A hard cap on the number of iterations. This rule must always be present as a safety bound:
Time Limit
A wall-clock time budget. Checked at the end of each iteration:
Bound Stalling
Detects when the lower bound has plateaued. The rule computes the relative improvement of over a sliding window of iterations:
If falls below the tolerance, further iterations are unlikely to improve the policy significantly.
Gap Convergence
Stops when the optimality gap falls below a threshold:
Requires an upper bound to be available (statistical or deterministic).
Simulation-Based Stopping (Recommended)
The most robust criterion combines bound stability with policy stability. Periodically (e.g., every 20 iterations), the rule:
-
Checks bound stability:
-
If stable, runs a batch of Monte Carlo simulations and computes the normalized distance between the per-stage cost profiles of consecutive simulation batches:
-
Stops when both converge:
This avoids premature termination from statistical noise and ensures the policy is genuinely stable, not just the bound.
Termination Output
When the algorithm stops, the output reports which rule triggered, the final iteration count, the lower and upper bounds, and the optimality gap. This information supports post-hoc analysis of whether the policy is sufficiently converged or whether additional iterations would be beneficial.
Related Topics
- SDDP Theory — Overview of the algorithm and its bound structure
- Forward and Backward Passes — The iteration mechanics that produce bounds
- Stopping Rules — Complete stopping rule formulas and configuration guidance
- Stopping Rules (spec) — Full specification with configuration schemas and formulas
- Upper Bound Evaluation (spec) — Deterministic upper bounds via inner approximation
Stopping Rules
Overview
SDDP is an iterative algorithm with no fixed termination point: it can always run another iteration and tighten the future cost approximation. Stopping rules provide the criteria for deciding when the current policy is good enough to stop.
Good stopping criteria balance two risks. Stopping too early leaves a suboptimal policy; stopping too late wastes computation on marginal improvements. Because the lower bound and the upper bound (statistical or deterministic) approach the true optimum from opposite sides, monitoring both gives a robust termination signal.
The Five Available Rules
Cobre provides five stopping criteria. Multiple rules can be combined: "any" mode (default) stops when the first rule triggers; "all" mode requires every rule to trigger simultaneously.
1. Iteration Limit (Mandatory)
A hard cap on the number of iterations:
where is the current iteration count and is the configured limit.
This rule must always be present. It acts as a safety bound preventing runaway computation if other rules fail to trigger. For production studies, is typically set high enough that convergence rules trigger first, but not so high that a non-converging run consumes unbounded resources.
2. Time Limit
A wall-clock budget:
Checked at the end of each iteration. Useful in operational contexts where results must be available within a fixed window, regardless of convergence status.
3. Bound Stalling
Detects when the lower bound has plateaued — the outer approximation is no longer improving despite additional iterations. The rule computes the relative improvement of the deterministic lower bound over a sliding window of iterations:
where is the relative tolerance (typically 0.01%). The window size controls sensitivity: a small window detects stalling faster but is more susceptible to transient plateaus; a larger window is more robust.
The intuition: if the LP approximation of future costs has not improved appreciably over the last iterations, the current cuts already provide a tight lower bound and further iteration is unlikely to change the dispatch policy.
4. Gap Convergence
When both a lower bound and an upper bound are available, their gap directly measures how far the current policy may be from optimal:
The upper bound can be the Monte Carlo average of forward pass costs (statistical, valid for risk-neutral problems) or the inner approximation via Lipschitz interpolation (deterministic, valid for all risk measures). A tight gap provides a verifiable certificate of near-optimality.
5. Simulation-Based Stopping (Recommended)
The most robust criterion combines two convergence indicators: stability of the outer approximation (bound) and stability of the policy itself (simulated cost profile). The rule executes in two steps, checked every period iterations:
Step 1 — Bound stability check:
where is the bound window (number of past iterations to compare against).
Step 2 — Policy stability check (only if bound is stable): Run replications Monte Carlo forward simulations under the current policy. Compute the mean per-stage cost across replications and compare to the previous simulation batch:
Stopping condition:
This criterion requires both the bound and the simulated policy costs to have converged. The two-step design avoids premature termination: a temporarily stable bound might coincide with a policy that still changes significantly across iterations, and vice versa.
Why this rule is recommended: The bound monitors convergence of the mathematical approximation; the simulation monitors convergence of the economic dispatch decisions. Requiring both to stabilize ensures the solution is practically meaningful, not just numerically tight.
Combining Rules
A typical conservative setup uses an iteration limit as a hard cap with simulation-based stopping as the primary convergence criterion:
- Iteration limit: 500 (hard safety cap)
- Simulation-based stopping: every 20 iterations, 100 replications, 1% policy tolerance
- Mode:
"any"(stop when either triggers)
The iteration limit ensures termination even if the simulation criterion never triggers (e.g., due to high variance). In practice, well-tuned simulation criteria typically trigger well before the iteration limit.
Termination Output
When any stopping rule triggers, the solver records which rule terminated the run, the final iteration count, the lower bound, the upper bound (if evaluated), and the optimality gap. This information is important for post-hoc analysis: a run terminated by the iteration limit before the simulation criterion converged may warrant rerunning with a higher limit.
Further Reading
- Convergence — how bounds are computed and the gap is interpreted
- SDDP Theory — the iteration structure that stopping rules monitor
- Stopping Rules (spec) — complete formal specification with configuration schemas
- Upper Bound Evaluation (spec) — deterministic upper bounds via inner approximation
Stage Subproblem LP Formulation
Overview
At each stage of the SDDP algorithm, the dispatcher solves a linear program (LP) that models the power system for that time period. This LP is the fundamental computational unit of the solver: the forward pass executes it once per stage to simulate the policy, and the backward pass executes it once per stage per scenario to generate Benders cuts.
Understanding the LP structure is important because it directly shapes the quality of the cuts and the economic signals propagated across stages. A well-structured LP ensures that cuts carry meaningful marginal water values and that every scenario is feasible.
Cost and Penalty Taxonomy
The objective function combines four types of costs. The distinction matters because each type serves a different algorithmic role.
Resource Costs
Resource costs represent actual operating expenditures with economic meaning:
| Cost | Symbol | Units | Role |
|---|---|---|---|
| Thermal generation | $/MWh | Fuel cost, typically 50–500 | |
| Contract dispatch | $/MWh | Positive for imports, negative for exports |
Category 1: Recourse Slacks
These penalty terms guarantee that every LP is feasible regardless of the inflow scenario. Without them, the backward pass could encounter infeasible subproblems, making cut generation impossible.
| Penalty | Symbol | Units | Purpose |
|---|---|---|---|
| Load deficit | $/MWh | Unserved energy (piecewise, 1,000–10,000) | |
| Excess generation | $/MWh | Absorbs uncontrollable surplus (0.001–0.1) |
Category 2: Constraint Violation Penalties
These provide soft enforcement of physical constraints that may be impossible to satisfy under extreme conditions. They must be high enough to propagate penalty signals into the future cost function and influence reservoir decisions multiple stages ahead.
| Penalty | Symbol | Violated Constraint |
|---|---|---|
| Storage below minimum | ||
| Filling target shortfall | (terminal) | |
| Turbined flow minimum | ||
| Outflow minimum/maximum | ||
| Generation minimum |
Category 3: Regularization Costs
Very small costs (2–3 orders of magnitude below economic costs) that break degeneracy and guide the solver toward physically preferred solutions when the LP is otherwise indifferent:
| Cost | Symbol | Purpose |
|---|---|---|
| Spillage | Prefer turbining over spilling | |
| FPHA turbined flow | Prevent degenerate FPHA solutions | |
| Exchange | Prevent unnecessary power flows |
Priority Ordering
The ordering must be maintained to ensure correct economic signals:
Filling a dead reservoir (dam safety) has the highest priority; load shedding ranks above generation costs; regularization terms are negligible compared to any economic quantity.
The Stage Subproblem LP
The complete objective minimizes total cost over all load blocks :
Storage violation penalties (, ) appear outside the block sum because they apply to end-of-stage storage (hm³), not per-block flow rates.
Key Constraint Families
Load Balance
For each bus and block , supply must meet demand. Hydro generation, thermal dispatch, imports, and transmission flows contribute to supply; deficit and excess slack variables ensure feasibility:
Hydro Water Balance
End-of-stage storage equals incoming storage plus net inflows and minus all outflows, scaled by the time conversion factor :
where is the incremental inflow from the PAR(p) model and is the incoming storage.
State-Fixing Constraints and the Benders Interface
A critical design choice is the introduction of explicit incoming-state LP variables and , each fixed to the trial value via an equality constraint:
The dual of each fixing constraint is the cut coefficient for that state dimension. This “fishing constraint” technique collects all sensitivity information into a single dual value per state variable — the LP solver automatically propagates contributions from all downstream constraints (water balance, FPHA, generic constraints) through the incoming-state variable. The result appears in the stage LP as:
where is the dual of the storage fixing constraint and is the dual of the lag fixing constraint. Each new Benders cut is derived from these duals after each backward-pass solve.
Hydro Production Models
Two production models are available during training:
Constant productivity: A linear equality linking generation to turbined flow:
where (MW per m³/s) depends on turbine efficiency and reference head. Simple and fast.
FPHA (piecewise-linear): A set of linear hyperplanes forming a concave upper bound on generation as a function of storage and flow:
where is average stage storage. FPHA captures head variation and the effect of spillage on tailrace level, at the cost of more constraints per hydro.
Further Reading
- Benders Decomposition — how cuts are derived from this LP structure
- Hydro Production — full derivation of constant productivity and FPHA models
- PAR(p) Autoregressive Models — the inflow model that produces
- LP Formulation (spec) — complete formal specification with all constraint families, variable bounds, and dual variable conventions
- Cut Management (spec) — dual extraction and cut coefficient derivation
Hydro Production Models
Overview
The amount of electrical power a hydroelectric plant produces depends on two physical quantities: how much water flows through the turbines and the pressure difference (net head) driving that flow. Net head is the difference between the upstream reservoir level and the downstream tailrace level, minus hydraulic losses in the penstock.
This nonlinear relationship creates a modeling challenge for LP-based optimization: the exact production function is a bilinear function of storage and flow, incompatible with linear programming. Cobre uses two linearization strategies during training (policy construction) that preserve LP tractability while capturing different levels of head-variation accuracy.
Constant Productivity Model
The simplest model assumes productivity is constant — independent of how full the reservoir is. Generation is a linear function of turbined flow:
where is the productivity coefficient (MW per m³/s), computed from the turbine efficiency and a reference net head:
with the turbine-generator efficiency (typically 0.85–0.92) and the net head at a representative operating point (typically 65% full storage).
This is an equality constraint: for each hydro and each load block , generation is fully determined by turbined flow. The LP does not treat generation as a free variable — it is substituted out. The simplicity makes this model fast and numerically well-conditioned, which is valuable for long planning horizons where head variation is secondary to reservoir management.
When to use: Run-of-river plants, far-future stages, and initial algorithm development where computational speed matters more than fine-grained head variation.
FPHA: Piecewise-Linear Head Approximation
The exact hydroelectric production function is:
where the net head captures the full hydraulic chain:
- : forebay (reservoir surface) level, a nonlinear function of storage
- : tailrace level, a function of total outflow
- : hydraulic losses in the penstock and turbines
Because is a product of and , it is nonlinear in the LP variables. FPHA (Função de Produção Hidrelétrica Aproximada) replaces this nonlinear surface with a concave piecewise-linear envelope: a set of hyperplanes that together bound generation from above everywhere in the operating region:
where is the average storage over the stage.
Physical Meaning of Coefficients
Each hyperplane coefficient has a clear hydraulic interpretation:
| Coefficient | Sign | Interpretation |
|---|---|---|
| Generation at zero storage and zero flow | ||
| Higher reservoir level raises forebay, increasing net head | ||
| More turbined flow produces more power | ||
| More spillage raises tailrace, reducing net head |
The negative sign on reflects a real hydraulic effect: water released as spillage raises the downstream level, which partially cancels the head driving power generation. In systems with strong tailrace backwater effects, this is an important operational consideration.
Concave Envelope and Conservative Bias
The LP optimizer maximizes hydro generation subject to the FPHA constraints (since hydro has zero fuel cost). At the optimum, generation lies on one of the hyperplane faces. Because the envelope is a concave upper bound on the exact nonlinear surface, the FPHA model may overestimate generation compared to the physical plant.
To prevent this, a correction factor scales the hyperplane intercepts:
The default approach sets as the worst-case ratio between the exact production function and the FPHA approximation across the operating grid, guaranteeing that FPHA never overestimates. For plants with modest head variation, typical values are –.
Impact on Water Values
Because the average storage appears in the FPHA constraint, the incoming storage variable is linked to the generation upper bound. The dual of the incoming storage fixing constraint therefore captures both the water balance sensitivity and the FPHA generation sensitivity — all through a single LP variable. This is what makes the “fishing constraint” technique (see LP Formulation) particularly powerful: the FPHA contribution to cut coefficients is automatic.
FPHA vs. Constant Productivity: Trade-offs
| Criterion | Constant Productivity | FPHA |
|---|---|---|
| LP constraints per hydro | 1 equality per block | inequalities per block |
| Head variation captured | No | Yes |
| Data required | Productivity coefficient | Topology functions + hyperplanes |
| Training speed | Fast | Slower (more constraints) |
| Cut quality | Conservative | More accurate water values |
In practice, many systems use FPHA for near-term stages (where head variation significantly affects near-term dispatch) and constant productivity for far-future stages (where approximation accuracy matters less than speed).
Further Reading
- LP Formulation — how production constraints fit into the assembled stage LP
- Benders Decomposition — how FPHA affects cut coefficient computation
- Hydro Production Models (spec) — complete formal specification including topology function interpolation, correction factor computation methods, and the simulation-only linearized head model
Stochastic Modeling
Why Inflows Are Uncertain
Hydrothermal dispatch optimizes the operation of interconnected hydroelectric and thermal power plants over a multi-year horizon. The dominant source of uncertainty is river inflow – the volume of water arriving at each reservoir in each time period. Inflows depend on rainfall, snowmelt, and upstream conditions that cannot be predicted with precision months or years ahead. Because water stored today displaces expensive thermal generation tomorrow (and vice versa), the dispatch decision at every stage depends critically on the distribution of future inflows, not just a single forecast.
Role of Autoregressive Models
SDDP requires a probabilistic model of inflows that captures two key properties:
- Seasonal patterns: Inflows are strongly periodic – wet and dry seasons drive large swings in mean and variance across the year.
- Temporal correlation: A wet month is more likely to be followed by another wet month than by a dry one. Ignoring this correlation would underestimate hydrological risk.
The Periodic Autoregressive model of order p (PAR(p)) addresses both properties. It fits separate autoregressive parameters for each season (month or week), allowing the mean, variance, and lag structure to vary across the hydrological cycle. At each stage, the model expresses the current inflow as a linear function of recent past inflows plus a random innovation term:
The lagged inflows become state variables in the SDDP subproblem, linking stages through the Bellman recursion.
Spatial Correlation
In systems with many river basins, inflows at different plants are correlated – a drought typically affects an entire region, not a single plant. Cobre handles spatial correlation by sampling the innovation vector from a multivariate distribution that preserves the observed cross-plant correlation structure. The PAR(p) model captures temporal dependence per plant, while the joint sampling of innovations captures spatial dependence across plants. See Spatial Correlation for details on the correlation modeling approach.
Integration with SDDP
During the forward pass, inflow scenarios are sampled from the PAR(p) model (or from external scenario files). During the backward pass, the opening tree of inflow realizations at each stage is generated from the same model, ensuring consistency between the policy being evaluated and the uncertainty it was trained against. When external scenarios are provided for training, a PAR(p) model is fitted to those scenarios so that the backward pass opening tree remains well-defined.
Further Reading
- PAR(p) Autoregressive Models – accessible explanation of the PAR(p) model, its parameters, and how lags become state variables
- PAR Inflow Model Specification – full mathematical specification including fitting procedure, model order selection, and validation invariants
- Scenario Generation – how inflow scenarios are produced for forward and backward passes
See also: For implementation details and usage, see the Stochastic Modeling guide in the software book.
PAR(p) Autoregressive Models
What Is a PAR(p) Model?
A Periodic Autoregressive model of order p (PAR(p)) is a time series model designed for data with strong seasonal patterns. It extends the classical autoregressive (AR) model by allowing every parameter to vary by season — the coefficients that govern January inflows are different from those that govern July inflows.
The “order p” indicates how many past time steps the model looks back. A PAR(3) model for a given month predicts the current inflow using the inflows from the previous three months. The order can differ by season: January might need only one lag while April might need four, reflecting different hydrological dynamics across the year.
The PAR(p) Equation
For hydro plant at stage falling in season , the PAR(p) model is:
In words: the inflow at stage equals the seasonal mean, plus a weighted combination of how much recent inflows deviated from their seasonal means, plus a random shock.
Parameters by Season
Each season has its own set of parameters:
| Parameter | Symbol | Role |
|---|---|---|
| Seasonal mean | Expected inflow for season | |
| AR coefficients | Weights on past deviations from the mean | |
| Residual std | Scale of the random innovation | |
| Innovation | Standardized random shock |
The seasonal mean and sample standard deviation are estimated from historical data. The AR coefficients are fitted using the Yule-Walker equations (see below). The residual standard deviation is derived at runtime from the other parameters (it is not stored independently).
How Lags Become State Variables
In the SDDP framework, decisions at each stage depend on a set of state variables that summarize everything the optimizer needs to know from the past. For the PAR(p) model, the state variables are the lagged inflows:
where is the reservoir volume and are the lagged inflows needed by the autoregressive equation. Each lag adds one state variable per hydro plant to the SDDP subproblem.
This is significant for problem size: a system with 150 hydro plants and a maximum PAR order of 6 adds up to state variables beyond the reservoir volumes. The LP formulation includes constraints that “shift” lagged inflows forward from one stage to the next, ensuring the autoregressive structure is respected across the Bellman recursion.
Stored vs. Computed Quantities
Cobre stores the natural outputs of the fitting process:
- Stored: seasonal means (), seasonal sample standard deviations (), AR order (), and AR coefficients in original units ()
- Computed at runtime: the residual standard deviation , derived from the stored quantities to guarantee consistency
This design avoids redundancy — is fully determined by the other parameters and recomputing it is inexpensive.
Yule-Walker Fitting Procedure
When fitting PAR(p) parameters from historical inflow data, the AR coefficients are estimated by solving the Yule-Walker equations — a linear system that relates the autocorrelations of the data to the model coefficients. The procedure has five steps.
Step 1 — Seasonal Statistics
For each season , compute the sample mean and standard deviation from historical observations :
where is the number of historical observations for season .
Step 2 — Seasonal Autocorrelations
Compute the cross-seasonal autocorrelation at lag for season . The cross-seasonal structure arises because lag at season reaches back to season (cyclically):
Note that is the standard deviation of season , not of season . This is the defining feature of a periodic (as opposed to stationary) autoregressive model.
Step 3 — Yule-Walker System
For each season , the coefficients in standardized form satisfy:
where:
The solution is:
The matrix is not a standard Toeplitz matrix (because consecutive rows use different seasons’ correlations), but it has a similar structure. The correlation matrix must be positive definite for the solution to exist; if not, the historical record may be too short for the requested order.
Step 4 — Residual Standard Deviation
After solving the Yule-Walker system, the residual standard deviation for season is:
This equals times the square root of the unexplained variance fraction. If , the model overfits — it explains all historical variance, leaving no room for the noise term.
Step 5 — Convert to Original Units
The Yule-Walker solution yields coefficients in standardized form (dimensionless, relating standardized deviations). The LP requires original-unit coefficients:
These are computed once at initialization and used directly as LP constraint matrix entries.
Key Properties
- Periodicity: All parameters vary by season, matching the strong seasonality of hydrological data.
- Parsimony: The model order is selected per season using AIC, BIC, or coefficient significance tests, avoiding unnecessary lags.
- Stationarity: Fitted models are validated to ensure the AR process does not diverge — the characteristic polynomial roots must lie outside the unit circle.
- Positive residual variance: After fitting, must hold for all seasons. A zero or negative residual variance indicates overfitting.
Further Reading
- Stochastic Modeling — overview of why inflow uncertainty matters and how PAR(p) fits into the SDDP workflow
- Inflow Non-Negativity — how negative PAR(p) realizations are handled
- PAR Inflow Model Specification — complete mathematical specification with unit conversion formulas, runtime preprocessing steps, and all validation invariants
See also: For implementation details and usage, see the Stochastic Modeling guide in the software book.
Inflow Non-Negativity
Overview
The PAR(p) autoregressive model generates inflow realizations by adding a random innovation to a weighted combination of past inflows. Because the innovation term can be arbitrarily negative in the Gaussian model, the total inflow can sometimes be negative — which is physically impossible. Negative inflows would cause the water balance to add water to the reservoir rather than drain it, producing absurd dispatch decisions.
Handling this situation correctly is important for both LP feasibility and for maintaining the statistical properties of the inflow model. Three strategies are available, with different trade-offs between model fidelity, LP complexity, and computational cost.
How Negative Inflows Arise
The PAR(p) model at stage for hydro generates:
When the noise realization is sufficiently negative (e.g., ), the total can become negative. For systems with low seasonal mean flows and high variability, this can occur with non-negligible probability in dry seasons.
If enters the water balance constraint uncorrected, the LP solver treats it as a negative inflow (water added to the river system), which has no physical meaning and will cause the optimizer to mismanage reservoir storage.
The Penalty Method (Recommended)
The recommended approach introduces a non-negative slack variable that absorbs any negative inflow, keeping the effective inflow non-negative while preserving the LP formulation and the AR model structure for positive realizations.
Modified AR constraint:
with . When is mild, the optimizer sets and takes its natural value. When is extreme, absorbs the excess, so the effective inflow:
The violation is penalized in the objective outside the block summation:
where is the total stage duration in hours. The factor converts the slack rate (m³/s) to an equivalent energy dimension over the full stage, making the penalty dimensionally consistent with storage violation penalties that appear in the same part of the objective.
The penalty is a Category 2 constraint violation penalty — it sits above generation costs in the penalty hierarchy, ensuring the optimizer “pays” for negative inflow events in the value function and propagates this signal back through the Benders cuts.
Properties
- LP always feasible: the slack prevents infeasibility for any noise realization
- AR dynamics preserved for positive realizations: when , the model is unchanged
- Clear cost signal: the penalty magnitude tracks how frequently and severely the threshold is violated
Truncation (Simple Alternative)
The simplest method truncates negative inflows to zero before they enter the LP:
No additional LP variables or constraints are needed. However, truncation has two statistical drawbacks: it shifts the mean inflow upward (positive bias) and disrupts temporal correlation at truncation events, because the extreme noise that triggered truncation is discarded rather than tracked.
For quick studies or debugging, truncation is acceptable. For production use, the bias can distort long-run cost estimates in drought scenarios.
Deferred: Truncation with Penalty
A more sophisticated hybrid approach (deferred to post-v0.1.0) combines truncation with explicit noise adjustment tracking. It introduces a dimensionless slack that adjusts the noise term rather than the inflow directly:
The penalty is proportional to the actual inflow correction , which is larger in high-variability seasons. This approach preserves AR model structure better than pure truncation and provides a more precise signal of how much the noise realization was adjusted. It is deferred because the interaction with the noise generation pipeline adds complexity that is not needed for the minimal viable solver.
Summary
| Method | LP Size | Bias | AR Preservation | Recommended |
|---|---|---|---|---|
| No handling | Base | None | Full | Debugging only |
| Penalty | +1 var/constraint per hydro | Minimal | Full | Production |
| Truncation | Base | Upward | Partial | Quick studies |
| Truncation with penalty | +vars | Minimal | Full | Post-v0.1.0 |
Further Reading
- PAR(p) Autoregressive Models — the inflow model that generates the realizations handled here
- Inflow Non-Negativity (spec) — complete formal specification including the full LP formulations for all four methods and penalty hierarchy placement
- LP Formulation (spec) — penalty taxonomy and priority ordering
Spatial Correlation
Hydro plants in the same river basin or geographic region tend to experience similar hydrological conditions – when one plant receives high inflows, nearby plants often do too. Capturing this spatial correlation is essential for realistic scenario generation. This page summarizes how Cobre handles it. For the full autoregressive model specification, see PAR Inflow Model (spec).
Temporal correlation: the PAR(p) model
Each hydro plant’s inflow series is modeled independently by a Periodic Autoregressive model of order (PAR(p)). This model captures temporal correlation – the tendency for high-inflow months to follow high-inflow months – through autoregressive coefficients that link the current inflow to past values:
The parameters (seasonal means , AR coefficients , residual standard deviations ) vary by season, reflecting the strong seasonality of hydrological processes.
Spatial correlation: correlated noise terms
The PAR(p) model for each plant produces a residual (innovation term) that represents the unexplained randomness after accounting for the autoregressive structure. Spatial correlation is introduced by making these residuals correlated across plants.
Instead of drawing independent noise for each plant, the scenario generator samples a vector of correlated noise terms. Plants in the same river basin share a large portion of their randomness, while plants in distant basins are less correlated. The correlation structure is typically estimated from the historical residuals of the fitted PAR(p) models.
Effect on scenario generation
Correlated noise means that the scenarios used in the forward and backward passes reflect realistic joint behavior across plants:
- In a wet scenario, most plants in a basin receive above-average inflows simultaneously, leading to system-wide surplus.
- In a dry scenario, most plants are deficient together, stressing the thermal fleet.
Without spatial correlation, the scenario generator would produce unrealistic combinations – some plants wet while their upstream neighbors are dry – leading to policies that underestimate system-level risk.
Implementation notes
The spatial correlation structure is encoded in the noise vectors stored in the opening tree. Each noise vector contains entries for all hydro plants, and the cross-plant correlations are baked into the vector generation process. The PAR(p) model then transforms these correlated noise vectors into inflow realizations that respect both the temporal dynamics (autoregressive lags) and the spatial structure (correlated residuals).
Related topics
- PAR Inflow Model (spec) – Full specification of the autoregressive model, fitting procedure, and validation
- Scenario Generation – How scenarios incorporating spatial correlation are used in the SDDP passes
- SDDP Theory – The broader algorithmic context in which inflow modeling operates
Scenario Generation
SDDP requires scenarios – discrete realizations of uncertain quantities (primarily inflows) – at multiple points in the algorithm. This page provides an overview of how scenarios are generated and used. For the underlying stochastic model, see PAR Inflow Model (spec). For the forward/backward pass mechanics that consume these scenarios, see SDDP Algorithm (spec).
The opening tree
Before the SDDP iteration loop begins, Cobre generates a fixed opening tree: a set of pre-sampled noise vectors for each stage. Each noise vector contains correlated random draws for all hydro plants, reflecting the spatial correlation structure estimated from historical data (see Spatial Correlation).
The opening tree is generated once and remains fixed throughout training. This ensures that every iteration’s backward pass evaluates the same set of realizations, which is important for cut validity – cuts are valid lower bounds on the expected cost-to-go computed over a specific discrete distribution.
The number of openings per stage is a key configuration parameter. More openings give a finer approximation of the continuous inflow distribution but increase the computational cost of each backward pass proportionally.
Forward pass sampling
During the forward pass, each trajectory needs one scenario realization per stage. The default scheme (InSample) draws uniformly at random from the opening tree – the same set used by the backward pass. This means the forward pass explores states that are consistent with the distribution the cuts were built for.
Alternative sampling schemes are available:
- External: Draws from user-provided scenario data, allowing the forward pass to explore states driven by historical or synthetically generated inflow sequences.
- Historical: Uses actual historical inflow records as forward pass scenarios, useful for validating the policy against observed conditions.
Regardless of the sampling scheme, the backward pass always uses the complete opening tree.
Backward pass branching
The backward pass evaluates all openings in the tree at each visited trial point. This complete enumeration is what makes the resulting Benders cut a valid expected-value inequality: the cut coefficients are computed as probability-weighted averages over the full discrete distribution.
For each trial point at stage :
- Solve the stage LP once per opening , using as the incoming state and as the inflow realization.
- Extract dual multipliers and objective values from each solve.
- Aggregate into a single cut (probability-weighted average of per-scenario coefficients).
The uniform probability applies when all openings are equally likely, which is the default.
From noise to inflows
The opening tree stores noise vectors (standardized innovations), not inflows directly. At each stage, the PAR(p) model transforms these noise vectors into physical inflow values using the autoregressive equation:
where is the noise draw from the opening tree. The deterministic base and lag contribution depend on the incoming state (autoregressive lags), so the same noise vector produces different inflows depending on the system’s history. This is how the Markov property is maintained – the state carries enough information to reconstruct the inflow dynamics.
Scenario count and computational cost
The number of openings directly affects the backward pass cost: each backward stage solve requires LP solves per trial point. Typical configurations use 20 to 200 openings per stage, balancing approximation quality against runtime.
The forward pass cost is independent of the opening count – each trajectory samples exactly one realization per stage.
Related topics
- PAR Inflow Model (spec) – The autoregressive model that transforms noise into inflows
- Spatial Correlation – How cross-plant correlation is embedded in the noise vectors
- Forward and Backward Passes – How the passes consume scenarios
- SDDP Algorithm (spec) – Full specification including scenario sampling schemes and opening tree structure
Cut Management
Cut management controls the lifecycle of Benders cuts in the SDDP algorithm: how cuts are generated, aggregated, stored, and selectively pruned. Effective cut management is essential for solver performance – without it, the number of constraints in each stage LP grows unboundedly, slowing every forward and backward pass solve.
What is a Benders cut?
A Benders cut is a linear inequality added to a stage’s LP that approximates the cost of future decisions. Each cut encodes information learned during a backward pass solve: how sensitive the total future cost is to changes in reservoir storage volumes and inflow history at that stage.
Mathematically, a cut takes the form:
where is the future cost variable, is the intercept, captures the marginal value of water in reservoir , and captures the marginal value of inflow history. The collection of all cuts at a stage forms a piecewise-linear lower approximation of the true future cost function.
How cuts are generated
During the backward pass, the algorithm solves each stage’s LP at trial states collected in the forward pass, for every scenario in the opening tree. The LP dual variables (shadow prices) from the water balance and AR lag-fixing constraints provide the cut coefficients. The intercept is computed so that the cut passes exactly through the trial point.
Because multiple scenarios are evaluated, the per-scenario coefficients are aggregated into a single cut per trial point using probability-weighted averaging. This is the single-cut formulation used by Cobre.
Why cut management matters
Each SDDP iteration adds new cuts, so after hundreds of iterations the cut pool can contain thousands of constraints per stage. Most older cuts become redundant as newer, tighter cuts supersede them. Without pruning:
- LP solve time increases linearly with the number of active cuts
- Memory consumption grows proportionally
- Numerical conditioning degrades as near-parallel cuts accumulate
Cut selection strategies identify and deactivate redundant cuts, keeping the LP compact while preserving the quality of the future cost approximation. The available strategies (Level-1, LML1, dominated cut detection) offer different trade-offs between aggressiveness and safety. See Cut Selection for a summary of each strategy.
Importantly, deactivated cuts are not deleted from memory – they are relaxed to so their indices remain stable. This preserves reproducibility across checkpoint/resume cycles and allows reactivation if needed.
Further reading
- Cut Management (spec) – complete formal specification: cut definition, dual extraction, aggregation formulas, validity conditions, selection strategies, convergence guarantees, and configuration parameters
- Single-Cut vs Multi-Cut – comparison of cut aggregation strategies
- Cut Selection – overview of the three selection strategies
- Benders Decomposition – the decomposition framework underlying cut generation
- Forward and Backward Passes – the iterative structure that drives cut generation
Single-Cut vs Multi-Cut
In SDDP, the backward pass evaluates multiple inflow scenarios at each trial state and must combine the resulting information into cuts for the previous stage. There are two approaches: the single-cut formulation (used by Cobre) and the multi-cut formulation (deferred to a future release).
Single-cut formulation
The single-cut approach aggregates per-scenario cut coefficients into one cut per trial point by computing the probability-weighted average:
This produces a single constraint added to the stage LP:
Advantages:
- Each iteration adds exactly one cut per stage per trial point, keeping the LP small
- LP solve times remain fast, especially important for systems with many stages
- Simpler implementation and lower memory footprint
Trade-off:
- Each cut carries averaged information, so more iterations may be needed to achieve the same approximation quality
Multi-cut formulation
The multi-cut approach keeps one cut per scenario, introducing scenario-specific future cost variables :
with the linking constraint .
Advantages:
- Preserves more information per iteration – each scenario’s sensitivity is represented individually
- Can converge in fewer iterations for problems with high scenario variability
Trade-off:
- Each iteration adds cuts per stage per trial point, leading to larger LPs
- LP solve time per iteration is higher
Which does Cobre use?
Cobre implements the single-cut formulation. For the system sizes typical of Brazilian hydrothermal dispatch (160+ hydro plants, hundreds of scenarios), the single-cut approach provides the best balance between iteration count and per-iteration solve time.
The multi-cut formulation is planned for a future release. See Deferred Features for status.
Further reading
- Cut Management (spec) – formal definition of single-cut aggregation (section 3) and the multi-cut deferral note
- Cut Management – overview of the full cut lifecycle
- Benders Decomposition – how cuts are derived from LP duals
Cut Selection
As SDDP iterates, the number of Benders cuts grows with each backward pass. Many older cuts become redundant once newer, tighter cuts are generated at nearby states. Cut selection strategies identify and deactivate these redundant cuts, keeping the stage LPs compact without sacrificing approximation quality.
Cobre supports three selection strategies, listed from least to most aggressive.
Cut activity
All three strategies rely on the concept of cut activity. A cut is active at a given state if it is binding (or nearly binding) at the LP optimum – meaning it is actually shaping the future cost approximation at that point. Inactive cuts sit below the current approximation surface and contribute nothing to the solution.
Activity is determined by checking whether the gap between the future cost variable and the cut’s value is below a configurable threshold :
A threshold of zero means only strictly binding cuts count; a small positive value (e.g., 1e-6) accounts for numerical tolerance.
Level-1
The simplest strategy. A cut is retained if it was active at least once during the entire algorithm execution. Periodically, cuts that have never been active are deactivated.
- Retention policy: ever-active
- Aggressiveness: low – keeps cuts that were useful at any point in training
- Risk: may retain cuts that were active early but are now permanently dominated by newer cuts
Limited Memory Level-1 (LML1)
A refinement of Level-1 that adds a time horizon. Each cut is timestamped with the most recent iteration at which it was active. Cuts whose timestamp is older than a configurable memory window (in iterations) are deactivated.
- Retention policy: active within the last iterations
- Aggressiveness: moderate – controlled by the window size
- Risk: a very small window may prematurely remove cuts that are infrequently but meaningfully active
Dominated cut detection
The most aggressive strategy. A cut is dominated if, at every visited state, some other cut in the pool achieves an equal or higher value. Dominated cuts provide no value at any known operating point and can be safely deactivated.
Since verifying domination over the entire state space is intractable, Cobre checks domination only at the states visited during recent forward passes. As the set of visited states grows denser over iterations, the domination check becomes more reliable.
- Retention policy: not dominated at any visited state
- Aggressiveness: high – directly targets cuts that contribute nothing
- Cost: per stage per check
Convergence guarantees
Level-1 and LML1 both preserve the finite convergence guarantee of SDDP: removing cuts that are never active at visited states does not affect the outer approximation quality at those states. This result is established in Bandarra and Guigues (2021).
Configuration
Cut selection is controlled by four parameters: the strategy (level1, lml1, or domination), the activity threshold, the frequency of selection checks (in iterations), and the memory window (for LML1). See Cut Management (spec) – section 9 for the parameter table.
Further reading
- Cut Management (spec) – formal definitions of cut activity, all three selection strategies, convergence theorem, and configuration parameters
- Cut Management – overview of the full cut lifecycle
- Convergence – how cut quality affects stopping criteria and bound computation
Risk Measures
Why risk matters in power system planning
Standard SDDP minimizes the expected total cost across all scenarios. This produces policies that perform well on average but can lead to extremely high costs in adverse scenarios – for example, a prolonged drought that depletes reservoirs and forces expensive thermal generation or load shedding.
Risk-averse SDDP addresses this by incorporating a risk measure into the optimization objective. Instead of minimizing only the average cost, the algorithm also penalizes outcomes in the tail of the cost distribution. The result is a policy that sacrifices a small amount of average-case performance for substantially better worst-case behavior.
Risk-neutral vs risk-averse
In risk-neutral SDDP, each backward pass aggregates per-scenario cut coefficients using the scenario probabilities . All scenarios contribute equally (weighted by probability) to the cut that approximates the future cost function.
In risk-averse SDDP, the scenario probabilities are replaced by risk-adjusted weights that place more emphasis on expensive (adverse) scenarios. The cut generation mechanics are otherwise identical – only the aggregation weights change.
The convex combination risk measure
Cobre uses a convex combination of expectation and Conditional Value-at-Risk (CVaR):
This formulation has two parameters:
- (risk aversion weight): Controls the blend between expected value and CVaR. Setting recovers risk-neutral SDDP; setting uses pure CVaR.
- (confidence level): Controls how deep into the tail CVaR looks. Smaller means focusing on more extreme adverse scenarios.
Both parameters can vary by stage, allowing operators to apply stronger risk aversion to near-term decisions (where consequences are immediate) and weaker risk aversion to distant stages.
Implications for convergence monitoring
A critical subtlety of risk-averse SDDP is that the first-stage LP objective is not a valid lower bound on the true risk-averse optimal cost. It remains a useful convergence indicator (it increases monotonically and plateaus), but it cannot be interpreted as a bound in the same way as in risk-neutral SDDP. Valid upper bounds require the inner approximation (SIDP) method.
Further reading
- CVaR – Intuitive explanation of Conditional Value-at-Risk
- Risk Measures (spec) – Complete formal specification: dual representations, subgradient theorem, risk-averse Bellman equation, cut generation algorithm, and lower bound validity warning
- Cut Management – How risk-adjusted weights integrate into cut aggregation
- Convergence – Bound computation and stopping criteria
Conditional Value at Risk (CVaR)
What is CVaR?
Conditional Value-at-Risk (CVaR) is a risk measure that captures the expected cost in the worst-case tail of a probability distribution. While the ordinary expected value averages over all outcomes equally, CVaR focuses on the most adverse fraction.
Formally, for a random cost and a confidence level :
The parameter determines how deep into the tail the measure looks. Smaller means a more pessimistic assessment.
Intuitive interpretation
Imagine sorting all possible cost outcomes from lowest to highest. CVaR is the average cost among the worst -fraction of those outcomes.
- : The “worst 100%” is the entire distribution, so CVaR equals the ordinary expected value .
- : The average cost of the worst half of outcomes.
- : The average cost of the worst 5% of outcomes – a strongly pessimistic measure.
Relationship to VaR
Value-at-Risk (VaR) is the threshold below which the worst -fraction of outcomes falls. CVaR goes further: it averages all costs beyond that threshold. This makes CVaR strictly more conservative than VaR and, unlike VaR, it is a coherent risk measure (satisfying monotonicity, translation equivariance, positive homogeneity, and subadditivity).
Why CVaR for hydrothermal dispatch?
In hydrothermal systems, the primary source of uncertainty is river inflows. A sequence of dry years can deplete reservoirs and force the system to rely on expensive thermal generation or, in extreme cases, impose load curtailment. The expected cost may look acceptable, but the cost in drought scenarios can be catastrophic.
By incorporating CVaR into the SDDP objective, the optimizer builds policies that maintain higher reservoir levels as a hedge against drought. The resulting policy costs slightly more on average but avoids the worst tail outcomes – a trade-off that power system operators typically prefer.
How CVaR enters the SDDP algorithm
Cobre does not use pure CVaR in isolation. Instead, it uses a convex combination of expectation and CVaR:
During the backward pass, this combination changes only the aggregation weights used to combine per-scenario cut coefficients into a single cut. Scenarios with higher costs receive proportionally more weight, while low-cost scenarios receive less. The LP formulation, dual extraction, and cut structure remain unchanged.
Further reading
- Risk Measures – Overview of risk-averse vs risk-neutral SDDP
- Risk Measures (spec) – Complete formal specification including the dual representation of CVaR, the sorting-based weight computation algorithm, and the critical warning about lower bound validity
- Cut Management (spec) – How CVaR-modified aggregation weights affect cut coefficient computation
- SDDP Theory – How the forward-backward iteration works
Roadmap
This section describes planned features for Cobre that are not yet implemented. The features listed here represent the team’s current thinking about where the solver is headed — they are directional plans, not committed timelines or version targets.
Each feature has been analyzed for feasibility and grouped by theme. The thematic pages below provide detail on motivation, prerequisites, and planned approach for each feature.
Note: Feature C.5 (Non-Controllable Sources) was originally deferred but is now fully implemented. It appears in the table below for historical reference with status “Implemented”. All other features remain planned.
Feature Index
| ID | Feature | Theme | Effort |
|---|---|---|---|
| C.1 | GNL Thermal Plants | Equipment & Modeling | Large (3-4 wk) |
| C.2 | Battery Energy Storage Systems | Equipment & Modeling | Medium (2-3 wk) |
| C.3 | Multi-Cut Formulation | Algorithm Variants | Medium (2-3 wk) |
| C.4 | Markovian Policy Graphs | Algorithm Variants | Large (3-4 wk) |
| C.5 | Non-Controllable Sources | Equipment & Modeling | Implemented |
| C.6 | FPHA Enhancements | Equipment & Modeling | Med-Large (2-4 wk) |
| C.7 | Temporal Scope Decoupling | Algorithm Variants | Large (4-6 wk) |
| C.8 | CEPEL PAR(p)-A Variant | Stochastic Enhancements | Small-Med (1-2 wk) |
| C.9 | Policy Compatibility Validation | Tooling & Interfaces | Medium (2-3 wk) |
| C.10 | Fine-Grained Temporal Resolution | Stochastic Enhancements | Large (4-6 wk) |
| C.11 | User-Supplied Noise Openings | Stochastic Enhancements | Small (1 wk) |
| C.12 | Complete Tree Solver | Algorithm Variants | Med-Large (3-4 wk) |
| C.13 | Alternative Forward Pass | Performance & Parallelism | Medium (2-3 wk) |
| C.14 | Monte Carlo Backward Sampling | Stochastic Enhancements | Small (1 wk) |
| C.15 | Risk-Adjusted Forward Sampling | Stochastic Enhancements | Medium (2-3 wk) |
| C.16 | Revisiting Forward Pass | Performance & Parallelism | Small-Med (1-2 wk) |
| C.17 | Forward Pass State Deduplication | Performance & Parallelism | Small-Med (<1-3 wk) |
| C.18 | Pipelined Backward Pass | Performance & Parallelism | Medium (2-3 wk) |
| C.19 | Dynamic Forward-Passes Scheduler | Performance & Parallelism | TBD |
Each feature page below provides details on motivation, prerequisites, and planned approach.
Equipment & Modeling
This page covers planned extensions to the set of power system equipment types and production models that Cobre can simulate. These features expand the physical scope of the solver to cover generation technologies and accuracy improvements not included in the initial release.
C.1 GNL Thermal Plants
Gas Natural Liquefeito (GNL) thermal plants operate under complex fuel supply contracts with minimum take-or-pay obligations, variable spot market fuel costs, and start-up and shutdown constraints. The existing thermal model covers simple dispatchable units with fixed cost; GNL requires modeling the fuel inventory as an additional state variable and enforcing contract fulfillment constraints over time.
Why it is deferred: GNL modeling requires integer variables for unit commitment decisions. Extending SDDP to handle integer subproblems requires SDDiP infrastructure (Lagrangian relaxation or other duality handlers) — a significant architectural change that is out of scope for the initial release.
Prerequisites:
- Duality handler infrastructure for MIP subproblems (Lagrangian relaxation or strengthened Benders cuts)
- MIP solver integration (Gurobi, CPLEX, or an open-source alternative such as Cbc)
- GNL-specific data model extensions (fuel inventory, contract parameters)
Estimated effort: Large (3-4 weeks). Requires SDDiP infrastructure before GNL-specific modeling can begin.
See also: Deferred Features §C.1
C.2 Battery Energy Storage Systems
Grid-scale batteries introduce a state-of-charge dimension alongside the existing reservoir storage state. Unlike hydro reservoirs, batteries have symmetric charge/discharge efficiency losses and a capacity that degrades over operational lifetime. The LP formulation is linear — no integer variables are required — making this a more tractable extension than GNL.
Why it is deferred: Batteries require a new state variable dimension (state of charge per battery), integration of charge and discharge flows into bus load balance constraints, and output schema additions for battery simulation results. The data model schemas for batteries are already fully defined, so the main effort is LP construction and testing.
Prerequisites:
- State variable infrastructure supports a dynamic number of storage dimensions
- Bus balance constraint generation handles battery charge and discharge contributions
- Output schema for battery simulation results implemented in
cobre-io
Estimated effort: Medium (2-3 weeks). LP formulation is straightforward; the main effort is the data pipeline and realistic test cases.
See also: Deferred Features §C.2
C.5 Non-Controllable Sources (Wind/Solar)
Status: Implemented. Non-controllable sources (wind, solar, and other variable renewable generation) are fully specified and implemented. The LP formulation — including generation bounds, curtailment variables, and bus balance participation — is in Equipment Formulations §6. The entity schema, scenario pipeline, and curtailment penalty are also fully specified. This entry is retained for completeness.
See also: Equipment Formulations §6, Deferred Features §C.5
C.6 FPHA Enhancements
The core Four-Point Head Approximation (FPHA) model for hydro generation is implemented with a constant turbine efficiency. Three accuracy extensions are deferred:
Variable efficiency curves — Replace the constant efficiency coefficient with a flow-dependent hill chart approximation. The efficiency varies with turbine load as a polynomial function of the normalized flow. This captures the operating curve of real turbines and improves generation estimates away from the nominal operating point.
Pumped hydro production function — Extend the FPHA to model reversible hydro units that can operate in both generation and pumping mode. The pumping mode uses a reversed head approximation. Mutual exclusion between generation and pumping is enforced via a high-penalty relaxation (the alternative of binary SOS1 constraints is deferred along with general MIP support).
Dynamic FPHA recomputation — Periodically refit the FPHA hyperplanes based on the observed operating region during training, narrowing the volume window to match where the algorithm actually explores. This improves approximation quality in practice but requires careful management of cut validity across refitting events.
Why it is deferred: Core FPHA is operational and validated. These extensions are accuracy improvements with problem-dependent benefit. Variable efficiency requires hill chart data infrastructure; pumped hydro requires the unified gen/pump production function; dynamic recomputation requires online hyperplane fitting with cut validity tracking.
Prerequisites:
- Core FPHA operational and validated against reference implementations
- Hyperplane fitting infrastructure supports refitting with a new volume window
- Performance baseline established to measure accuracy improvements
Estimated effort: Medium-Large (2-4 weeks total across all three sub-features).
See also: Deferred Features §C.6, Hydro Production Models
Algorithm Variants
This page covers planned extensions to the core SDDP algorithm: alternative cut formulations, richer policy graph structures, and solver modes that address problem types not covered by the initial release.
C.3 Multi-Cut Formulation
The standard SDDP implementation uses a single-cut formulation: one aggregated Benders cut is added per backward pass iteration. The multi-cut formulation instead generates one cut per scenario in the opening tree. This provides more information per iteration at the cost of a larger LP at each stage.
The trade-off is well-studied: multi-cut converges in fewer iterations but each iteration is slower and uses more memory. Single-cut is better for large scenario counts and risk-averse configurations with CVaR; multi-cut is better for small scenario counts and risk-neutral settings.
Why it is deferred: Multi-cut requires the LP builder to handle a variable number of future cost variables (one per scenario instead of one aggregate), a cut pool indexed by scenario, and adapted cut selection logic. The interaction with CVaR risk measures requires careful analysis to ensure the cut validity guarantees are preserved.
Prerequisites:
- LP builder supports a configurable number of future cost variables per stage
- Cut pool is indexed by scenario identifier
- Cut selection strategy is adapted for per-scenario pools
Estimated effort: Medium (2-3 weeks). The core algorithm change has wide-reaching effects on cut management.
See also: Deferred Features §C.3, Cut Management
C.4 Markovian Policy Graphs
The current SDDP implementation assumes stage-wise independence: the same scenario tree structure is used at every stage regardless of which scenario was realized in the previous stage. Markovian policy graphs relax this assumption by introducing a Markov chain over “regimes” (for example, wet/dry/normal inflow regimes), where the transition to the next regime depends on the current one.
In this extension, the policy graph has nodes indexed by (stage, regime) rather than just stage. Cuts are regime-specific — they are only shared within nodes of the same regime. The state space grows by a factor equal to the number of Markov states.
Why it is deferred: Markovian policy graphs substantially increase algorithm complexity. The forward pass must track and sample regime transitions. The backward pass generates cuts for each (stage, markov_state) node. The cut pool, binary format, and cut selection all need to be extended with regime indexing. The data model is already prepared (the stages.json schema includes optional markov_states fields), but the algorithmic work is large.
Prerequisites:
- Policy graph supports multi-node-per-stage structure
- Cut pool indexed by
(stage, markov_state)tuples - Forward and backward pass logic handles Markov regime transitions
- Scenario generation respects regime-dependent inflow distributions
Estimated effort: Large (3-4 weeks). Fundamental change to the policy graph and forward/backward pass logic.
See also: Deferred Features §C.4, Input Scenarios
C.7 Temporal Scope Decoupling
The current SDDP formulation tightly couples three temporal scopes: the SDDP decomposition stage (where Benders cuts are generated), the physical time resolution of the constraints, and the stochastic process realization period. This forces a trade-off between fine temporal resolution (accurate physics, exponential cut growth) and coarse resolution (manageable cuts, poor short-term dynamics).
Temporal scope decoupling, inspired by the SPARHTACUS framework, allows each SDDP stage to contain multiple physical decision periods. Within a single stage, the LP chains multiple sub-period problems (period 1 feeds period 2, and so on). Cuts are still generated only at stage boundaries — they reference the state at the stage boundary, not intermediate periods — so the cut pool size does not increase even as temporal resolution within each stage improves.
The key advantage is that hourly or weekly resolution can be modeled within monthly SDDP stages without multiplying the cut pool size. The LP per stage grows proportionally to the number of sub-periods, but cut growth (the usual bottleneck) is unchanged.
Why it is deferred: This requires significant architectural changes to LP construction (multi-period sub-problem chaining within a stage), modified forward and backward pass logic, data model changes (a periods array within stages), and careful interaction with chronological block formulations.
Prerequisites:
- Core SDDP training loop validated and stable
- Chronological block formulation operational
- Performance profiling showing cut growth as the binding bottleneck
Estimated effort: Large (4-6 weeks). Fundamental change to LP construction, the data model, and the algorithm.
See also: Deferred Features §C.7
C.12 Complete Tree Solver
The complete tree solver replaces SDDP’s sample-based forward and backward passes with deterministic traversal of an explicit scenario tree. Instead of sampling scenarios, all nodes in the tree are enumerated and a subproblem is solved at each node. The result is an exact solution to the stochastic program (relative to the given tree discretization), matching the behavior of CEPEL’s DECOMP model.
The LP construction per node is identical to the SDDP stage subproblem — the complete tree mode reuses the existing LP builder. The difference is purely in the traversal logic (BFS/DFS enumeration of all tree nodes vs. random sampling) and cut aggregation (tree-weighted aggregation vs. sample-averaged aggregation).
Why it is deferred: Full tree traversal requires infrastructure for enumerating tree nodes, distributing them across MPI ranks, and storing results for potentially millions of nodes. The convergence criterion also changes: rather than a statistical lower bound, convergence means closing the Benders gap on the tree exactly.
Prerequisites:
- Core SDDP training loop operational
- Opening tree infrastructure supports variable per-stage branching counts
- External scenario integration validated
- Performance profiling establishes tractability bounds for target problem sizes
Estimated effort: Medium-Large (3-4 weeks). LP construction is reused; main effort is tree traversal, MPI node distribution, and result aggregation.
See also: Deferred Features §C.12, Scenario Generation §7
Stochastic Enhancements
This page covers planned improvements to the stochastic modeling and sampling layers of Cobre. These features extend the inflow model, allow finer temporal resolution, add flexibility to the noise generation pipeline, and introduce sampling variants for the backward pass and forward pass.
C.8 CEPEL PAR(p)-A Variant
The standard PAR(p) inflow model is implemented and validated. The CEPEL PAR(p)-A variant extends it with four refinements primarily relevant to basins with highly skewed inflow distributions:
- Maximum AR order fixed at 12 to enforce an annual cycle
- Stationarity enforcement via a coefficient constraint
- Lognormal transformation: the model fits on
log(inflow)rather than the raw inflow, which prevents synthetic inflow values from going negative - Regional correlation between hydro plants in the same river basin
The lognormal variant is mainly needed when inflow distributions are highly right-skewed and the standard model produces negative synthetic values with non-negligible probability. The inflow non-negativity handling strategies already mitigate this for the standard model in most basins.
Why it is deferred: The standard PAR(p) model covers most practical use cases. The PAR(p)-A variant is a refinement for specific basin characteristics. The current input format (inflow_seasonal_stats.parquet and inflow_ar_coefficients.parquet) is already compatible with PAR(p)-A — the lognormal transformation is applied during history preprocessing before computing the seasonal statistics.
Prerequisites:
- Standard PAR(p) fitting and validation operational
- Lognormal transformation infrastructure (log-space fitting, back-transformation)
- Validation suite comparing PAR(p) and PAR(p)-A on representative basins
Estimated effort: Small-Medium (1-2 weeks). The mathematical extensions are straightforward; the main effort is validation and testing.
See also: Deferred Features §C.8, PAR Inflow Model
C.10 Fine-Grained Temporal Resolution (Typical Days)
The current block formulation represents each SDDP stage with a small number of load blocks (for example, peak, shoulder, and off-peak) that aggregate monthly hours by load level. This is adequate for long-term planning but cannot model daily cycling patterns — daily storage behavior for pumped hydro and batteries, hourly renewable generation profiles, time-of-use pricing, or intra-day ramp constraints.
The planned extension introduces representative typical day types (for example, weekday and weekend) within each SDDP stage, each containing a sequence of chronological hourly blocks. This enables accurate daily sub-structure without increasing the cut pool size (cuts are still generated at stage boundaries, not within day types).
Key open design questions that require research before implementation:
- Day-type chaining: Should the end-of-day storage from one day type carry forward to the next day type within the same stage, or should each day type operate independently with a weighted average end-of-stage storage?
- Objective scaling: Block durations are actual hours (for water balance), but the objective contribution must be scaled by how many days each day type represents.
- Two-phase architecture: Training with aggregated blocks followed by simulation with full typical-day resolution. Cut compatibility conditions between the two phases need formal verification.
Why it is deferred: This feature requires research on the open design questions before implementation can begin. The LP size per stage grows substantially (from 3 blocks to 72 or more), and the interaction with existing block formulations is complex.
Prerequisites:
- Core parallel and chronological block modes operational and validated
- Simulation architecture supports variable block configurations
- Research on day-type chaining and two-phase cut compatibility completed
Estimated effort: Large (4-6 weeks). Significant input schema design, LP construction changes, and research required.
See also: Deferred Features §C.10
C.11 User-Supplied Noise Openings
The standard noise generation pipeline samples independent Gaussian noise vectors and applies Cholesky correlation. This pipeline covers most use cases, but some workflows require direct control over the noise values:
- Importing noise realizations from external stochastic models that use non-Gaussian distributions
- Reproducing exact noise sequences from legacy tools for validation
- Using domain-specific spatial correlation structures not captured by the Cholesky approach
- Research workflows where specific noise patterns are under study
The planned mechanism is a scenarios/noise_openings.parquet file. When this file is present, the scenario generator skips internal noise sampling and Cholesky correlation entirely, loading the user-supplied values directly into the opening tree.
Open design questions to resolve before implementation: the relationship to the existing external scenario mechanism (with noise inversion), what validation checks should be applied to user-supplied noise, whether load entity noise should be included alongside inflow noise, and whether separate noise sets are needed for forward and backward passes.
Prerequisites:
- Opening tree architecture implemented and validated
- Forward/backward noise separation operational
- Clear use case catalog that cannot be served by the existing external scenario mechanism
Estimated effort: Small (1 week). Input loading and validation are straightforward once the design questions are resolved.
See also: Deferred Features §C.11, Scenario Generation §2.3
C.14 Monte Carlo Backward Sampling
The standard backward pass evaluates all openings in the opening tree at each backward stage. When the opening count is large (500 or more, for high-fidelity tail representation), the backward pass dominates iteration time. Monte Carlo backward sampling replaces full enumeration with a sample of n openings drawn with replacement from the tree, reducing backward pass cost from O(N_openings) to O(n) LP solves per stage per trial point.
The resulting cut is an unbiased estimator of the full cut but with higher variance. The trade-off relative to the default full evaluation: fewer solves per iteration, but non-monotonic lower bound behavior (which complicates convergence monitoring) and slower per-iteration convergence.
Why it is deferred: The default complete evaluation is reliable and performant for typical production opening counts (50-200). Monte Carlo sampling introduces non-monotonic lower bounds, which require adaptations to convergence monitoring. The benefit depends on the chosen n relative to N_openings, which is problem-dependent.
Prerequisites:
- Core SDDP with complete backward sampling validated
- Convergence monitoring supports non-monotonic lower bounds
- Empirical study of the
nvs. convergence rate trade-off
Estimated effort: Small (1 week). Sampling infrastructure is trivial; the main effort is convergence monitoring adaptation.
See also: Deferred Features §C.14
C.15 Risk-Adjusted Forward Sampling
Standard forward sampling draws scenarios uniformly from the opening tree. For strongly risk-averse policies (CVaR with weight lambda close to 1.0), uniform sampling under-explores the worst-case tail scenarios that matter most for the risk measure.
Risk-adjusted forward sampling biases the forward pass toward tail scenarios by evaluating the risk measure over candidate noise terms at each forward stage and re-weighting or re-sampling the next-stage noise accordingly. A complementary importance sampling variant weights forward trajectories by their likelihood ratio under the risk-adjusted distribution, enabling tighter upper bound estimates for risk-averse settings.
Why it is deferred: Integration with the CVaR risk measure configuration is non-trivial, and importance weights must be handled carefully in upper bound estimation. Default uniform sampling is sufficient for most applications; the benefit is primarily for strongly risk-averse configurations.
Prerequisites:
- CVaR risk measure implemented and validated
- Forward sampling scheme abstraction supports per-stage re-weighting
- Upper bound evaluation handles importance-weighted trajectories
Estimated effort: Medium (2-3 weeks). The algorithm is well-documented in the literature; the main effort is integration with the risk measure and convergence analysis.
See also: Deferred Features §C.15, Risk Measures
Performance & Parallelism
This page covers planned optimizations to the SDDP training loop that reduce computation time, improve state space exploration, or exploit parallel hardware more effectively. These features are motivated by profiling observations rather than new algorithmic capabilities — they make the existing algorithm faster or more thorough, without changing its fundamental behavior.
C.13 Alternative Forward Pass
The default forward pass solves the training LP, which excludes simulation-only features (linearized head, unit commitment, bottom discharge) to preserve convexity for valid cut generation. Trial points from this simplified model may not represent states that are realistic under full operational modeling, potentially slowing convergence.
The alternative forward pass maintains two LP models per stage: the training LP (convex, used for backward pass cut generation) and an alternative LP (includes simulation-only features, used for the forward pass to generate more realistic trial points). After each backward pass, new cuts are added to both models.
Cuts remain valid because they are always generated from the convex training LP. Trial points are more realistic because they come from the richer alternative LP. The trade-off: memory approximately doubles (two LP models per stage), and convergence may be slower because forward trial points are not optimal for the training model.
Why it is deferred: Maintaining two parallel LP models per stage doubles memory and complicates solver workspace management. The benefit depends on how much simulation-only features change the trial points, which is problem-dependent and requires empirical investigation.
Prerequisites:
- Core SDDP training loop operational and validated
- Simulation-only LP construction (linearized head, unit commitment) implemented
- Solver workspace infrastructure supports multiple LP models per stage
Estimated effort: Medium (2-3 weeks). LP construction infrastructure is reused; the main effort is dual LP management, cut copying, and convergence testing.
See also: Deferred Features §C.13, Simulation Architecture
C.16 Revisiting Forward Pass
Standard forward passes always start from the initial state at stage 1. In problems with large state spaces, repeated iterations can visit similar states and generate cuts in the same regions, leaving parts of the state space poorly covered.
The revisiting forward pass maintains a buffer of previously visited states from past iterations. With some probability, a forward pass starts from a randomly selected historical state at a randomly selected stage instead of from stage 1. The resulting trial points generate cuts in regions that standard forward passes have not recently visited.
Why it is deferred: Starting a forward pass from an intermediate stage produces a partial trajectory that does not contribute a full-horizon cost estimate. This complicates upper bound estimation. The benefit is primarily for problems where standard forward passes provably concentrate in a narrow region of the state space.
Prerequisites:
- Core SDDP training loop validated
- State history buffer infrastructure
- Convergence monitoring handles partial-trajectory iterations
Estimated effort: Small-Medium (1-2 weeks). The state buffer is straightforward; the main effort is convergence analysis for partial trajectories.
See also: Deferred Features §C.16
C.17 Forward Pass State Deduplication
When multiple forward scenarios visit identical or near-identical states at a given stage, the backward pass redundantly evaluates the cost-to-go from duplicate trial points. Identical states produce identical cuts, so the duplication adds no information.
Two approaches are planned:
- Exact deduplication — Hash-based deduplication of state vectors with identical values. Straightforward to implement but limited in benefit, since exact duplicates are uncommon in problems with continuous state spaces.
- Approximate deduplication — Merge states within a tolerance using spatial indexing (for example, k-d tree). Greater reduction in backward solves, but introduces approximation in cut coefficients. Requires analysis of convergence implications before deployment.
Why it is deferred: Exact duplicates are uncommon, making exact deduplication a marginal optimization. Approximate deduplication requires careful convergence analysis. This feature should be implemented only when profiling shows backward pass cost is dominated by trial point count rather than per-solve cost.
Prerequisites:
- Core SDDP training loop validated and profiled
- Backward pass timing data identifying trial point count as the dominant cost factor
Estimated effort: Small (less than 1 week) for exact deduplication; Medium (2-3 weeks) for approximate deduplication with convergence analysis.
See also: Deferred Features §C.17, Training Loop §5.2
C.18 Pipelined Backward Pass
The standard sequential backward pass uses the cut approximation from the current iteration at each stage. This requires a synchronization barrier between stages: stage t cannot begin its backward solve until stage t+1 has finished and broadcast its cuts.
The pipelined backward pass uses the previous iteration’s approximation instead. This eliminates per-stage barriers and allows backward stages to proceed in a pipeline — stage t begins its solve while stage t+1 is still communicating cuts via non-blocking MPI collectives (MPI_Iallgatherv). The result is overlapped communication and computation.
The trade-off: pipelined cuts are looser (older information), so more iterations are needed to converge. Whether the shorter wall-clock time per iteration outweighs the slower per-iteration convergence depends on hardware-specific communication latency, which cannot be determined without profiling production workloads.
When to consider: Profiling shows backward pass per-stage barrier synchronization accounts for more than 20% of backward pass time. Most likely with very large stage counts (more than 100 stages) and high inter-node network latency.
Why it is deferred: The sequential mode is simpler, produces tighter cuts, and is the default in SDDP.jl and most production implementations. The pipelining benefit is hardware-specific.
Prerequisites:
- Core SDDP training loop validated and profiled
- Backward pass timing data showing barrier synchronization as a bottleneck
- Non-blocking MPI collective support in ferrompi (
MPI_Iallgatherv)
Estimated effort: Medium (2-3 weeks). Requires async state management, non-blocking collective wrappers, and convergence regression testing.
See also: Deferred Features §C.18, Communication Patterns
C.19 Dynamic Forward-Passes Scheduler
The number of forward passes per iteration (forward_passes) is currently set statically in the configuration. A dynamic scheduler would adjust this count during training based on convergence metrics (for example, increasing forward passes when the lower bound is stagnant) or wall-clock budget (for example, maintaining a fixed seconds-per-iteration target).
Why it is deferred: The cut pool is pre-allocated using the formula warm_start_cuts + max_iterations × forward_passes with a deterministic slot assignment. A dynamic scheduler would require either a worst-case static allocation (wasteful for most runs) or dynamic reallocation (which invalidates the deterministic slot assignment and complicates reproducibility). The right approach requires profiling data from production workloads.
See also: Deferred Features §C.19, Cut Management Implementation §1.3
Tooling & Interfaces
This page covers planned additions to the tooling ecosystem around the Cobre solver: validation tooling for trained policies, and the three interface crates that expose Cobre to different consumer contexts (AI agents via MCP, Python workflows via PyO3, and interactive terminal monitoring via ratatui).
C.9 Policy Compatibility Validation
When the solver runs in simulation-only mode, warm-start mode, or resumes from a checkpoint, it must validate that the current input data is compatible with the previously trained policy. The policy (cut coefficients) encodes LP structural information: the number of state variables, the constraint topology, the block configuration, the penalty values. If any of these change between training and simulation, the cuts become invalid and produce silently incorrect results.
The planned mechanism has two components:
- Policy metadata record — During training, the solver persists a metadata record alongside the cut data, capturing all input properties that affect LP structure. The record is versioned for forward compatibility.
- Validation phase — At the start of simulation or warm-start, the current input is compared against the metadata. Any mismatch produces a hard error with a clear description of what changed.
Properties that must be validated include: block mode and block count per stage, number of hydro plants and their AR orders, cascade topology, bus and line count, thermal and contract counts, production model per hydro, and penalty configuration. Some properties may allow controlled relaxation in the future (for example, adding a new thermal plant at the end of the generator list might be compatible if the state variable dimensions are unchanged), but the initial implementation validates everything strictly.
Why it is deferred: This is a cross-cutting concern touching training, simulation, checkpointing, and input loading. All prerequisite specs are now approved, and C.9 is unblocked pending a dedicated specification that defines the complete property list, the metadata format, the validation algorithm, and the error reporting format.
Prerequisites (all now met):
- Training loop architecture finalized — Training Loop approved
- Checkpoint format defined — Checkpointing and Binary Formats §3-§4 approved
- Simulation architecture finalized — Simulation Architecture approved
- Input loading pipeline defined — Input Loading Pipeline approved
Estimated effort: Medium (2-3 weeks). Primarily specification and testing; implementation is straightforward once the property list is defined.
See also: Deferred Features §C.9, Binary Formats
MCP Server (cobre-mcp)
The MCP server exposes Cobre as a first-class tool for AI coding agents via the Model Context Protocol. It runs as a standalone binary (cobre-mcp) or as a cobre serve subcommand, in single-process mode without MPI. Computation is delegated to cobre-sddp; all tool responses use the structured output envelope defined in Structured Output.
The server exposes Cobre’s run, validate, and report capabilities as MCP tools, with streaming progress updates for long-running training jobs. Multi-process execution via TCP or shared memory backends is architecturally possible but deferred pending demonstrated demand from MCP-based agent workflows.
The full specification is in MCP Server.
Python Bindings (cobre-python)
The Python bindings expose Cobre’s solver to Python workflows as the cobre module via PyO3. The module compiles to a shared library (cdylib) that is installed and imported like any other Python package.
Key design points: the GIL is released during all Rust computation; NumPy and Arrow FFI provide zero-copy data paths; MPI is prohibited from the Python interface (multi-process execution uses TCP or shared memory backends instead). The Python exception hierarchy maps to Cobre’s structured error kind registry.
The full specification is in Python Bindings.
Terminal UI (cobre-tui)
The terminal UI provides real-time monitoring of SDDP training runs in the terminal. It is built on ratatui and renders convergence plots, iteration timing breakdowns, cut statistics, resource usage, and MPI communication metrics.
The TUI operates in two modes: co-hosted within the cobre binary via an in-process broadcast channel (sharing the same process as the solver), or standalone reading JSON-lines from stdin for monitoring remote or already-running jobs. Interactive features — pause/resume, cut inspection, scenario comparison, stopping rule adjustment — all operate at iteration boundaries to preserve training loop atomicity.
The full specification is in Terminal UI.
Overview
Note: These specifications were written before implementation to define contracts and interfaces. With all 8 phases complete, the source of truth for behavior is the source code and the software book. These specs remain as reference for the design rationale behind implementation decisions.
Internal development artifacts: This section is intended for Cobre contributors and maintainers. The specs document design decisions, trait contracts, and implementation constraints that were authored before the code was written. If you are here to understand the mathematics or algorithms, the Theory section is the recommended starting point.
This section contains the foundational specifications that underpin all other sections of the Cobre documentation. It establishes the design philosophy that guides every architectural and algorithmic decision, the notation conventions that ensure consistency across all mathematical and data-model specs, and the production-scale reference dimensions that anchor performance analysis and memory budget calculations throughout the HPC specs.
These three specs are prerequisites for reading any other specification section. They are referenced pervasively – design principles inform trade-off discussions in the architecture specs, notation conventions define the symbols used in every equation, and production-scale dimensions appear whenever a spec quantifies communication volume, memory footprint, or computational cost.
Reading Order
The specs are short and self-contained; reading them in order takes under fifteen minutes:
- Design Principles – The 9 foundational principles guiding the Cobre solver design. These principles are cited throughout the architecture and HPC specs to justify specific design choices.
- Notation Conventions – Index sets, symbols, and unit conventions used throughout all mathematical formulations. Required context before reading any spec in the Mathematical Formulations section.
- Production Scale Reference – Representative problem dimensions for a national-scale hydrothermal system (number of plants, stages, scenarios, state dimension). Referenced by every spec that performs sizing analysis or communication volume estimation.
Spec Index
| Spec | Description |
|---|---|
| Design Principles | Foundational design goals and trade-off principles that govern all architectural decisions |
| Notation Conventions | Index sets, mathematical symbols, physical units, and naming conventions for the specification suite |
| Production Scale Reference | Concrete problem dimensions for a national-scale hydrothermal dispatch system, used for sizing and performance analysis |
| Decision Log | Central registry of cross-cutting architectural decisions affecting two or more spec files |
Navigation
The Specifications section contains 7 subsections: Overview (this section), Mathematical Formulations, Data Model, Architecture, High-Performance Computing, Configuration, and Deferred Features. Readers encountering the specs for the first time should complete the three overview specs before proceeding to any other subsection.
Cross-Reference Index
This page provides a centralized navigation index for the 79 specification files in the Cobre documentation. It is designed to help implementers determine which specs to read for a given crate, in what order, and how specs relate to each other through cross-references.
The index has five components:
- Spec-to-Crate Mapping Table – which crate(s) each spec belongs to
- Per-Crate Reading Lists – ordered reading lists for each of the 11 crates
- Outgoing Cross-Reference Table – for each spec, which other specs it references
- Incoming Cross-Reference Table – for each spec, which other specs reference it
- Dependency Ordering – a global topological reading order for the entire corpus
Errata resolved: Seven HIGH-severity section-number errors (F-1, F-5, F-6, F-7, F-8, F-9, F-11) were identified in the Epic 03 cross-reference audit and corrected in Epic 06 remediation. All section-number references now point to the correct targets.
1. Spec-to-Crate Mapping Table
| # | Spec File | Section | Primary Crate | Secondary Crate(s) |
|---|---|---|---|---|
| 1 | design-principles.md | overview | cobre-core, cobre-io | All crates (cross-cutting) |
| 2 | notation-conventions.md | overview | (cross-cutting) | All crates |
| 3 | production-scale-reference.md | overview | cobre-sddp, cobre-solver | ferrompi, cobre-io |
| 73 | implementation-ordering.md | overview | (cross-cutting) | All crates |
| 74 | spec-gap-inventory.md | overview | (cross-cutting) | All crates |
| 4 | input-directory-structure.md | data-model | cobre-io | cobre-core, cobre-cli |
| 5 | input-system-entities.md | data-model | cobre-core | cobre-io |
| 6 | input-hydro-extensions.md | data-model | cobre-core | cobre-io |
| 7 | input-scenarios.md | data-model | cobre-io, cobre-stochastic | cobre-core |
| 8 | input-constraints.md | data-model | cobre-io | cobre-core, cobre-sddp |
| 9 | penalty-system.md | data-model | cobre-core | cobre-sddp |
| 10 | internal-structures.md | data-model | cobre-core | cobre-sddp, cobre-stochastic |
| 11 | output-schemas.md | data-model | cobre-io | cobre-sddp |
| 12 | output-infrastructure.md | data-model | cobre-io | ferrompi, cobre-sddp |
| 13 | binary-formats.md | data-model | cobre-io | cobre-sddp, cobre-solver |
| 14 | sddp-algorithm.md | math | cobre-sddp | – |
| 15 | lp-formulation.md | math | cobre-sddp | cobre-core, cobre-solver |
| 16 | system-elements.md | math | cobre-core | cobre-sddp |
| 17 | block-formulations.md | math | cobre-sddp | – |
| 18 | hydro-production-models.md | math | cobre-sddp | cobre-core |
| 19 | cut-management.md | math | cobre-sddp | – |
| 20 | discount-rate.md | math | cobre-sddp | – |
| 21 | infinite-horizon.md | math | cobre-sddp | – |
| 22 | risk-measures.md | math | cobre-sddp | – |
| 23 | inflow-nonnegativity.md | math | cobre-sddp | cobre-stochastic |
| 24 | par-inflow-model.md | math | cobre-stochastic | cobre-io, cobre-core |
| 25 | equipment-formulations.md | math | cobre-sddp | cobre-core |
| 26 | stopping-rules.md | math | cobre-sddp | – |
| 27 | upper-bound-evaluation.md | math | cobre-sddp | – |
| 28 | training-loop.md | architecture | cobre-sddp | cobre-solver, cobre-stochastic |
| 29 | simulation-architecture.md | architecture | cobre-sddp | cobre-io, cobre-stochastic |
| 30 | cli-and-lifecycle.md | architecture | cobre-cli | – |
| 31 | validation-architecture.md | architecture | cobre-io | cobre-cli |
| 32 | input-loading-pipeline.md | architecture | cobre-io | cobre-core |
| 33 | scenario-generation.md | architecture | cobre-stochastic | cobre-sddp |
| 34 | solver-abstraction.md | architecture | cobre-solver | – |
| 35 | solver-highs-impl.md | architecture | cobre-solver | – |
| 36 | solver-clp-impl.md | architecture | cobre-solver | – |
| 37 | solver-workspaces.md | architecture | cobre-solver | – |
| 76 | performance-adaptation-layer.md | architecture | cobre-sddp | – |
| 38 | cut-management-impl.md | architecture | cobre-sddp | cobre-io |
| 39 | convergence-monitoring.md | architecture | cobre-sddp | – |
| 40 | extension-points.md | architecture | cobre-sddp | cobre-stochastic, cobre-io |
| 41 | work-distribution.md | hpc | cobre-sddp | ferrompi |
| 42 | hybrid-parallelism.md | hpc | cobre-sddp | ferrompi, cobre-solver |
| 43 | communication-patterns.md | hpc | ferrompi | cobre-sddp |
| 44 | memory-architecture.md | hpc | cobre-sddp | cobre-solver |
| 45 | shared-memory-aggregation.md | hpc | cobre-sddp | ferrompi |
| 46 | checkpointing.md | hpc | cobre-sddp | cobre-io, cobre-cli |
| 47 | slurm-deployment.md | hpc | cobre-cli | ferrompi |
| 48 | synchronization.md | hpc | cobre-sddp | ferrompi |
| 49 | configuration-reference.md | configuration | cobre-cli | cobre-sddp, cobre-stochastic, cobre-core |
| 50 | deferred.md | deferred | (multi-crate) | See audit report section 2.2 |
| 51 | structured-output.md | interfaces | cobre-cli | cobre-mcp, cobre-python |
| 52 | mcp-server.md | interfaces | cobre-mcp | cobre-cli |
| 53 | python-bindings.md | interfaces | cobre-python | cobre-cli |
| 54 | terminal-ui.md | interfaces | cobre-tui | cobre-cli |
| 55 | communicator-trait.md | hpc | cobre-comm | cobre-sddp |
| 56 | backend-selection.md | hpc | cobre-comm | cobre-sddp, cobre-cli |
| 57 | backend-ferrompi.md | hpc | cobre-comm | ferrompi |
| 58 | backend-local.md | hpc | cobre-comm | – |
| 59 | backend-tcp.md | hpc | cobre-comm | – |
| 60 | backend-shm.md | hpc | cobre-comm | – |
| 61 | risk-measure-trait.md | architecture | cobre-sddp | – |
| 62 | risk-measure-testing.md | architecture | cobre-sddp | – |
| 63 | horizon-mode-trait.md | architecture | cobre-sddp | – |
| 64 | horizon-mode-testing.md | architecture | cobre-sddp | – |
| 65 | sampling-scheme-trait.md | architecture | cobre-stochastic | cobre-sddp |
| 66 | sampling-scheme-testing.md | architecture | cobre-stochastic | cobre-sddp |
| 67 | cut-selection-trait.md | architecture | cobre-sddp | – |
| 68 | cut-selection-testing.md | architecture | cobre-sddp | – |
| 69 | stopping-rule-trait.md | architecture | cobre-sddp | – |
| 70 | stopping-rule-testing.md | architecture | cobre-sddp | – |
| 71 | solver-interface-trait.md | architecture | cobre-solver | – |
| 72 | solver-interface-testing.md | architecture | cobre-solver | – |
| 73 | backend-testing.md | hpc | cobre-comm | – |
| 74 | ecosystem-guidelines.md | overview | (cross-cutting) | All crates |
| 75 | ecosystem-vision.md | overview | (cross-cutting) | All crates |
| 79 | decision-log.md | overview | (cross-cutting) | All crates |
2. Per-Crate Reading Lists
Specs are ordered by reading dependency: foundational specs (referenced by many others) appear first. Where no dependency exists, order follows section precedence (overview, math, data-model, architecture, hpc, configuration, deferred). Secondary specs are marked with “(secondary)”.
cobre-sddp
This crate owns the SDDP algorithm, training loop, LP construction, cut management, simulation, convergence, risk measures, work distribution, synchronization, and memory architecture. 33 primary specs, 12 secondary.
- LP Formulation
- Cut Management
- SDDP Algorithm
- Configuration Reference (secondary)
- Scenario Generation (secondary)
- Penalty System (secondary)
- Training Loop
- Risk Measures
- Binary Formats (secondary)
- Stopping Rules
- Input Constraints (secondary)
- Memory Architecture
- Discount Rate
- Hybrid Parallelism
- Hydro Production Models
- Upper Bound Evaluation
- System Elements (secondary)
- Block Formulations
- Infinite Horizon
- Internal Structures (secondary)
- Production Scale Reference
- Equipment Formulations
- Output Schemas (secondary)
- Cut Management Implementation
- Work Distribution
- Communication Patterns (secondary)
- Shared Memory Aggregation
- Checkpointing
- Output Infrastructure (secondary)
- Convergence Monitoring
- Synchronization
- Inflow Non-Negativity
- Simulation Architecture
- Extension Points
- Performance Adaptation Layer
- Risk Measure Trait
- Risk Measure Testing
- Horizon Mode Trait
- Horizon Mode Testing
- Sampling Scheme Trait (secondary)
- Sampling Scheme Testing (secondary)
- Cut Selection Strategy Trait
- Cut Selection Testing
- Stopping Rule Trait
- Stopping Rule Testing
- Communicator Trait (secondary)
- Backend Selection (secondary)
- Implementation Ordering (secondary)
- Spec Gap Inventory (secondary)
- Ecosystem Guidelines (secondary)
- Ecosystem Vision (secondary)
- Decision Log (secondary)
cobre-core
This crate owns entity types, internal structures, penalty system, and design principles. 6 primary specs, 9 secondary.
- LP Formulation (secondary)
- Configuration Reference (secondary)
- Penalty System
- Input System Entities
- Input Scenarios (secondary)
- Design Principles
- Input Constraints (secondary)
- PAR Inflow Model (secondary)
- Hydro Production Models (secondary)
- Input Directory Structure (secondary)
- System Elements
- Input Hydro Extensions
- Internal Structures
- Equipment Formulations (secondary)
- Input Loading Pipeline (secondary)
- Implementation Ordering (secondary)
- Spec Gap Inventory (secondary)
- Ecosystem Guidelines (secondary)
- Ecosystem Vision (secondary)
- Decision Log (secondary)
Phase 2 Module-to-Spec Mapping (cobre-core)
The following table maps each Rust module added in Phase 2 to the spec section(s) it implements.
| Module | Rust File | Primary Spec Section(s) |
|---|---|---|
temporal | src/temporal.rs | Input Scenarios §1.1–1.10 (stages, blocks, seasons, policy graph, state variables, risk measure, noise method) |
scenario | src/scenario.rs | Input Scenarios §2–5 (PAR model parameters, load statistics, correlation model, scenario source) |
initial_conditions | src/initial_conditions.rs | Input Constraints §1 (initial storage and filling-storage arrays) |
generic_constraint | src/generic_constraint.rs | Input Constraints §3 (generic linear constraint in-memory representation, expression grammar hook) |
resolved | src/resolved.rs | Penalty System §3 (pre-resolved O(1) penalty containers); Input Constraints §2 (pre-resolved O(1) bound containers) |
cobre-io
This crate owns input parsing, output writing, validation, binary formats, and the loading pipeline. 9 primary specs, 8 secondary.
- Design Principles
- Input System Entities (secondary)
- Input Scenarios
- Binary Formats
- Input Constraints
- PAR Inflow Model (secondary)
- Input Directory Structure
- Input Hydro Extensions (secondary)
- Production Scale Reference (secondary)
- Output Schemas
- Cut Management Implementation (secondary)
- Checkpointing (secondary)
- Output Infrastructure
- Validation Architecture
- Input Loading Pipeline
- Simulation Architecture (secondary)
- Extension Points (secondary)
- Implementation Ordering (secondary)
- Spec Gap Inventory (secondary)
- Ecosystem Guidelines (secondary)
- Ecosystem Vision (secondary)
- Decision Log (secondary)
Phase 2 Module-to-Spec Mapping (cobre-io)
The following table maps each public Rust module in crates/cobre-io/src/ to the spec section(s) it implements.
| Module | Rust Path | Primary Spec Section(s) |
|---|---|---|
lib | src/lib.rs | Input Loading Pipeline §8.1 (load_case public API, LoadError enum) |
error | src/error.rs | Input Loading Pipeline §8.1 (LoadError six-variant enum) |
pipeline | src/pipeline.rs | Input Loading Pipeline §2–7 (five-layer pipeline orchestration, resolution, scenario assembly, SystemBuilder construction) |
config | src/config.rs | Input Directory Structure §2 (config.json schema); Configuration Reference §3–7 |
stages | src/stages.rs | Input Scenarios §1 (stages.json schema, policy graph, scenario source) |
initial_conditions | src/initial_conditions.rs | Input Constraints §1 (initial_conditions.json parser) |
penalties | src/penalties.rs | Penalty System §1 (penalties.json global defaults parser) |
broadcast | src/broadcast.rs | Binary Formats §2 (postcard MPI broadcast, DEC-002); Input Loading Pipeline §6.1–6.4 |
report | src/report.rs | Validation Architecture §5 (ValidationReport JSON serialization) |
validation::mod | src/validation/mod.rs | Validation Architecture §3–4 (ValidationContext, ErrorKind catalog, Severity) |
validation::structural | src/validation/structural.rs | Validation Architecture §2.1 (Layer 1: structural); Input Directory Structure §1 (FileManifest, 33-file inventory) |
validation::schema | src/validation/schema.rs | Validation Architecture §2.2 (Layer 2: schema) |
validation::referential | src/validation/referential.rs | Validation Architecture §2.3 (Layer 3: referential integrity); Input Loading Pipeline §2.6 (26-rule cross-reference checklist) |
validation::dimensional | src/validation/dimensional.rs | Validation Architecture §2.4 (Layer 4: dimensional consistency) |
validation::semantic | src/validation/semantic.rs | Validation Architecture §2.5 (Layer 5: semantic rules — GNL rejection, penalty ordering, PAR stationarity, acyclic cascade) |
system | src/system/ | Input System Entities §1–7 (entity registry parsers for all 7 entity types); Input Hydro Extensions §1–3 |
extensions | src/extensions/ | Input Hydro Extensions §1–3 (FPHA hyperplanes, hydro geometry, production models) |
constraints | src/constraints/ | Input Constraints §2–4 (bounds Parquet parsers, penalty override parsers, exchange factors, generic constraints, generic constraint bounds) |
scenarios | src/scenarios/ | Input Scenarios §3–5 (PAR coefficients, seasonal stats, inflow history, load factors, correlation, external scenarios, assembly) |
resolution | src/resolution/ | Input Loading Pipeline §5 (three-tier sparse-to-dense expansion); Penalty System §3 (penalty cascade); Input Constraints §2 (bound cascade) |
output | src/output/ | Output Schemas §1–6 (stub — Phase 7 scope); Output Infrastructure §1–6 (stub — Phase 7 scope); Binary Formats §3 (FlatBuffers stub — Phase 7 scope) |
parquet_helpers | src/parquet_helpers.rs | (internal) Binary Formats §2.2 (Parquet column extraction helpers, Parquet input format per DEC-004) |
cobre-stochastic
This crate owns the PAR model, scenario generation, noise correlation, and sampling scheme abstraction. 5 primary specs, 6 secondary.
- Configuration Reference (secondary)
- Scenario Generation
- Training Loop (secondary)
- Input Scenarios
- PAR Inflow Model
- Internal Structures (secondary)
- Inflow Non-Negativity (secondary)
- Simulation Architecture (secondary)
- Extension Points (secondary)
- Sampling Scheme Trait
- Sampling Scheme Testing
- Implementation Ordering (secondary)
- Spec Gap Inventory (secondary)
- Ecosystem Guidelines (secondary)
- Ecosystem Vision (secondary)
- Decision Log (secondary)
cobre-solver
This crate owns the solver abstraction, HiGHS and CLP implementations, workspaces, and solver interface trait. 7 primary specs, 4 secondary.
- LP Formulation (secondary)
- Binary Formats (secondary)
- Solver Abstraction
- Solver Interface Trait
- Solver Interface Testing
- Memory Architecture (secondary)
- Hybrid Parallelism (secondary)
- Solver Workspaces
- Production Scale Reference
- Solver HiGHS Implementation
- Solver CLP Implementation
- Implementation Ordering (secondary)
- Spec Gap Inventory (secondary)
- Ecosystem Guidelines (secondary)
- Ecosystem Vision (secondary)
- Decision Log (secondary)
cobre-cli
This crate owns CLI lifecycle, config parsing, and SLURM deployment. 3 primary specs, 3 secondary.
- Configuration Reference
- Input Directory Structure (secondary)
- CLI and Lifecycle
- Checkpointing (secondary)
- Validation Architecture (secondary)
- SLURM Deployment
- Implementation Ordering (secondary)
- Spec Gap Inventory (secondary)
- Ecosystem Guidelines (secondary)
- Ecosystem Vision (secondary)
- Decision Log (secondary)
ferrompi
This crate owns MPI communication and SharedWindow. 1 primary spec, 8 secondary.
- Hybrid Parallelism (secondary)
- Production Scale Reference (secondary)
- Work Distribution (secondary)
- Communication Patterns
- Shared Memory Aggregation (secondary)
- Output Infrastructure (secondary)
- Synchronization (secondary)
- SLURM Deployment (secondary)
- Backend: Ferrompi (secondary)
- Implementation Ordering (secondary)
- Spec Gap Inventory (secondary)
- Ecosystem Guidelines (secondary)
- Ecosystem Vision (secondary)
- Decision Log (secondary)
cobre-comm
This crate owns the communication backend abstraction: the Communicator trait, backend registration, and all four backend implementations. 7 primary specs, 4 secondary.
- Communicator Trait – trait definition, method contracts, SharedMemoryProvider
- Backend Selection – feature flags, factory pattern, runtime selection
- Backend: Ferrompi – MPI backend wrapping ferrompi
- Backend: Local – single-process no-op backend
- Backend: TCP – TCP socket backend for MPI-free deployments
- Backend: Shared Memory – POSIX shared memory backend
- Backend Testing – conformance test suite for all four Communicator backends
- Communication Patterns (secondary) – usage patterns for the trait
- Hybrid Parallelism (secondary) – initialization sequence
- Shared Memory Aggregation (secondary) – SharedMemoryProvider usage
- Implementation Ordering (secondary)
- Spec Gap Inventory (secondary)
- Ecosystem Guidelines (secondary)
- Ecosystem Vision (secondary)
- Decision Log (secondary)
cobre-mcp
This crate owns the MCP server specification. 1 primary spec, 5 secondary.
- MCP Server
- Structured Output (secondary)
- Convergence Monitoring (secondary)
- Validation Architecture (secondary)
- Output Schemas (secondary)
- Output Infrastructure (secondary)
- Implementation Ordering (secondary)
- Spec Gap Inventory (secondary)
- Ecosystem Guidelines (secondary)
- Ecosystem Vision (secondary)
- Decision Log (secondary)
cobre-python
This crate owns the Python bindings specification. 1 primary spec, 5 secondary.
- Python Bindings
- Structured Output (secondary)
- Hybrid Parallelism (secondary)
- Memory Architecture (secondary)
- Training Loop (secondary)
- Output Schemas (secondary)
- Implementation Ordering (secondary)
- Spec Gap Inventory (secondary)
- Ecosystem Guidelines (secondary)
- Ecosystem Vision (secondary)
- Decision Log (secondary)
cobre-tui
This crate owns the terminal UI specification. 1 primary spec, 3 secondary.
- Terminal UI
- Convergence Monitoring (secondary)
- Training Loop (secondary)
- Structured Output (secondary)
- Implementation Ordering (secondary)
- Spec Gap Inventory (secondary)
- Ecosystem Guidelines (secondary)
- Ecosystem Vision (secondary)
- Decision Log (secondary)
3. Outgoing Cross-Reference Table
For each spec file, this table shows which other specs it references in its ## Cross-References section. Grouped by section.
Overview
Math
Data Model
Architecture
HPC
Configuration
Deferred
Interfaces
4. Incoming Cross-Reference Table
For each spec file, this table shows which other specs reference it in their ## Cross-References sections. This is the inverse of Component 3.
Overview
Math
Data Model
Architecture
HPC
Configuration
Deferred
Interfaces
5. Dependency Ordering
This is a global reading order for the entire 79-spec corpus. Specs that are referenced by the most other specs (most foundational) appear first. Within the same reference count, section order applies (overview, math, data-model, architecture, hpc, configuration, deferred, interfaces).
Note on errata: Seven section-number references were identified as incorrect in the Epic 03 audit (findings F-1, F-5, F-6, F-7, F-8, F-9, F-11) and corrected in Epic 06. All links and section numbers in this index are now accurate.
Mathematical Formulations
This section contains the formal mathematical specifications that define Cobre’s optimization model. Together, these 14 specs describe the complete LP formulation solved at each stage of the SDDP algorithm, the stochastic processes that drive uncertainty, the cut management strategies that approximate the cost-to-go function, and the convergence machinery that determines when a policy is good enough.
Every constraint, variable bound, and algorithmic step that Cobre implements traces back to one of these pages. The specs are written to be precise enough to serve as a direct implementation reference: a developer should be able to read a spec and translate it into solver API calls without ambiguity. Where design choices exist (e.g., single-cut vs. multi-cut, constant vs. piecewise-linear productivity), each spec enumerates the supported variants and their configuration knobs.
The formulations assume familiarity with linear programming duality, the Bellman equation for multistage stochastic programs, and the basic SDDP decomposition scheme. Readers new to these topics should start with the Algorithm Reference section, which provides tutorial-style explanations, before diving into the specs here.
Reading Order
The specs have cross-references, so reading order matters. The following sequence builds concepts incrementally:
- SDDP Algorithm – Start here. Establishes the policy graph, state variables, Bellman recursion, and the single-cut vs. multi-cut distinction that the rest of the specs build on.
- System Elements – Defines every physical element (hydro plants, thermal units, buses, transmission lines, contracts) and its variables. Required context for reading any constraint formulation.
- LP Formulation – The complete stage subproblem: objective function, all constraint families, and the dual variables used for cut generation.
- Hydro Production Models – How water-to-energy conversion is modeled: constant productivity, FPHA hyperplanes, and linearized head.
- Equipment Formulations – Thermal dispatch, transmission limits, energy contracts, pumping stations, and non-controllable sources.
- Block Formulations – Parallel and chronological block structures, and how they affect constraint aggregation.
- Cut Management – Cut generation, aggregation, selection strategies (Level 1, LML1), and dominated-cut detection.
- PAR Inflow Model – The periodic autoregressive model for stochastic inflows: fitting, validation, and scenario generation.
The remaining specs can be read in any order after the first eight:
- Discount Rate – Stage-dependent discount factors and their effect on the Bellman equation.
- Infinite Horizon – Periodic policy graphs, cycle detection, and cross-cycle cut sharing.
- Risk Measures – CVaR, convex combination with expectation, and risk-averse cut generation.
- Inflow Non-Negativity – Strategies for handling negative synthetic inflows from the PAR model.
- Stopping Rules – Iteration limits, time limits, bound stalling, and simulation-based gap tests.
- Upper Bound Evaluation – Statistical upper bound computation and optimality gap estimation.
Spec Index
| Spec | Description | Algorithm Reference |
|---|---|---|
| SDDP Algorithm | Policy graph, state variables, Bellman recursion, single-cut vs. multi-cut | SDDP Theory, Benders Decomposition |
| LP Formulation | Stage subproblem objective, constraints, and dual variables | Forward and Backward Passes |
| System Elements | Physical elements, their decision variables, and interconnections | – |
| Block Formulations | Parallel and chronological blocks, policy compatibility validation | – |
| Hydro Production Models | Constant productivity, FPHA hyperplanes, linearized head | – |
| Cut Management | Cut generation, aggregation, Level 1 / LML1 selection, dominance detection | Cut Management, Cut Selection |
| Discount Rate | Discounted Bellman equation, stage-dependent discount factors | – |
| Infinite Horizon | Periodic policy graph, cycle detection, cross-cycle cut sharing | Convergence |
| Risk Measures | CVaR, convex combination with expectation, risk-averse cuts, per-stage profiles | Risk Measures, CVaR |
| Inflow Non-Negativity | Truncation, penalty, and hybrid strategies for negative synthetic inflows | Scenario Generation |
| PAR Inflow Model | PAR(p) model definition, stored vs. computed quantities, fitting, validation | PAR(p) Models |
| Equipment Formulations | Thermal, transmission, contracts, pumping, NCS, simulation-only enhancements | – |
| Stopping Rules | Iteration limit, time limit, bound stalling, simulation-based gap test | Convergence |
| Upper Bound Evaluation | Inner approximation, Lipschitz interpolation, statistical gap computation | Convergence |
Conventions
All specs in this section use the notation defined in Notation Conventions. Index sets, symbol definitions, and unit conventions are established there and are not repeated in individual spec pages.
The System Elements spec extends that notation with the concrete variables and parameters for each power system component. It serves as a second prerequisite for reading any constraint formulation – the LP Formulation, Equipment Formulations, and Hydro Production Models specs all reference variables introduced there.
Data Model
This section specifies every data structure that flows into, through, and out of the Cobre solver. On the input side, that means the JSON registries that define physical entities (hydro plants, thermal units, buses, transmission lines), the Parquet tables that carry stage-varying bounds and stochastic parameters, the penalty cascade that guarantees LP feasibility, and the config.json file that controls all solver behavior. On the output side, it covers the schemas for training convergence reports, simulation result tables, MPI-partitioned file manifests, and the binary persistence formats used for warm-starting and resuming interrupted runs.
The specs are organized around the data lifecycle. Input specs describe what the user provides and how the solver validates and loads it. Internal structure specs describe the in-memory model that the solver builds from those inputs. Output specs describe what the solver produces and how distributed results are assembled. Binary format specs describe the FlatBuffers schemas used for zero-copy serialization of policy data (cuts, states, basis vectors). Together, these 10 specs fully define the contract between the user, the I/O layer (cobre-io), the data model library (cobre-core), and the MPI communication layer (ferrompi).
Every file path, column name, JSON key, and Parquet schema documented here is normative. The solver rejects inputs that do not conform to these specs, and the output schemas are guaranteed stable within a major version. Where design choices exist (e.g., JSON vs. Parquet for a given file, sparse vs. dense override tables), the rationale is stated inline using the format selection criteria from the Design Principles spec.
Reading Order
The specs have extensive cross-references, so reading order matters. The following sequence builds concepts from the filesystem inward:
- Input Directory Structure – Start here. Defines the case directory layout, the
config.jsonschema, and the penalty summary that motivates the dedicated penalty spec. - Input System Entities – The seven entity registries in
system/: buses, lines, hydros, thermals, non-controllable sources, pumping stations, and energy contracts. Required context for reading any other input spec. - Input Hydro Extensions – Hydro-specific extension files: geometry curves, stage-varying production model configuration, and precomputed FPHA hyperplanes.
- Input Scenarios – The
stages.jsonschema (seasons, policy graph, blocks, risk measures), inflow and load models, correlation profiles, and external scenario injection. - Input Constraints – Initial conditions, stage-varying entity bounds, exchange capacity factors, and generic linear constraints.
- Penalty System – The three-tier penalty cascade (global defaults, entity overrides, stage overrides), the full penalty inventory, and resolution semantics that guarantee LP feasibility.
- Internal Structures – The in-memory solver model built from input files: indexed entity tables, assembled LP matrices, and the runtime state that the forward and backward passes operate on.
- Output Schemas – Training convergence tables, simulation result Parquet files, and per-iteration diagnostic exports.
- Output Infrastructure – File manifests, MPI rank-partitioned output assembly, streaming vs. buffered write modes, and compression settings.
- Binary Formats – FlatBuffers schemas for policy persistence: cut coefficients, visited states, inner approximation vertices, and solver basis snapshots.
Spec Index
| Spec | Description | Math Reference |
|---|---|---|
| Input Directory Structure | Case directory layout, config.json schema, penalty summary | – |
| Input System Entities | Seven entity registries: buses, lines, hydros, thermals, NCS, pumping, contracts | System Elements |
| Input Hydro Extensions | Hydro geometry curves, production model config, FPHA hyperplanes | Hydro Production Models |
| Input Scenarios | Stage definitions, policy graph, inflow/load models, correlations, external scenarios | PAR Inflow Model, Risk Measures |
| Input Constraints | Initial conditions, stage-varying bounds, exchange factors, generic constraints | LP Formulation |
| Penalty System | Three-tier penalty cascade, full inventory, resolution semantics | LP Formulation |
| Internal Structures | In-memory solver model: indexed tables, LP matrices, runtime state | LP Formulation, SDDP Algorithm |
| Output Schemas | Training convergence, simulation results, diagnostic exports | Upper Bound Evaluation, Stopping Rules |
| Output Infrastructure | File manifests, MPI-partitioned assembly, streaming writes, compression | – |
| Binary Formats | FlatBuffers schemas for cuts, states, vertices, basis persistence | Cut Management |
Conventions
All specs in this section follow the format selection criteria and declaration order invariance principle defined in Design Principles. In brief: JSON is used for human-editable structured objects with nested or optional fields (entity registries, configuration, correlation profiles); Parquet is used for typed columnar tabular data (stage-varying overrides, time series, scenario parameters); FlatBuffers is used for binary persistence where zero-copy deserialization matters (policy data). Declaration order within JSON arrays and Parquet rows never affects solver behavior – entities are identified by their id field, not by position.
The Notation Conventions spec establishes the index sets, symbols, and unit conventions used throughout. Column names in Parquet schemas and JSON keys are chosen to match the mathematical notation where practical (e.g., volume for \(v*{i,t}\), turbined for \(u*{i,t}\)).
Architecture
This section contains the architectural specifications that define how Cobre’s SDDP solver is structured at the software level. Where the Mathematical Formulations section defines what the solver computes and the Data Model section defines what data flows in and out, the architecture specs define how the solver is organized internally: the training loop that drives SDDP iteration, the simulation engine that evaluates trained policies, the solver abstraction layer that isolates LP solver dependencies, the scenario generation pipeline that produces correlated noise vectors, the input loading sequence that builds the in-memory model, the validation pipeline that rejects malformed inputs before any computation begins, the CLI entrypoint that orchestrates the full execution lifecycle, the convergence monitor that decides when to stop, the cut management implementation that maintains the future cost function, and the extension points that allow algorithm variants to be composed at configuration time.
Together, these 14 specs fully describe the runtime architecture of the Cobre solver. They are written at the behavioral level – specifying component responsibilities, interaction contracts, data flow, and parallelization strategy – without prescribing Rust module boundaries or struct layouts. A developer implementing a component should be able to read its architecture spec alongside the referenced math and data-model specs and produce a correct implementation without ambiguity. Where performance-critical design decisions exist (e.g., thread-trajectory affinity in the forward pass, streaming output in simulation, LP template cloning for solver workspaces, the performance adaptation layer that transforms domain types into solver-ready representations), each spec documents the rationale and the constraints that drove the choice.
The specs assume familiarity with the SDDP algorithm as described in SDDP Algorithm, the stage LP structure from LP Formulation, and the input/output contracts from the Data Model section. Readers new to the solver’s high-level design should start with CLI and Lifecycle, which maps the full execution sequence from process invocation to shutdown, before diving into the individual subsystem specs.
Reading Order
The specs have extensive cross-references, so reading order matters. The following sequence builds concepts from the outermost orchestration layer inward to the solver core:
- Training Loop – Start here. Defines the SDDP iteration lifecycle (forward pass, backward pass, convergence check), the four abstraction points (risk measure, cut formulation, horizon mode, sampling scheme), state management, and dual extraction for cut coefficients. This is the central spec that most other architecture specs plug into.
- Simulation Architecture – How trained policies are evaluated on large scenario sets: parallel distribution, per-scenario forward pass, policy compatibility validation, non-convex extensions, statistics computation, and streaming output.
- Solver Abstraction – The unified interface through which the SDDP algorithm interacts with LP solvers: solver interface contract, LP layout convention, cut pool design, error categories, retry logic, dual normalization, basis storage, and compile-time solver selection.
- Solver HiGHS Implementation – HiGHS-specific patterns for the C API, batch bound operations, retry strategy, basis management, memory footprint, and SDDP-tuned configuration.
- Solver CLP Implementation – CLP-specific patterns for the C API baseline, mutable pointer optimization, C++ wrapper strategy for LP template cloning, retry strategy, basis management, and memory footprint.
- Solver Workspaces – Thread-local solver workspace infrastructure and LP scaling: NUMA-local solver instances, pre-allocated buffers, and the bridge between the solver abstraction and the HPC execution layer.
- Performance Adaptation Layer – How cobre-core’s domain types are transformed into cobre-sddp’s performance-adapted runtime representations: transformation taxonomy, adapted type inventory, initialization build order, entity data flow mapping, and adaptation contracts.
- Scenario Generation – The scenario generation pipeline: PAR model preprocessing, correlated noise generation, the sampling scheme abstraction, external scenario integration, load scenario generation, and the memory layout optimized for the forward pass hot-path.
- Input Loading Pipeline – Rank-0 centric loading pattern, file loading sequence with dependency ordering, sparse time-series expansion, data broadcasting, parallel policy loading for warm-start, and transition to the in-memory data model.
- Extension Points – How algorithm variants are selected, composed, and validated at configuration time: the four abstraction points mapped to their configuration sources, validation rules, and cross-variant compatibility constraints.
- CLI and Lifecycle – Program entrypoint, command-line interface, exit codes, execution phase lifecycle, conditional execution modes, configuration resolution hierarchy, and job scheduler integration.
- Validation Architecture – Multi-layer input validation pipeline: the five validation layers, error collection strategy, error type catalog, and validation report format.
- Convergence Monitoring – Convergence criteria, stopping rules, bound computation with cross-rank aggregation, and training log format for progress reporting.
- Cut Management Implementation – How the mathematical cut management concepts are implemented: future cost function runtime structure, cut selection on the pre-allocated cut pool, FlatBuffers serialization for checkpoint/resume, cross-rank cut synchronization via MPI, cut coefficient extraction via fixing constraint duals, and cut activity tracking.
Spec Index
| Spec | Description | Math/Data Reference |
|---|---|---|
| Training Loop | SDDP iteration lifecycle, abstraction points, forward/backward passes, state management, dual extraction | SDDP Algorithm, Cut Management, Stopping Rules |
| Simulation Architecture | Policy evaluation on large scenario sets, parallel distribution, statistics, streaming output | Risk Measures, Discount Rate, Output Schemas |
| Solver Abstraction | Unified LP solver interface, LP layout, cut pool design, error handling, basis storage | LP Formulation |
| Solver HiGHS Implementation | HiGHS C API integration, batch operations, SDDP-tuned configuration | LP Formulation |
| Solver CLP Implementation | CLP C/C++ API integration, LP template cloning, mutable pointer optimization | LP Formulation |
| Solver Workspaces | Thread-local NUMA-aware solver instances, pre-allocated buffers, LP scaling | LP Formulation |
| Performance Adaptation Layer | Domain-to-solver type transformation taxonomy, adapted type inventory, build order, entity flow, contracts | Internal Structures, PAR Inflow Model |
| Scenario Generation | PAR preprocessing, correlated noise, sampling schemes, external scenarios, memory layout | PAR Inflow Model, Input Scenarios |
| Input Loading Pipeline | Rank-0 loading, dependency ordering, sparse expansion, broadcast, warm-start policy loading | Input Directory Structure, Binary Formats |
| Extension Points | Algorithm variant selection, composition, validation, cross-variant compatibility | Risk Measures, Infinite Horizon |
| CLI and Lifecycle | Program entrypoint, CLI, exit codes, phase lifecycle, configuration resolution | Input Directory Structure |
| Validation Architecture | Five validation layers, error collection, error catalog, validation report | Input System Entities, Input Constraints |
| Convergence Monitoring | Convergence criteria, bound computation, cross-rank aggregation, training log | Stopping Rules, Upper Bound Evaluation |
| Cut Management Implementation | FCF runtime structure, cut selection, FlatBuffers serialization, MPI cut sync, activity tracking | Cut Management, Binary Formats |
Conventions
All specs in this section describe behavioral contracts rather than implementation artifacts. Component responsibilities are stated as “the component does X” rather than “the struct has field Y”. This keeps the specs stable across refactors while remaining precise enough to verify an implementation against. Where a spec references mathematical quantities (cut coefficients, dual variables, risk weights), it uses the notation from Notation Conventions and links to the relevant math spec for the full derivation. Where a spec references data schemas (Parquet columns, JSON keys, FlatBuffers tables), it links to the relevant data-model spec for the normative definition. Cross-references to the High-Performance Computing section appear where parallelization strategy is architecturally significant (MPI distribution, OpenMP threading, NUMA placement).
High-Performance Computing
This section contains the specifications for Cobre’s hybrid MPI+OpenMP parallelization strategy. Where the Architecture section defines how the solver is structured at the software level, the HPC specs define how that architecture maps onto distributed and shared-memory hardware: the process topology that places one MPI rank per NUMA domain, the OpenMP threading layer that parallelizes LP solves within each rank, the communication patterns that synchronize cuts and bounds across ranks, the memory layout that eliminates false sharing and minimizes NUMA penalties, and the deployment recipes that translate these design choices into SLURM job scripts.
Together, these 8 specs fully describe the parallel execution model of the Cobre solver. They are written at the behavioral level – specifying distribution strategies, synchronization contracts, memory placement policies, and communication protocols – without prescribing MPI implementation details or OpenMP pragma syntax. A developer implementing the HPC layer should be able to read these specs alongside the referenced architecture and math specs and produce a correct parallel implementation without ambiguity. Where performance-critical design decisions exist (e.g., static contiguous block distribution over dynamic dispatch, sequential opening evaluation over parallel, thread-trajectory affinity), each spec documents the rationale and the constraints that drove the choice.
The specs assume familiarity with the SDDP training loop as described in Training Loop, the stage LP structure from LP Formulation, and the solver workspace infrastructure from Solver Workspaces. Readers new to the parallel execution model should start with Hybrid Parallelism, which establishes the two-level ferrompi+OpenMP architecture, before diving into the individual specs.
Reading Order
The specs have cross-references, so reading order matters. The following sequence builds concepts from the parallelization model outward to deployment:
- Work Distribution – How forward pass scenarios and backward pass trial points are distributed across MPI ranks and OpenMP threads: static contiguous block assignment, thread-trajectory affinity, and the load balancing strategy.
- Hybrid Parallelism – The two-level parallelization model: ferrompi as the backbone for process-level parallelism and shared memory, OpenMP via C FFI for intra-rank threading, design rationale, configuration, initialization sequence, and build integration.
- Communication Patterns – MPI communication patterns used during the SDDP training loop:
MPI_Allreducefor bound aggregation,MPI_Allgathervfor cut synchronization, and shared memory windows for intra-node data sharing. - Memory Architecture – Memory layout and NUMA-aware allocation: per-rank memory budget, shared memory region sizing, first-touch initialization, and false sharing avoidance.
- Shared Memory Aggregation – Hierarchical cut aggregation within MPI ranks sharing a physical node: node-local aggregation before inter-node communication to reduce message volume.
- Synchronization – Synchronization barriers and coordination points in the SDDP training loop: per-stage backward pass barriers, forward pass completion, and thread synchronization within ranks.
- Checkpointing – Checkpoint and restart for fault tolerance: what state is saved, when checkpoints are taken, how the solver resumes from a checkpoint across MPI ranks.
- SLURM Deployment – SLURM job submission and configuration: job scripts for single-node and multi-node runs, resource allocation, environment variable setup, and performance monitoring.
Spec Index
| Spec | Description | Architecture Reference |
|---|---|---|
| Work Distribution | Static block distribution, thread-trajectory affinity, load balancing | Training Loop, SDDP Algorithm |
| Hybrid Parallelism | ferrompi + OpenMP architecture, design rationale, configuration, initialization | Training Loop, Solver Workspaces |
| Communication Patterns | MPI collectives, shared memory windows, cut synchronization protocols | Cut Management Implementation, Convergence Monitoring |
| Memory Architecture | NUMA-aware allocation, memory budget, shared region sizing, false sharing avoidance | Solver Workspaces |
| Shared Memory Aggregation | Node-local cut aggregation, hierarchical reduction, shared memory scenarios | Cut Management Implementation |
| Synchronization | Per-stage barriers, forward pass completion, thread coordination | Training Loop |
| Checkpointing | Checkpoint/restart, fault tolerance, state serialization across ranks | Cut Management Implementation, CLI and Lifecycle |
| SLURM Deployment | Job scripts, resource allocation, environment setup, multi-node deployment | CLI and Lifecycle |
Conventions
All specs in this section describe parallel execution behavior and resource placement rather than sequential algorithmic logic. Where a spec references mathematical quantities (cut coefficients, dual variables, trial points), it uses the notation from Notation Conventions and links to the relevant math spec for the full derivation. Where a spec references architectural components (training loop, solver workspaces, cut management), it links to the relevant architecture spec for the behavioral contract. The HPC specs complement rather than duplicate the architecture specs – the architecture specs define what happens at each algorithmic step, while the HPC specs define how that step is distributed, synchronized, and placed in memory.
Configuration
This section contains the configuration reference that maps every tunable parameter exposed by Cobre to its effect on LP subproblem construction, solver behavior, and algorithm variant selection. Configuration is split across two files – config.json for global solver parameters and stages.json for temporal structure and per-stage options – and the reference documents all valid values, defaults, and LP-level consequences for each setting.
Spec Index
| Spec | Description |
|---|---|
| Configuration Reference | Complete mapping of configuration options to LP effects, with JSON examples, formulation-to-config traceability, and variable correspondence |
Cross-Section References
The configuration options documented here reference definitions from three other specification sections. Modeling options and training parameters map to formulations in Mathematical Formulations (cut selection strategies, stopping rules, risk measures, discount rates). Data file paths and JSON schemas are defined in Data Model (input directory structure, stages schema, penalty system). Algorithm variant selection and validation rules are specified in Architecture (extension points, scenario generation, cut management implementation).
Interfaces
This section specifies the four interface layers through which external agents, tools, and users interact with Cobre beyond the traditional MPI batch execution path. Each interface layer is implemented as a separate crate with its own responsibility boundary, but all share the same event types defined in cobre-core and operate in single-process mode (no MPI).
| Interface | Crate | Purpose |
|---|---|---|
| Structured Output | cobre-cli | JSON and JSON-lines output protocol for CLI responses and progress streaming |
| MCP Server | cobre-mcp | Model Context Protocol server exposing Cobre operations as tools, resources, and prompts |
| Python Bindings | cobre-python | PyO3-based Python module for programmatic access to validation, training, simulation, and results |
| Terminal UI | cobre-tui | Interactive terminal dashboard for real-time training monitoring and convergence visualization |
All four interfaces consume the shared event stream architecture defined in the Training Loop and Convergence Monitoring specs. The structured output spec (CLI JSON protocol) serves as the foundational schema layer – the MCP server, Python bindings, and TUI all reuse its error schema and event type definitions.
Deferred Features
Purpose
This spec documents features that are planned but not yet implemented in the Cobre SDDP solver. Each feature includes a description, rationale for deferral, prerequisites, and estimated effort. The data model is designed to accommodate these extensions without breaking changes.
C.1 GNL Thermal Plants
Status: DEFERRED
Description: Gas Natural Liquefeito (GNL) thermal plants have complex operational constraints including:
- Minimum take-or-pay contracts
- Variable fuel costs based on LNG spot market
- Start-up and shutdown constraints
- Fuel inventory management
Planned Formulation:
- Binary variables for unit commitment (requires MIP solver integration)
- Fuel inventory balance constraints
- Contract fulfillment constraints
- Piecewise-linear fuel cost functions
Why Deferred: Requires MIP solver integration (SDDiP or Lagrangian relaxation) which is a significant architectural change. Unit commitment is not in the immediate roadmap for medium/long-term planning.
Prerequisites:
- Duality handler infrastructure (Lagrangian relaxation for MIP subproblems)
- MIP solver integration (Gurobi, CPLEX, or Cbc)
- GNL-specific data model extensions
Estimated Effort: Large (3-4 weeks). Requires SDDiP infrastructure before GNL-specific modeling.
Reference: CEPEL NEWAVE/DECOMP GNL modeling documentation.
C.2 Battery Energy Storage Systems
Status: DEFERRED
Description: Grid-scale batteries with:
- State-of-charge management
- Charge/discharge efficiency losses
- Degradation modeling (cycle counting)
- Capacity fade over time
Planned Formulation:
Variables:
| Variable | Domain | Units | Description |
|---|---|---|---|
| MWh | State of charge | ||
| MW | Charging power | ||
| MW | Discharging power |
Energy Balance:
Load Balance Contribution:
Data Model: The system/batteries.json schema is fully specified with fields for capacity (energy/charge/discharge), efficiency, initial SOC, and SOC limits. LP variables include battery_soc (state), battery_charge, and battery_discharge (controls). Output schema in simulation/batteries/ is also defined. See Input System Entities for the entity registry pattern and Internal Structures for how entities are resolved at runtime.
Why Deferred: Batteries are linear storage devices (no integer variables needed), but require:
- New state variable dimension (SOC per battery)
- Integration with bus load balance
- Testing with realistic battery degradation scenarios
Prerequisites:
- State variable infrastructure supports dynamic dimension
- Bus balance constraint generation handles battery charge/discharge
- Output schema for battery simulation results
Estimated Effort: Medium (2-3 weeks). LP formulation is straightforward; main effort is data pipeline and testing.
C.3 Multi-Cut Formulation
Status: DEFERRED
Description: Alternative to single-cut aggregation that creates one cut per scenario.
Formulation:
Instead of a single aggregated future cost variable , introduce per-scenario variables :
With per-scenario cuts:
Trade-offs:
| Aspect | Single-Cut | Multi-Cut |
|---|---|---|
| Cuts per iteration | 1 | (one per scenario) |
| LP size | Smaller (1 future cost variable) | Larger ( future cost vars) |
| Convergence rate | Slower (more iterations) | Faster (fewer iterations) |
| Time per iteration | Faster | Slower |
| Memory | Lower | Higher |
| Numerical stability | More stable | Can have issues with risk measures |
| Best for | Large scenario counts, risk-averse | Small scenario counts, risk-neutral |
Why Deferred: Multi-cut requires significant changes:
- LP construction must handle multiple future cost variables
- Cut storage and selection becomes more complex
- Interaction with CVaR risk measures needs careful implementation
- Performance tuning (when to use which formulation) is problem-dependent
Prerequisites:
- LP builder supports variable number of future cost variables
- Cut pool indexed by scenario
- Cut selection adapted for multi-cut pools
Estimated Effort: Medium (2-3 weeks). Core algorithm change with wide-reaching effects on cut management.
Reference: Birge, J.R. (1985). “Decomposition and partitioning methods for multistage stochastic linear programs.” Operations Research, 33(5), 989-1007.
C.4 Markovian Policy Graphs
Status: DEFERRED
Description: Extension to handle scenario-dependent transitions (e.g., different inflow regimes).
Current Limitation: Cobre assumes stage-wise independent scenarios. The same scenario tree structure is used regardless of which scenario was realized in the previous stage.
Planned Extension:
- Markov chain over “regimes” (e.g., wet/dry/normal)
- Transition probabilities between regimes
- Regime-dependent inflow distributions
- Cut sharing across nodes in same regime
Formulation:
Let be a Markov chain with states and transition matrix .
The policy graph becomes:
- Nodes: for stage and regime
- Edges: with probability
Value function approximation:
Cuts are regime-specific and only shared within the same regime.
Data Model: The stages.json schema supports optional markov_states fields. Transitions include source_markov and target_markov fields. Cut files are indexed by (stage_id, markov_state) as stage_XXX_markov_YYY.bin. See Input Scenarios for the stages.json schema and Binary Formats for cut file persistence.
Why Deferred: Markovian policy graphs substantially increase algorithm complexity:
- Forward passes must track Markov state transitions
- Backward passes generate cuts for each
(stage, markov_state)node - State space grows by factor of
|markov_states| - Requires careful handling of stagewise-independent noise within each Markov state
Prerequisites:
- Policy graph supports multi-node-per-stage structure
- Cut pool indexed by
(stage, markov_state)tuples - Forward/backward pass logic handles Markov transitions
- Scenario generation respects regime-dependent distributions
Estimated Effort: Large (3-4 weeks). Fundamental change to policy graph and forward/backward pass logic.
Reference: Philpott, A.B., & de Matos, V.L. (2012). “Dynamic sampling algorithms for multi-stage stochastic programs with risk aversion.” European Journal of Operational Research, 218(2), 470-483.
C.5 Non-Controllable Sources (Wind/Solar)
Status: IMPLEMENTED
Note: Non-controllable sources are no longer deferred. The LP formulation (generation bounds, curtailment variables, bus balance participation) is specified in Equipment Formulations §6. The data model (entity registry, scenario pipeline, penalty overrides) is specified in Input System Entities §7. The penalty system includes curtailment cost as a Category 3 regularization penalty in Penalty System §2. The formulation and data model descriptions below are retained for reference.
Variables:
| Variable | Domain | Units | Description |
|---|---|---|---|
| MW | Non-controllable generation | ||
| MW | Curtailment |
Generation Constraint:
where is the stochastic availability factor.
Curtailment Penalty:
Data Model: The system/non_controllable_sources.json schema defines source type, bus assignment, capacity, and curtailment settings. Generation models in scenarios/non_controllable_models.parquet provide mean and standard deviation per source per stage. Correlation with inflows is supported via correlation.json blocks. Output schema in simulation/non_controllables/ is defined.
C.6 FPHA Enhancements
Status: DEFERRED (Partial – core FPHA implemented)
Description: Advanced extensions to the FPHA (Four-Point Head Approximation) model for improved accuracy in hydroelectric production function modeling.
C.6.1 Variable Efficiency Curves
Current: Constant turbine-generator efficiency .
Enhancement: Flow-dependent efficiency using characteristic curves:
where is a hill chart approximation, typically:
Data Requirements:
- Efficiency curve coefficients in
hydro_production_data.parquet efficiency_type = "flow_dependent"efficiency_coeffs = [a_0, a_1, a_2, a_3]
Impact on FPHA: Hyperplane fitting must use at each grid point. Increases nonlinearity captured by the approximation. More planes may be needed for same accuracy.
C.6.2 Pumped Hydro Production Function
Current: Pumping modeled separately from generation.
Enhancement: Unified production function for reversible hydro plants:
Generation Mode (standard FPHA):
Pumping Mode (reversed inequality – pumping power increases with head):
Pumping Production Function:
where = pumping head (downstream to upstream) and = pumping efficiency (typically 0.85-0.90).
Hyperplane Form:
Operational Constraints:
- Mutual exclusion: (nonlinear)
- Alternative: Big-M or SOS1 constraints (introduces integer variables)
- Cobre approach: Allow simultaneous gen/pump with high penalty (relaxation)
C.6.3 Dynamic FPHA Recomputation
Current: FPHA hyperplanes fixed per stage configuration.
Enhancement: Recompute hyperplanes based on expected operating region.
Approach:
- Track volume distribution per stage across forward passes
- Adjust to cover observed operation
- Generate new planes for updated windows
- Manage cut validity after FPHA updates
Configuration (future):
{
"fpha_config": {
"dynamic_recomputation": {
"enabled": true,
"recompute_every_n_iterations": 50,
"window_adaptation": "narrow_only",
"percentile_margin": 5
}
}
}
Warning: Dynamic recomputation changes the LP structure across iterations. This may affect SDDP convergence guarantees.
Why Deferred: Core FPHA is implemented; these are accuracy improvements requiring:
- Variable efficiency: Hill chart data and fitting infrastructure
- Pumped hydro: Unified gen/pump production function with mutual exclusion
- Dynamic recomputation: Online hyperplane refitting with cut validity management
Prerequisites:
- Core FPHA operational and validated
- Hyperplane fitting infrastructure supports refitting
- Performance baseline established to measure improvements
Estimated Effort: Medium-Large (2-4 weeks total across all three sub-features).
C.7 Temporal Scope Decoupling
Status: DEFERRED
Description: Advanced temporal decomposition inspired by SPARHTACUS that decouples the physical time resolution (decision dynamics) from the SDDP stage decomposition (Benders cut generation points). Enables flexible multi-resolution modeling with controlled cut growth.
Motivation: In conventional SDDP, three temporal scopes are tightly coupled: stage (SDDP decomposition unit), decision period (physical time resolution), and stochastic process (uncertainty realization base). This forces a trade-off between fine temporal resolution (accurate physics, exponential cut growth) and coarse resolution (manageable cuts, poor short-term dynamics).
Three Independent Temporal Scopes (SPARHTACUS nomenclature):
| Scope | Portuguese Term | Cobre Current | Purpose |
|---|---|---|---|
| Optimization Period | Periodo de otimizacao | stages[t] | SDDP decomposition unit, Benders cut generation |
| Study Period | Periodo de estudo | (coupled to stage) | Physical time resolution for constraints and decisions |
| Stochastic Process Period | Periodo do processo estocastico | inflow_seasonal_stats.parquet per stage | Base for uncertainty realization |
Extended Multi-Period Stage Subproblem:
Let stage contain decision periods indexed by .
Subject to:
- Period 1 constraints:
- Period k constraints: for
- State transition:
Key property: State variable dimension is unchanged – cuts reference only at stage boundaries, not intermediate periods. LP size increases by factor but cut count remains constant.
LP Size Impact:
| Configuration | Stages | Avg LP Size | Cut Pool |
|---|---|---|---|
| Standard monthly | 60 | 1500 vars | ~1200 cuts @ 20 iter |
| Hybrid (4 weekly + rest monthly) | 60 | ~1600 vars | ~1200 cuts |
| All weekly | 260 | 1500 vars | ~5200 cuts @ 20 iter |
Why Deferred: Requires significant architectural changes:
- Multi-period LP construction within single stage
- Modified forward/backward pass logic
- Data model changes (periods array within stages)
- Interaction with chronological blocks (nested: Stage → Periods → Blocks)
Prerequisites:
- Core SDDP training loop validated and stable
- Chronological block formulation operational
- Performance profiling shows cut growth is the bottleneck
Estimated Effort: Large (4-6 weeks). Fundamental change to LP construction, data model, and algorithm.
References:
- SPARHTACUS/SPTcpp: Escopo Temporal
- Pereira, M.V.F., & Pinto, L.M.V.G. (1991): Original SDDP paper with monthly stages
C.8 CEPEL PAR(p)-A Variant
Status: DEFERRED
Description: CEPEL’s PAR(p)-A model (referenced in Rel-1941_2021) extends the standard PAR(p) with:
- Order constraint: Maximum AR order often fixed at 12 (annual cycle)
- Stationarity enforcement: Coefficients adjusted to ensure
- Lognormal transformation: Working with for strictly positive inflows
- Regional correlation: Cross-correlation between hydros in the same river basin
Why Deferred: The standard PAR(p) model covers most practical use cases. The lognormal variant is primarily relevant for basins with highly skewed inflow distributions where negative synthetic inflows become problematic. The inflow non-negativity handling strategies (see Inflow Non-Negativity) provide adequate mitigation for the standard model.
Prerequisites:
- Standard PAR(p) fitting and validation operational
- Lognormal transformation infrastructure (log-space fitting, back-transformation)
- Validation suite comparing PAR(p) vs. PAR(p)-A on representative basins
Data Model Compatibility: The current input format (inflow_seasonal_stats.parquet + inflow_ar_coefficients.parquet) supports PAR(p)-A — the lognormal transformation is applied to history before computing seasonal stats, and the resulting μ, s, ψ values are stored in the same schema.
Estimated Effort: Small-Medium (1-2 weeks). Mathematical extensions are straightforward; main effort is validation and testing.
Reference: CEPEL Rel-1941_2021.
C.9 Policy Compatibility Validation
Status: DEFERRED (requires dedicated spec)
Description: When the solver runs in simulation-only, warm-start, or checkpoint resume mode, it must validate that the current input data is compatible with the previously trained policy (cuts). Incompatible inputs produce silently incorrect results — cut coefficients encode LP structural information that becomes invalid if the system changes.
Properties to validate (non-exhaustive):
| Property | Why It Matters |
|---|---|
| Block mode per stage | Cut duals come from different water balance structures (parallel vs. chronological) |
| Block count and durations per stage | LP column/row dimensions change |
| Number of hydro plants | State variable dimension changes |
| AR orders per hydro | State variable dimension changes |
| Cascade topology | Water balance constraint structure changes |
| Number of buses, lines | Load balance constraint structure changes |
| Number of thermals, contracts, NCS | LP column count changes |
| Production model per hydro per stage | FPHA vs. constant affects generation constraint and dual structure |
| Penalty configuration | Affects objective coefficients and thus cut intercepts |
Design considerations:
- The training phase must persist a policy metadata record alongside the cut data, capturing all input properties that affect LP structure
- The validation phase compares the current input against this metadata and produces a hard error on any mismatch
- The metadata format should be versioned for forward compatibility
- Some properties may allow controlled relaxation (e.g., adding a new thermal plant at the end might be compatible if the policy’s state variables are unchanged) — these exceptions require careful analysis
Why Deferred: This is a complex cross-cutting concern that touches training, simulation, checkpointing, and input loading. It requires a dedicated specification that defines:
- The complete list of validated properties
- The metadata format persisted by training
- The validation algorithm (exact match vs. compatible subset)
- Error reporting format
- Interaction with checkpoint versioning
Prerequisites (all now met — approved specs):
- Training loop architecture finalized — Training Loop approved
- Checkpoint format defined — Checkpointing approved, Binary Formats §3-§4 approved
- Simulation architecture finalized — Simulation Architecture approved
- Input loading pipeline defined — Input Loading Pipeline approved
C.9 is unblocked and can proceed to its own dedicated specification.
Estimated Effort: Medium (2-3 weeks). Primarily specification and testing; implementation is straightforward once the property list is defined.
Cross-references:
- Block Formulations §4 — block mode validation requirement (first identified property)
- Training Loop — must persist policy metadata
- Simulation Architecture — must validate on entry
- Checkpointing — checkpoint format must include metadata
- Binary Formats — policy file format that carries metadata
C.10 Fine-Grained Temporal Resolution (Typical Days)
Status: DEFERRED (requires research)
Description: Decompose each stage into D representative typical day types (e.g., weekday, weekend, peak-season day), each containing N chronological blocks (e.g., 24 hourly periods). This enables accurate modeling of daily cycling patterns within monthly or weekly stages.
Motivation: The current block formulation uses a single level of temporal decomposition — a few load blocks (e.g., peak/shoulder/off-peak) with duration τ_k representing the total monthly hours for that load level. This is adequate for long-term planning but cannot capture:
- Daily storage cycling (pumped hydro, batteries)
- Hourly renewable generation profiles (solar peak, wind patterns)
- Time-of-use pricing dynamics
- Intra-day ramp constraints
Key design questions (require research):
- Day-type chaining: Should typical days chain sequentially within a stage (day 1 end-storage → day 2 initial storage), or operate independently with weighted-average end-of-stage storage?
- Objective weighting: Block durations within a day type are the actual hourly duration (e.g., 1 hour), but the objective contribution must be scaled by the day-type weight (number of days it represents). This requires separating the current τ_k into two components: block duration (for water balance) and effective duration (for objective).
- Two-phase architecture: Train with aggregated blocks, simulate with full typical-day resolution. Cut compatibility conditions need formal verification.
- Input data requirements: Day-type definitions, weights, hourly demand profiles per day type, hourly renewable availability profiles per day type.
LP size impact (estimated for 100 hydros):
| Configuration | Blocks/stage | Water balance rows | Additional LP vars |
|---|---|---|---|
| Current (3 load blocks) | 3 | 100-300 | 0-200 |
| 3 day types × 24 hours | 72 | 7,200 | 7,100 |
| 5 day types × 24 hours | 120 | 12,000 | 11,900 |
References:
- PSR SDDP v17.3 release notes — “Typical Days” representation
- NZ Battery Project (Jacobs/PSR, 2023) — 21 chronological blocks per weekly stage
- Garcia et al. (2020), “Genesys” — 3 chronological blocks per day in weekly stages
- SPARHTACUS temporal decoupling (see §C.7 above)
Prerequisites:
- Core parallel and chronological block modes operational and validated
- Simulation architecture supports variable block configurations
- Research on day-type chaining and two-phase cut compatibility completed
Estimated Effort: Large (4-6 weeks). Significant input schema design, LP construction changes, and research required.
C.11 User-Supplied Noise Openings
Status: DEFERRED (requires design investigation)
Description: Allow users to directly input pre-sampled, pre-correlated noise values for the opening tree, bypassing the internal noise generation and correlation pipeline entirely.
Motivation: The standard pipeline generates noise internally (sample independent , apply Cholesky correlation). Some use cases require full user control over the noise:
- Importing noise realizations from external stochastic models that use non-Gaussian distributions
- Reproducing exact noise sequences from legacy tools for validation
- Using domain-specific spatial correlation structures not captured by the Cholesky approach
- Research workflows where specific noise patterns are under study
Proposed Input File: scenarios/noise_openings.parquet
| Column | Type | Description |
|---|---|---|
| opening_id | int32 | Opening index () |
| stage_id | int32 | Stage identifier |
| entity_id | int32 | Hydro (or bus, for load noise) identifier |
| noise_value | float64 | Already-correlated noise |
When this file is present, the scenario generator skips internal noise sampling and Cholesky correlation entirely, loading the user-supplied values directly into the opening tree (§2.3 of Scenario Generation).
Design Questions (require investigation before implementation):
- Relationship to external scenarios — Can the existing external scenario mechanism (with noise inversion) cover all use cases, or does direct noise input serve fundamentally different needs?
- Validation — What checks should be applied? (e.g., noise dimensionality matches system, reasonable value ranges, correlation structure is PSD)
- Interaction with load noise — Should the file include load entity noise, or only inflow noise?
- Forward/backward separation — Should users supply separate noise sets for forward and backward passes?
Prerequisites:
- Opening tree architecture (§2.3) implemented and validated
- Forward/backward noise separation (§3.1) operational
- Clear use case catalog that cannot be served by external scenarios + noise inversion
Estimated Effort: Small (1 week). Input loading and validation are straightforward; the opening tree already supports external population. Main effort is design decisions above.
Cross-references:
- Scenario Generation §2.3 — Opening tree architecture
- Input Scenarios §2.5 — External scenarios (related mechanism)
C.12 Complete Tree Solver Integration
Status: DEFERRED (concept documented, solver integration pending)
Description: Full solver integration for complete tree mode — enumerating all nodes in an explicit scenario tree and solving a subproblem per node using Benders decomposition, as in CEPEL’s DECOMP model.
The concept and tree structure are documented in Scenario Generation §7. This deferred item covers the solver-side integration:
Required Components:
- Tree enumerator — Given per-stage branching counts , enumerate all tree nodes with parent-child relationships and branching probabilities
- Node-to-subproblem mapping — Each tree node maps to a stage subproblem with specific RHS values (from the node’s branching realization) and a specific state variable value (from the parent node’s solution)
- Tree-aware backward pass — Instead of SDDP’s sample-based backward pass, solve backward through the tree: at each node, aggregate cuts from its children (weighted by branching probabilities)
- Result aggregation — Collect optimal values, state trajectories, and duals from all tree nodes; compute expected cost and policy metrics
- Exhaustive forward pass — Replace sampling with deterministic tree traversal, visiting every path from root to leaf
DECOMP Special Case: When for all , the tree degenerates into a deterministic trunk with branching only at stage . The forward pass solves a single path up to , then branches. This is the standard DECOMP configuration for short-term planning.
LP Construction: Each node’s LP is identical in structure to the SDDP stage subproblem — the complete tree mode reuses the existing LP builder. The difference is purely in the traversal logic (enumeration vs. sampling) and cut aggregation (tree-weighted vs. sample-averaged).
Why Deferred: Solver integration requires:
- Tree traversal infrastructure (BFS/DFS node enumeration with MPI distribution)
- Modified training loop that replaces SDDP’s forward/backward sampling with tree enumeration
- Result storage for potentially millions of tree nodes
- Convergence criterion different from SDDP (the tree solution is exact — convergence means Benders gap closure on the tree, not statistical bound convergence)
Prerequisites:
- Core SDDP training loop operational
- Opening tree infrastructure (§2.3) supports variable per-stage branching counts
- External scenario integration validated
- Performance profiling establishes tractability bounds for target problem sizes
Estimated Effort: Medium-Large (3-4 weeks). LP construction is reused; main effort is tree traversal, MPI distribution of tree nodes, and result aggregation.
References:
- CEPEL DECOMP: Modelo DECOMP — Short-term hydrothermal dispatch with scenario trees
- Scenario Generation §7 — Complete tree concept and structure
C.13 Alternative Forward Pass Model
Status: DEFERRED
Description: Solve a different LP model in the forward pass — one that includes simulation-only features (linearized head, unit commitment, bottom discharge) — to generate trial points that better reflect real-world operations, while keeping the training LP (convex, no simulation-only features) for backward pass cut generation.
Motivation: The default forward pass solves the training LP, which excludes simulation-only features (see Simulation Architecture). Trial points from this simplified model may not visit states that are realistic under full operational modeling. An alternative forward pass addresses this gap by solving a richer model to generate more representative trial points.
Design (inspired by SDDP.jl’s AlternativeForwardPass):
- Maintain two LP models per stage: the training LP (convex) and the alternative LP (includes simulation-only features)
- Forward pass solves the alternative LP at each stage, producing trial states
- Backward pass solves the training LP at each stage using these trial states, generating valid Benders cuts
- After each backward pass, new cuts are added to both LP models (the alternative LP needs cuts too, for its variable)
Key properties:
- Cuts remain valid because they are generated from the convex training LP
- Trial points are more realistic because they come from the richer alternative LP
- Convergence may be slower (trial points from the alternative model may not be optimal for the training model)
- Memory cost approximately doubles (two LP models per stage)
Why Deferred: Requires maintaining two parallel LP models per stage, which doubles memory and complicates solver workspace management. The benefit depends on how different simulation-only features make trial points — this is problem-dependent and needs empirical investigation.
Prerequisites:
- Core SDDP training loop operational and validated
- Simulation-only LP construction (linearized head, unit commitment) implemented
- Solver workspace infrastructure supports multiple LP models per stage
Estimated Effort: Medium (2-3 weeks). LP construction infrastructure is reused; main effort is dual LP management, cut copying, and convergence testing.
Reference: SDDP.jl AlternativeForwardPass and AlternativePostIterationCallback in src/plugins/forward_passes.jl.
C.14 Monte Carlo Backward Sampling
Status: DEFERRED
Description: Sample openings with replacement from the fixed opening tree instead of evaluating all in the backward pass. This reduces backward pass cost from to LP solves per stage per trial point.
Motivation: When is large (e.g., 500+ for high-fidelity tail representation), the backward pass dominates iteration time. Sampling a subset provides an unbiased cut estimator with reduced computation.
Design (inspired by SDDP.jl’s MonteCarloSampler):
- At each backward stage, sample noise vectors uniformly with replacement from the opening tree
- Compute cut coefficients from only these solves
- The resulting cut is an unbiased estimator of the full cut (with higher variance)
Trade-offs:
| Aspect | Complete (current) | MonteCarlo(n) |
|---|---|---|
| Solves per stage | ||
| Cut quality | Exact (for given tree) | Unbiased estimator, higher variance |
| Convergence | Monotonic lower bound | Non-monotonic (stochastic cuts) |
| Best for | Small-medium | Large |
Why Deferred: Introduces non-monotonic lower bound behavior, which complicates convergence monitoring. Requires careful tuning of relative to . The default complete evaluation is reliable and performant for typical production sizes (50-200 openings).
Prerequisites:
- Core SDDP with complete backward sampling validated
- Convergence monitoring supports non-monotonic lower bounds
- Empirical study of vs. convergence rate trade-off
Estimated Effort: Small (1 week). Sampling infrastructure is trivial; main effort is convergence monitoring adaptation.
Reference: SDDP.jl MonteCarloSampler in src/plugins/backward_sampling_schemes.jl.
C.15 Risk-Adjusted Forward Sampling
Status: DEFERRED (supersedes “Risk-Adjusted Forward Passes” in Additional Variants below)
Description: Oversample scenarios from distribution tails in the forward pass, improving exploration of worst-case outcomes for risk-averse policies. This is a forward sampling scheme variant that biases sampling toward extreme scenarios.
Design (inspired by SDDP.jl’s RiskAdjustedForwardPass):
- After solving each forward pass stage, evaluate the risk measure over the candidate noise terms
- Re-weight or re-sample the next-stage noise based on the risk adjustment
- The resulting forward trajectory visits states that are more relevant for the tail of the cost distribution
Complementary approach — Importance Sampling (inspired by SDDP.jl’s ImportanceSamplingForwardPass):
- Weight forward trajectories by their likelihood ratio under the risk-adjusted distribution vs. the nominal distribution
- Use these weights in upper bound estimation for tighter risk-averse bounds
Why Deferred: Requires integration with the CVaR risk measure configuration and careful handling of importance weights. Default uniform sampling is sufficient for most applications. The benefit is primarily for strongly risk-averse configurations ( close to 1.0).
Prerequisites:
- CVaR risk measure implemented and validated
- Forward sampling scheme abstraction supports per-stage re-weighting
- Upper bound evaluation handles importance-weighted trajectories
Estimated Effort: Medium (2-3 weeks). Algorithm is well-documented in literature; main effort is integration with risk measure and convergence analysis.
References:
- SDDP.jl
RiskAdjustedForwardPassinsrc/plugins/forward_passes.jl - Philpott, A.B., & de Matos, V.L. (2012). “Dynamic sampling algorithms for multi-stage stochastic programs with risk aversion.”
C.16 Revisiting Forward Pass
Status: DEFERRED
Description: Encourage state-space diversity by occasionally re-solving forward passes from previously visited states rather than always starting from the root node. This helps the algorithm explore under-represented regions of the state space.
Design (inspired by SDDP.jl’s RevisitingForwardPass):
- Maintain a buffer of previously visited states from past iterations
- With some probability, start a forward pass from a randomly selected historical state at a randomly selected stage (rather than from stage 1 with )
- The resulting trial points provide cuts in previously unvisited regions
Why Deferred: Modifies the forward pass initialization, which affects upper bound estimation (partial trajectories don’t contribute full-horizon costs). Requires careful interaction with convergence monitoring. The benefit is primarily for problems with large state spaces where standard forward passes repeatedly visit similar states.
Prerequisites:
- Core SDDP training loop validated
- State history buffer infrastructure
- Convergence monitoring handles partial-trajectory iterations
Estimated Effort: Small-Medium (1-2 weeks). State buffer is straightforward; main effort is convergence analysis for partial trajectories.
Reference: SDDP.jl RevisitingForwardPass in src/plugins/forward_passes.jl.
C.17 Forward Pass State Deduplication
Status: DEFERRED
Description: When multiple forward scenarios visit identical (or near-identical) states at a given stage, the backward pass redundantly evaluates the cost-to-go from duplicate trial points. State deduplication merges these duplicates before the backward pass, reducing the number of backward LP solves without affecting cut quality (identical states produce identical cuts).
Design Considerations:
- Exact deduplication — Hash-based deduplication of state vectors with identical storage volumes and AR lag values. Straightforward but limited benefit (exact duplicates are rare with continuous state spaces)
- Approximate deduplication — Merge states within a tolerance using spatial indexing (e.g., k-d tree). Greater reduction in backward solves, but introduces approximation error in cut coefficients. Requires analysis of the impact on convergence guarantees
Why Deferred: Exact duplicates are uncommon in continuous-state SDDP, so the benefit of exact deduplication is marginal. Approximate deduplication requires careful analysis of convergence implications. Should be implemented only when profiling shows the backward pass is bottlenecked on trial point count rather than per-solve cost.
Prerequisites:
- Core SDDP training loop validated and profiled
- Backward pass timing data showing trial point count as the dominant cost factor
Estimated Effort: Small (< 1 week) for exact deduplication; Medium (2-3 weeks) for approximate with convergence analysis.
Cross-references:
- Training Loop §5.2 — State lifecycle where deduplication would be applied
C.18 Pipelined Backward Pass
Status: DEFERRED
Description: The standard (sequential) backward pass uses — the freshly computed approximation from the current iteration — requiring a synchronization barrier at each stage boundary. The pipelined variant uses (previous iteration’s approximation), allowing stages to be computed with overlapped communication. This eliminates per-stage barriers and enables non-blocking MPI broadcasts (ibroadcast) to overlap with computation at the next stage.
Trade-offs:
| Aspect | Sequential (current) | Pipelined (deferred) |
|---|---|---|
| Cut source | (current iteration) | (previous iteration) |
| Cut quality | Tighter | Looser |
| Iterations to converge | Fewer | More |
| Time per iteration | Longer (per-stage barriers) | Shorter (overlapped communication) |
| Implementation | Simple | Complex (async state management) |
| MPI primitives | MPI_Allgatherv (blocking) | MPI_Iallgatherv + MPI_Wait (non-blocking) |
Mathematical validity: Both approaches produce valid cuts — supporting hyperplanes of the true value function. The difference is in tightness: sequential cuts incorporate more recent information (downstream cuts from the same iteration), leading to faster convergence per iteration.
When to consider: When profiling shows backward pass per-stage barrier synchronization accounts for a significant fraction (>20%) of backward pass time. This is most likely with very large stage counts (>100 stages) and high inter-node network latency.
Why Deferred: The sequential mode is simpler, produces tighter cuts, and is the default in SDDP.jl and most production implementations. The benefit of pipelining depends on hardware-specific communication latency, which cannot be determined without profiling production workloads.
Prerequisites:
- Core SDDP training loop validated and profiled
- Backward pass timing data showing barrier synchronization as a bottleneck
- Non-blocking MPI collective support in ferrompi
Estimated Effort: Medium (2-3 weeks). Requires async state management, non-blocking collective wrappers, and convergence regression testing.
Cross-references:
- Work Distribution §2 — Current sequential backward pass distribution
- Training Loop §6 — Backward pass execution with per-stage barrier
- Communication Patterns — Non-blocking ferrompi collectives
C.19 Dynamic Forward-Passes Scheduler
Status: DEFERRED
Description: A scheduler that adjusts the number of forward passes per iteration (forward_passes) during training based on convergence metrics or wall-clock budget.
Why Deferred: The cut pool capacity is pre-allocated using the formula warm_start_cuts + max_iterations × forward_passes (see Cut Management Implementation SS1.3). A dynamic scheduler would require either a worst-case static allocation (wasteful for most runs) or dynamic reallocation (invalidates the deterministic slot assignment in SS1.2). Both alternatives need profiling data to choose correctly.
Additional Deferred Algorithm Variants
The following algorithm variants are also deferred:
Objective States
Extends SDDP to handle exogenous random processes that affect objective coefficients (e.g., electricity spot prices following an AR process). Uses inner approximation (Lipschitz interpolation) for the value function component that depends on objective states.
Why Deferred: Not typically needed for hydrothermal dispatch where prices are marginal cost-based. Can often be approximated by scenario-based approaches.
Belief States (POMDP)
Extends SDDP to partially observable Markov decision processes where the agent maintains a probability distribution (belief) over hidden states. Useful for modeling phenomena like unobservable climate regimes.
Why Deferred: Research-level feature with limited practical benefit for most hydrothermal applications. Can often be approximated by expanding Markov states.
Duality Handlers (Lagrangian Relaxation)
Methods to generate valid cuts from MIP subproblems when integer variables are present (e.g., unit commitment). Includes Lagrangian relaxation and strengthened Benders cuts.
Why Deferred: Significant complexity in Lagrangian multiplier updates. Alternative: solve unit commitment deterministically after SDDP provides marginal values.
Cross-References
- Configuration Reference – Config options for implemented features
- SDDP Algorithm – Core algorithm that deferred features extend
- Hydro Production Models – Base FPHA that C.6 enhances
- Cut Management – Cut formulation that multi-cut (C.3) modifies
- Risk Measures – Risk framework that Markovian (C.4) and risk-adjusted passes extend
- Block Formulations – Block structure that temporal decoupling (C.7) generalizes; policy validation requirement (§4) motivates C.9
- PAR Inflow Model – Standard PAR(p) that CEPEL PAR(p)-A (C.8) extends
- Equipment Formulations – Thermal formulations that GNL (C.1) extends
- Input System Entities – Entity schemas for batteries (C.2) and non-controllables (C.5)
- Input Scenarios – External scenario data model (C.11, C.12)
- Scenario Generation – Opening tree (C.11), complete tree concept (C.12), sampling scheme abstraction (C.13-C.16)
- Training Loop – Must persist policy metadata for C.9 validation; forward/backward pass structure for C.13-C.16
- Simulation Architecture – Must validate policy compatibility (C.9) on entry
- Checkpointing – Checkpoint format that stores policy metadata (C.9)
- Binary Formats – Policy file format that carries metadata (C.9)
Glossary
Power system terminology used in Cobre, with Portuguese equivalents where they appear in documentation or Brazilian regulatory context.
Power System
| English | Portuguese | Definition |
|---|---|---|
| Block | Patamar | An intra-stage time period (e.g., peak, shoulder, off-peak) representing load level variation within a stage; can be parallel (independent) or chronological (sequential) |
| Bus | Barramento | A node in the electrical network where components connect |
| Line | Linha / Circuito | A transmission line or transformer connecting two buses |
| Subsystem | Subsistema | A region of the interconnected grid (e.g., SE/CO, S, NE, N in Brazil) |
| Exchange | Intercâmbio | Power transfer between subsystems |
| Load | Carga / Demanda | Electrical power consumption at a bus |
| Deficit | Déficit | Unmet demand — load that cannot be served by available generation |
Hydro Generation
| English | Portuguese | Definition |
|---|---|---|
| Hydro plant | Usina hidrelétrica (UHE) | A hydroelectric generating station |
| Reservoir | Reservatório | Water storage volume behind a dam |
| Storage | Armazenamento | Current water volume in a reservoir (hm³) |
| Inflow | Afluência / Vazão natural | Natural water flow arriving at a reservoir |
| Turbined outflow | Vazão turbinada | Water passing through turbines to generate electricity |
| Spillage | Vertimento | Water released from a reservoir without generating electricity |
| Cascade | Cascata | Sequence of hydro plants along the same river |
| Downstream | Jusante | Direction of water flow; the plant that receives outflow from upstream |
| Upstream | Montante | Direction against water flow |
| Productivity | Produtibilidade | Conversion factor from water flow (m³/s) to power (MW) |
| Run-of-river | Fio d’água | Hydro plant with no significant storage capacity |
| Diversion | Desvio | Water bypassed to a separate channel, not passing through turbines |
| Evaporation | Evaporação | Water loss from the reservoir surface due to heat |
| Forebay level | Nível de montante | Water level at the upstream face of the dam, a function of reservoir storage |
| FPHA | - | Four-Point Head Approximation — piecewise-linear model of hydro generation as a function of storage, flow, and spillage |
| Head | Queda | Height difference between reservoir level and tailrace level, determining generation efficiency |
| Tailrace level | Nível de jusante | Water level at the downstream channel below the dam, a function of total outflow |
Thermal Generation
| English | Portuguese | Definition |
|---|---|---|
| Thermal unit | Usina termelétrica (UTE) | A fossil-fuel or nuclear generating station |
| Minimum generation | Geração mínima / Inflexibilidade | Minimum output when the unit is committed |
| Operating cost | Custo variável unitário / CVU | Variable cost per MWh of generation |
| Startup cost | Custo de partida | Cost incurred when bringing a unit online |
Stochastic Modeling
| English | Portuguese | Definition |
|---|---|---|
| Scenario | Cenário | One realization of uncertain quantities (inflows, wind, etc.) |
| Stage | Estágio | A time period in the planning horizon |
| State variable | Variável de estado | Variables that link one stage to the next (storage, lagged inflows) |
| PAR(p) | PAR(p) | Periodic Autoregressive model of order p for inflow generation |
| Historical record | Registro histórico | Observed inflow data used to fit stochastic models |
| Innovation | Inovação | The independent noise term in the PAR(p) model, representing the unpredictable component after removing autoregressive structure |
| Yule-Walker equations | Equações de Yule-Walker | System of linear equations relating autoregressive coefficients to sample autocorrelations, used to fit PAR(p) model parameters |
SDDP Algorithm
| English | Portuguese | Definition |
|---|---|---|
| Cut (Benders cut) | Corte (de Benders) | A linear inequality approximating the future cost function |
| Cost-to-go function | Função de custo futuro (FCF) | Expected cost from the current stage to the end of the horizon |
| Forward pass | Passagem direta | Simulation phase: solve stages sequentially under sampled scenarios |
| Backward pass | Passagem reversa | Optimization phase: generate cuts by solving from the last stage backward |
| Lower bound | Limite inferior | Estimate from the first-stage problem (improves with more cuts) |
| Upper bound | Limite superior | Statistical estimate from simulation (converges to true cost in risk-neutral setup) |
| Optimality gap | Gap de otimalidade | Difference between upper and lower bounds, as a percentage |
| Dual variable | Variável dual / Multiplicador | Shadow price from LP solution; indicates marginal value of a resource |
| Marginal cost (CMO) | Custo Marginal de Operação | Shadow price of the demand constraint — the cost of one additional MWh |
| Cut pool | Conjunto de cortes | Collection of all generated Benders cuts for a given stage |
| Discount factor | Fator de desconto | Multiplicative factor applied to future costs reflecting the time value of money; required for infinite-horizon SDDP convergence |
| Epigraph variable | - | The auxiliary LP variable that lower-bounds the true cost-to-go function ; named after the epigraph of a convex function |
| Infinite horizon | Horizonte infinito | Policy graph with cyclic transitions, used for long-term planning |
| Opening | Abertura | A pre-generated scenario noise vector used in the backward pass |
| Opening tree | Árvore de aberturas | The fixed set of pre-generated noise vectors used in the backward pass; generated once before training begins and reused across all iterations. Each stage has num_scenarios noise vectors. See Scenario Generation. |
| Outer approximation | Aproximação exterior | The piecewise-linear lower bound on the cost-to-go function constructed from Benders cuts; the primary output of SDDP training |
| Policy graph | Grafo de política | Directed graph defining the stage structure and transitions in an SDDP problem |
| Relatively complete recourse | Recurso relativamente completo | Property that every LP subproblem is feasible for all incoming states and scenario realizations; ensured in Cobre via penalty slack variables |
| Trajectory record | Trajetória | Data structure capturing one stage’s forward pass result: primal solution, dual solution, stage cost, and end-of-stage state. Used for cut coefficient extraction in the backward pass and for simulation output |
| Trial point | Ponto amostral | The state visited during a forward pass, used to construct cuts in the backward pass |
Risk Measures
| English | Portuguese | Definition |
|---|---|---|
| Coherent risk measure | Medida de risco coerente | A risk measure satisfying monotonicity, translation equivariance, positive homogeneity, and subadditivity; CVaR is the canonical example used in SDDP |
| CVaR | CVaR | Conditional Value at Risk — expected cost in the worst α% of scenarios |
| EAVaR | - | Expectation plus Average Value-at-Risk; the convex combination used as Cobre’s risk measure |
| Risk-neutral | Neutro ao risco | Optimization that minimizes expected cost only |
| Risk-averse | Averso ao risco | Optimization that penalizes high-cost tail scenarios |
Brazilian Ecosystem
| Term | Definition |
|---|---|
| NEWAVE | Long-term hydrothermal dispatch model (monthly, 5–10 years) |
| DECOMP | Medium-term model (weekly resolution) |
| DESSEM | Short-term model (hourly/half-hourly, day-ahead) |
| GEVAZP | Synthetic scenario generation tool |
| ONS | Operador Nacional do Sistema Elétrico — Brazilian grid operator |
| CCEE | Câmara de Comercialização de Energia Elétrica — electricity trading chamber |
| CEPEL | Centro de Pesquisas de Energia Elétrica — R&D center that develops the official programs |
| SIN | Sistema Interligado Nacional — the Brazilian interconnected power system |
Solver
| English | Portuguese | Definition |
|---|---|---|
| Basis | Base | The set of basic variables defining a vertex of the LP feasible region |
| CLP | - | Open-source LP solver from COIN-OR, used as a reference backend in cobre-solver |
| HiGHS | - | Open-source LP/MIP solver used as the default backend in cobre-solver |
| LP (Linear Program) | Programa Linear | An optimization problem with a linear objective and linear constraints |
| RowBatch | - | A batch of LP rows (constraints) in CSR sparse format for bulk addition to a solver instance via the add_rows method |
| Simplex method | Método Simplex | Algorithm for solving linear programs by traversing vertices of the feasible polytope |
| Warm-start | Partida a quente | Reusing a previous solution basis to accelerate solving a modified LP |
Data Formats
| English | Portuguese | Definition |
|---|---|---|
| Arrow | - | In-memory columnar data format for analytics; Parquet is its on-disk counterpart |
| CSC (Compressed Sparse Column) | - | Column-major sparse matrix format used for stage LP templates passed to solvers |
| CSR (Compressed Sparse Row) | - | Row-major sparse matrix format used for batch cut addition via solver addRows APIs |
| FlatBuffers | - | Zero-copy serialization library used for policy data (cuts, states) |
| Parquet | - | Columnar file format for efficient storage and retrieval of large tabular datasets |
HPC (High-Performance Computing)
| English | Portuguese | Definition |
|---|---|---|
| MPI | - | Message Passing Interface — standard for distributed-memory parallel computing |
| NUMA | - | Non-Uniform Memory Access — hardware topology where memory access time depends on processor-memory proximity |
| OpenMP | - | API for shared-memory parallel programming via compiler directives; Cobre uses Rayon (Rust data-parallelism library) instead of OpenMP for intra-node thread parallelism |
| Rayon | - | Rust data-parallelism library used for intra-node thread parallelism in Cobre; provides work-stealing parallel iterators as a safe, idiomatic alternative to OpenMP |
| Rank | - | An MPI process; each rank has its own address space |
| Thread affinity | - | Binding of threads to specific CPU cores to prevent migration and ensure NUMA-local memory access |
Cobre Ecosystem
| English | Portuguese | Definition |
|---|---|---|
| Solver vertical | - | A complete solver algorithm stack built on the Cobre ecosystem (e.g., SDDP for hydrothermal dispatch, OPF for power flow) |
| Ecosystem vision | - | The design goal of Cobre as a generic power system ecosystem with multiple solver verticals sharing a common data model and HPC infrastructure |
Bibliography
Core references for the algorithms and methods implemented in Cobre.
SDDP Foundations
-
Benders, J.F. (1962). Partitioning procedures for solving mixed-variables programming problems. Numerische Mathematik, 4(1), 238–252. — The original Benders decomposition paper. Foundation for the L-shaped method and SDDP.
-
Birge, J.R. (1985). Decomposition and partitioning methods for multistage stochastic linear programs. Operations Research, 33(5), 989–1007. — Multi-cut formulation for stochastic programs. Origin of the multi-cut L-shaped method.
-
Birge, J.R. & Louveaux, F.V. (2011). Introduction to Stochastic Programming. Springer, 2nd edition. — Standard textbook reference for stochastic programming theory and decomposition methods.
-
Pereira, M.V.F. & Pinto, L.M.V.G. (1991). Multi-stage stochastic optimization applied to energy planning. Mathematical Programming, 52(1–3), 359–375. — The original SDDP paper. Foundational for everything in
cobre-sddp. -
Philpott, A.B. & Guan, Z. (2008). On the convergence of stochastic dual dynamic programming and related methods. Operations Research Letters, 36(4), 450–455. — Convergence theory for SDDP.
-
Costa, B.F.P., Calixto, A.O., Sousa, R.F.S., Figueiredo, R.T., Penna, D.D.J., Khenayfis, L.S. & Oliveira, A.M.R. (2025). Boundary conditions for hydrothermal operation planning problems: the infinite horizon approach. Proceeding Series of the Brazilian Society of Computational and Applied Mathematics, 11(1), 1–7. doi:10.5540/03.2025.011.01.0355 — Infinite horizon boundary conditions for hydrothermal planning. Related to the infinite horizon extension in
cobre-sddp.
Cut Management and Performance
-
de Matos, V.L., Philpott, A.B. & Finardi, E.C. (2015). Improving the performance of Stochastic Dual Dynamic Programming. Journal of Computational and Applied Mathematics, 290, 196–208. — Cut selection strategies. Basis for the cut selection in
cobre-sddp. -
Bandarra, M. & Guigues, V. (2021). Single cut and multicut stochastic dual dynamic programming with cut selection for multistage stochastic linear programs: convergence proof and numerical experiments. Computational Management Science, 18(2), 125–148. doi:10.1007/s10287-021-00387-8. Preprint: arXiv:1902.06757 — Convergence proof for Level-1 and LML1 cut selection strategies. Guarantees finite convergence with probability 1.
Risk Measures
-
Shapiro, A. (2011). Analysis of stochastic dual dynamic programming method. European Journal of Operational Research, 209(1), 63–72. — Convergence analysis, complexity bounds, and risk-averse extensions (including CVaR) for SDDP.
-
Philpott, A.B. & de Matos, V.L. (2012). Dynamic sampling algorithms for multi-stage stochastic programs with risk aversion. European Journal of Operational Research, 218(2), 470–483. — Dynamic sampling with risk aversion and Markovian scenario transitions.
-
Philpott, A.B., de Matos, V.L. & Finardi, E.C. (2013). On solving multistage stochastic programs with coherent risk measures. Operations Research, 61(4), 957–970. doi:10.1287/opre.2013.1175 — Time-consistent risk-averse SDDP with CVaR. Dual representation for risk-averse cut generation and nested risk measures.
Upper Bound and Inner Approximation
- Costa, B.F.P. & Leclere, V. (2023). Duality of upper bounds in stochastic dynamic programming. Optimization Online. optimization-online.org/?p=23738
— Duality framework for upper bounds in stochastic dynamic programming. Basis for the upper bound evaluation in
cobre-sddp.
Inflow Modeling
- Larroyd, P.V., Pedrini, R., Beltran, F., Teixeira, G., Finardi, E.C. & Picarelli, L.B. (2022). Dealing with Negative Inflows in the Long-Term Hydrothermal Scheduling Problem. Energies, 15(3), 1115. doi:10.3390/en15031115 — Inflow non-negativity treatment for PAR(p) models in hydrothermal dispatch.
Software References
- Dowson, O. & Kapelevich, L. (2021). SDDP.jl: A Julia Package for Stochastic Dual Dynamic Programming. INFORMS Journal on Computing, 33(1), 27–33. — Algorithmic reference for SDDP.jl. Influenced cut management and risk measure implementation in Cobre.
Brazilian Power System
-
CEPEL Technical Documentation. https://see.cepel.br/manual/libs/latest/ — Official documentation for the NEWAVE/DECOMP/DESSEM suite.
-
SPARHTACUS Wiki. https://github.com/SPARHTACUS/SPTcpp/wiki — Documentation for the C++ SDDP implementation. Reference for auditable pre-processing approach.
Solver
- Huangfu, Q. & Hall, J.A.J. (2018). Parallelizing the dual revised simplex method. Mathematical Programming Computation, 10, 119–142. — HiGHS simplex implementation. Cobre uses HiGHS as its default LP solver.
Frequently Asked Questions
This page is under construction.
Notation
This page defines the complete mathematical notation used across the Cobre documentation: index sets, parameters, decision variables, and dual variables. It is the canonical reference for symbol meanings, ensuring consistency across all mathematical and data model content.
1. General Notation Conventions
This document follows SDDP.jl notation conventions for consistency with the broader SDDP literature:
| Convention | Meaning |
|---|---|
| Stage index | |
| Scenario realization at stage | |
| State variables at end of stage | |
| Incoming state (from previous stage) | |
| Value function (cost-to-go) at stage | |
| Epigraph variable approximating | |
| Dual variables (Lagrange multipliers) | |
| Cut intercept and coefficients | |
| Iteration counter |
2. Index Sets
| Symbol | Description | Typical Size | Notes |
|---|---|---|---|
| Stages | 60-120 | 5-10 year monthly horizon | |
| Blocks within stage | 1-24 | 3 typical (LEVE/MÉDIA/PESADA) | |
| Buses | 4-10 | 4-5 for SIN subsystems | |
| Hydro plants | 160 | All plants in system | |
| Operating hydros (can generate) | Most/all plants typically operating | ||
| Filling hydros (no generation) | 0 | Usually 0; rare for new plants under commissioning | |
| Hydros using FPHA production model | 50 | Subset with fitted hyperplanes | |
| Hydros using constant productivity | Complement of within | ||
| Thermal plants | 130 | ||
| Non-controllable generation sources | 0 | Renewable curtailment entities | |
| Transmission lines | 10 | Regional interconnections | |
| All contracts () | 10 | Unified contract set | |
| , | Import/export contracts | 5 | |
| Pumping stations | 5 | ||
| Generic constraints | 50 | User-defined | |
| Deficit segments for bus | 1 | Multiple segments optional | |
| FPHA planes for hydro | 125 | Typical value; depends on grid resolution | |
| Upstream hydros of | 1-2 | Immediate upstream in cascade | |
| Scenario realizations at stage | 20 | Standard branching factor |
3. Parameters
3.1 Time and Conversion
| Symbol | Units | Description |
|---|---|---|
| hours | Duration of block | |
| - | Block weight (fraction of stage) | |
| hm³/(m³/s) | Time conversion: m³/s over stage → hm³ |
Time Conversion Factor Derivation
The factor converts a flow rate in m³/s to a volume in hm³ accumulated over the stage duration.
Fundamental Relationship:
Unit Conversion Chain:
- Flow rate: [m³/s]
- Time period: [hours]
- Target volume: [hm³] = m³
For a stage with multiple blocks: If the stage has blocks with durations hours, and the flow is assumed constant across the stage (parallel blocks), the total time is hours:
Dimensional Analysis:
Worked Example (Monthly Stage):
| Block | Name | Duration (h) |
|---|---|---|
| 1 | LEVE | 200 |
| 2 | MÉDIA | 300 |
| 3 | PESADA | 228 |
| Total | 728 |
Verification: A constant inflow of m³/s over the month yields:
Direct calculation: ✓
3.2 Load and Costs
| Symbol | Units | Description |
|---|---|---|
| MW | Load at bus , block | |
| $/MWh | Deficit cost at bus , segment | |
| MW | Deficit segment depth | |
| $/MWh | Excess generation cost | |
| $/MWh | Thermal cost at plant , segment | |
| $/(m³/s·h) | Spillage cost | |
| $/(m³/s·h) | Diversion cost | |
| $/MWh | Exchange (transmission) cost | |
| , | $/MWh | Contract import cost / export revenue |
3.3 Hydro Parameters
| Symbol | Units | Description |
|---|---|---|
| hm³ | Incoming storage (state from previous stage) | |
| , | hm³ | Storage bounds |
| , | m³/s | Turbined flow bounds |
| , | MW | Generation bounds |
| , | m³/s | Outflow bounds |
| MW/(m³/s) | Productivity (constant model) | |
| - | FPHA plane coefficients |
3.4 Transmission and Contract Parameters
| Symbol | Units | Description |
|---|---|---|
| , | MW | Line capacity (direct/reverse) |
| - | Line efficiency | |
| , | MW | Contract capacity bounds |
3.5 Inflow Model Parameters
Note on Periodicity: The PAR(p) model uses periodic parameters that repeat with a cycle length . Common configurations:
- Monthly stages: (seasons = months)
- Weekly stages: (seasons = weeks)
- Custom resolution: = number of distinct periods in the cycle
We use “season ” as a generic term for the position within the cycle, avoiding the term “month” which is resolution-specific. The mapping converts stage index to season index .
| Symbol | Units | Description |
|---|---|---|
| m³/s | Seasonal mean inflow for season | |
| - | AR coefficient for season , lag | |
| m³/s | Residual standard deviation for season | |
| m³/s | Incoming AR lag (state) |
4. Decision Variables
Notation Convention:
- Generation variables use with entity subscript: (hydro at plant ), (thermal at plant )
- Flow variables use intuitive single letters: (turbined), (spillage), (diversion/bypass)
- Total outflow is explicitly defined: (downstream channel flow)
- Contract variables use (chi) with direction superscript: ,
- Slack variables use with constraint-type superscript
Symbol Selection Rationale:
- (turbined): from “vazão turbinada” (Portuguese) or “discharge through turbines”
- (spillage): standard hydrology notation
- (diversion): “bypass” or “desvio” — avoids confusion with demand or deficit
- (outflow): total downstream flow affecting tailrace level
- (withdrawal): “retirada” — consumptive removal from the system
- (contract): Greek chi, visually distinct from cost symbol
4.1 Per-Block Variables
Per-block variables are indexed by :
| Variable | Domain | Units | Description |
|---|---|---|---|
| MW | Deficit at bus , segment | ||
| MW | Excess generation at bus | ||
| MW | Direct flow on line | ||
| MW | Reverse flow on line | ||
| MW | Thermal generation at plant , segment | ||
| m³/s | Turbined flow at hydro | ||
| m³/s | Spillage at hydro | ||
| MW | Hydro generation at plant | ||
| m³/s | Diversion/bypass flow (to separate channel) | ||
| - | m³/s | Total downstream outflow: | |
| free | m³/s | Evaporation (can be negative for condensation) | |
| m³/s | Water withdrawal (consumptive use) | ||
| m³/s | Pumped flow at station | ||
| MW | Contract import | ||
| MW | Contract export |
4.2 Stage-Level State Variables
| Variable | Domain | Units | Description |
|---|---|---|---|
| hm³ | End-of-stage storage | ||
| - | hm³ | Average storage during stage: | |
| fixed | m³/s | AR lag (fixed by state transition) | |
| $ | Future cost (cost-to-go approximation) |
4.3 Slack Variables
Slack variables for soft constraints:
| Variable | Domain | Units | Constraint |
|---|---|---|---|
| hm³ | Storage below minimum | ||
| hm³ | Filling target shortfall | ||
| m³/s | Turbined flow below minimum | ||
| m³/s | Outflow below minimum | ||
| m³/s | Outflow above maximum | ||
| MW | Generation below minimum | ||
| , | m³/s | Evaporation violation | |
| m³/s | Water withdrawal violation | ||
| m³/s | Inflow non-negativity (if enabled) |
5. Dual Variables
Dual variables are essential for cut coefficient computation in the SDDP backward pass. This section describes how state-linking constraints are formulated in the LP for efficient solver updates, and how the resulting dual variables map to cut coefficients.
5.1 LP Formulation Strategy for Efficient Hot-Path Updates
In the SDDP algorithm, each subproblem solve requires setting the incoming state values (storage volumes and AR lags from the previous stage). For computational efficiency with solvers like HiGHS, we formulate constraints so that:
Design Principle: All incoming state variables are isolated on the right-hand side (RHS) of their respective constraints.
This allows the hot path (forward/backward passes) to update subproblems by simply modifying row bounds via changeRowBounds() without rebuilding constraint matrices. The LP matrix coefficients remain constant across all subproblem solves within a stage.
5.2 Water Balance: LP Form
The water balance is mathematically:
For LP implementation, we rearrange to isolate on the RHS:
Expanding the net flows and collecting all LP variables on the LHS:
LP Structure:
- LHS: Linear combination of LP variables (storage , flows , , , etc.)
- RHS: Incoming state only (set via row bounds in hot path)
- Constraint type: Equality ()
5.3 AR Lag Constraints: LP Form
For autoregressive inflow state variables, the constraint fixes the current-stage lag variable to the incoming value:
LP Structure:
- LHS: Single LP variable (coefficient = 1)
- RHS: Incoming lag value (set via row bounds in hot path)
- Constraint type: Equality ()
5.4 Cut Coefficient Derivation from Duals
The SDDP cut at stage has the form:
where is the intercept and are the coefficients with respect to state variables.
Key principle: For a constraint written as , the dual variable represents:
where is the optimal objective value. This is the marginal cost with respect to increasing the RHS.
Storage Dual ()
For the storage fixing constraint (see LP Formulation §4a):
The dual measures: “How does optimal cost change if incoming storage increases by 1 hm³?”
Economic interpretation:
- More incoming storage means more water available for generation
- Water has value (can displace thermal generation or avoid deficit)
- Therefore, increasing decreases cost:
- By LP convention (minimization), this gives
Cut coefficient:
No sign change is needed because the incoming state appears directly on the RHS with coefficient . By the LP envelope theorem, this dual automatically captures all downstream effects — water balance, FPHA hyperplanes, and generic constraints — without manual combination of duals from multiple constraint types. See Cut Management.
AR Lag Dual ()
For the lag fixing constraint:
The dual measures: _“How does optimal cost change if incoming lag increases by 1 m³/s?”_
Economic interpretation:
- Higher historical inflow (in the PAR model) correlates with higher expected current inflow
- Higher inflows reduce cost (more hydro generation possible)
- Therefore, (increasing the lag decreases cost)
Cut coefficient:
The cut coefficient for lag is the dual variable directly, since appears on the RHS with coefficient . No sign change or scaling is needed.
5.5 Summary Table
| Symbol | Constraint (LP Form) | RHS | Cut Coefficient |
|---|---|---|---|
| (storage fixing) | (captures all downstream effects) | ||
| (direct) | |||
| Load balance | Marginal cost of energy | ||
| Water balance | - | Not used directly for cut coefficients | |
| FPHA hyperplane | - | Captured via automatically | |
| Generic constraint | - | Captured via automatically | |
| Benders cut | Cut activity indicator |
5.6 Implementation Notes
The hot-path solver update pattern (modifying RHS via changeRowBounds for incoming state, extracting duals via getRowDual for cut coefficients) is documented in the Solver HiGHS Implementation and Solver Abstraction specs. The key property: since incoming state variables appear on the RHS of fixing constraints with coefficient , no sign change is needed when mapping duals to cut coefficients (; for AR lags, is used directly). Cut coefficient extraction is a single contiguous slice read: dual[0..n_state].
Verification check: In a typical hydrothermal system:
- (water has value, more storage reduces cost)
- (cut value increases as storage decreases — future is more expensive with less water)
- The cut correctly penalizes low storage
Cross-References
- Theory: SDDP Theory — Algorithm overview and cut generation process
- Theory: Cut Management — Cut coefficient computation and aggregation details
- Theory: PAR(p) Autoregressive Models — Detailed PAR(p) model using inflow parameters defined here
- Specs: LP Formulation — Complete LP subproblem using this notation
- Specs: Cut Management — Formal cut management specification
- Specs: PAR Inflow Model — PAR(p) inflow model specification
- Specs: Hydro Production Models — FPHA plane coefficients and productivity
- Specs: Equipment Formulations — Thermal, contract, pumping variable notation