gtopt::SddpOptions struct

SDDP-specific solver configuration parameters.

Groups all SDDP-related options into a single sub-object for clearer JSON organization. Field names omit the sddp_ prefix since they already live inside the sddp_options namespace.

All fields are optional — defaults are applied via PlanningOptionsLP.

Public functions

auto merge(SddpOptions&& opts) -> void

Public variables

OptReal alpha_max
Upper bound for future cost variable α (default: 1e12)
OptReal alpha_min
Lower bound for future cost variable α (default: 0.0)
OptName aperture_directory
Directory for aperture-specific scenario data.
OptReal aperture_timeout
Timeout in seconds for individual aperture LP solves in the SDDP backward pass.
std::optional<Array<Uid>> apertures
Aperture UIDs for the backward pass.
OptBool api_enabled
Enable the SDDP monitoring API (writes JSON status file each iteration; default: true)
OptInt backward_max_fallbacks
Maximum algorithm fallback attempts for backward-pass and aperture solves.
std::optional<SolverOptions> backward_solver_options
Optional LP solver configuration for SDDP backward pass.
OptName boundary_cuts_file
CSV file with boundary (future-cost) cuts for the last phase.
std::optional<BoundaryCutsMode> boundary_cuts_mode
How boundary cuts are loaded: noload, separated (default), or combined.
OptInt boundary_max_iterations
Maximum number of SDDP iterations to load from the boundary cuts file. Only cuts from the last N iterations (by iteration column, i.e. PLP's IPDNumIte) are loaded. 0 = load all (default).
OptReal convergence_confidence
Confidence level for statistical convergence criterion (0-1).
std::optional<ConvergenceMode> convergence_mode
Convergence criterion mode selection.
OptReal convergence_tol
Relative gap tolerance for convergence (default: 1e-4)
OptReal cut_coeff_eps
Absolute tolerance for filtering numerically tiny Benders cut coefficients.
OptReal cut_coeff_max
Maximum allowed absolute coefficient in a Benders cut row.
std::optional<CutCoeffMode> cut_coeff_mode
How Benders cut coefficients are extracted from solved subproblems.
OptName cut_directory
Directory for Benders cut files (default: "cuts")
OptInt cut_prune_interval
Iterations between cut pruning passes. Default: 10.
std::optional<HotStartMode> cut_recovery_mode
Cut persistence mode: none (default), keep, append, or replace. Controls whether to load cuts from a previous run and how to handle the combined output file on completion.
std::optional<CutSharingMode> cut_sharing_mode
Cut sharing mode: none (default), expected, accumulate, or max.
OptName cuts_input_file
File path for loading initial cuts (hot-start; empty = cold start)
std::optional<ElasticFilterMode> elastic_mode
Elastic filter mode: single_cut (default, alias "cut") or multi_cut or backpropagate.
OptReal elastic_penalty
Penalty for elastic slack variables in feasibility (default: 1e6)
OptInt forward_max_fallbacks
Maximum algorithm fallback attempts for forward-pass solves.
std::optional<SolverOptions> forward_solver_options
Optional LP solver configuration for SDDP forward pass.
OptInt max_cuts_per_phase
Maximum retained cuts per (scene, phase) LP. 0 = unlimited (default).
OptInt max_iterations
Maximum number of forward/backward iterations (default: 100)
OptInt max_stored_cuts
Maximum total stored cuts per scene (0 = unlimited). Default: 0.
OptInt min_iterations
Minimum iterations before declaring convergence (default: 2)
std::optional<MissingCutVarMode> missing_cut_var_mode
How to handle cuts referencing state variables not in the model.
OptInt multi_cut_threshold
Forward-pass infeasibility count threshold for switching from single_cut to multi_cut (default: 10; 0 = never auto-switch)
OptName named_cuts_file
CSV file with named-variable cuts for hot-start across all phases.
OptReal prune_dual_threshold
Dual threshold for inactive cut detection. Default: 1e-8.
std::optional<RecoveryMode> recovery_mode
Recovery mode: none (0), cuts (1), or full (2). Controls what is recovered from a previous run:
OptBool save_aperture_lp
Save LP files for infeasible apertures to the log directory.
OptBool save_per_iteration
Save cuts to CSV after each iteration (default: true). When false, cuts are only saved at the end of the solve or on stop.
OptReal scale_alpha
Scale divisor for future cost variable α (default: 1000).
OptName sentinel_file
Path to a sentinel file; if it exists, the solver stops gracefully after the current iteration (analogous to PLP's userstop)
OptBool simulation_mode
OptBool single_cut_storage
Use single cut storage: store in per-scene vectors only. Default: false.
std::optional<StateVariableLookupMode> state_variable_lookup_mode
How update_lp elements obtain reservoir/battery volume between phases.
OptReal stationary_tol
Tolerance for stationary-gap convergence criterion.
OptInt stationary_window
Number of iterations to look back when checking for a stationary gap. Used by both the standalone stationary criterion and the statistical+stationary criterion. Default: 10.
OptInt update_lp_skip
Iterations to skip between update_lp dispatches. 0 = update every iteration (default). Applies to all volume-dependent LP element updates (seepage, discharge limit, production factor).
OptBool use_clone_pool
Reuse cached LP clones for aperture solves. Default: true.
OptBool warm_start
Enable warm-start for SDDP resolves. When true, previous forward-pass primal/dual solutions are loaded into clone LPs before resolving (backward pass, elastic filter, apertures). Combined with solver_options.reuse_basis, this enables efficient incremental re-solves. Default when unset: true.

Variable documentation

OptName gtopt::SddpOptions::aperture_directory

Directory for aperture-specific scenario data.

When present, scenarios referenced by Aperture::source_scenario are first looked up in this directory. If not found there, they fall back to the regular input_directory. This allows backward-pass apertures to use different affluent data than the forward-pass scenarios.

OptReal gtopt::SddpOptions::aperture_timeout

Timeout in seconds for individual aperture LP solves in the SDDP backward pass.

When an aperture LP exceeds this time, it is treated as infeasible (skipped), a WARNING is logged, and the solver continues with the remaining apertures. Default 15 seconds. 0 = no timeout.

std::optional<Array<Uid>> gtopt::SddpOptions::apertures

Aperture UIDs for the backward pass.

  • absent (nullopt) – use per-phase Phase::apertures (default)
  • empty array [] – no apertures (pure Benders)
  • non-empty [1,2,3] – use exactly these aperture UIDs, overriding per-phase apertures

OptInt gtopt::SddpOptions::backward_max_fallbacks

Maximum algorithm fallback attempts for backward-pass and aperture solves.

Controls how many alternative algorithms the solver tries when a backward-pass or aperture LP returns non-optimal. Default: 0 (no fallback — fail immediately).

std::optional<SolverOptions> gtopt::SddpOptions::backward_solver_options

Optional LP solver configuration for SDDP backward pass.

When set, these options are merged with the global PlanningOptions::solver_options. Backward-pass-specific options take precedence over the global ones.

Typical use: use dual simplex with reuse_basis for the backward pass (warm-started resolves after adding cuts).

OptName gtopt::SddpOptions::boundary_cuts_file

CSV file with boundary (future-cost) cuts for the last phase.

These are analogous to PLP's "planos de embalse" — external optimality cuts that approximate the expected future cost beyond the planning horizon. Each cut is of the form:

α ≥ rhs + Σ_i coeff_i · state_var_i

The CSV header row names the state variables (reservoir / battery); subsequent rows provide the cut name, iteration, scene UID, RHS, and gradient coefficients.

Format:

name,iteration,scene,rhs,Reservoir1,Reservoir2,...
cut_001,1,1,-5000.0,0.25,0.75,...

The scene column contains the scene UID (matching the uid field in gtopt's scene_array). The solver maps column headers to the LP state-variable columns in the last phase and adds each cut as a lower-bound constraint on the future cost variable α. If empty, no boundary cuts are loaded.

std::optional<BoundaryCutsMode> gtopt::SddpOptions::boundary_cuts_mode

How boundary cuts are loaded: noload, separated (default), or combined.

  • noload — do not load boundary cuts even if a file is given.
  • separated — load cuts per scene (scene UID matching; default).
  • combined — load all cuts into all scenes (broadcast).

OptReal gtopt::SddpOptions::convergence_confidence

Confidence level for statistical convergence criterion (0-1).

When > 0 and multiple scenes exist, convergence is checked via PLP-style confidence interval: UB - LB <= z_{α/2} * σ. Combined with stationary_tol, also handles the non-zero-gap case where the gap stabilises above the CI threshold.

Default: 0.95 (95% CI). Set to 0.0 to disable.

std::optional<ConvergenceMode> gtopt::SddpOptions::convergence_mode

Convergence criterion mode selection.

  • gap_only: deterministic gap test only.
  • gap_stationary: gap + stationary gap detection.
  • statistical: gap + stationary + CI (default, PLP-style).

The statistical mode degrades gracefully to gap_stationary when only one scene is present (no apertures / pure Benders).

OptReal gtopt::SddpOptions::cut_coeff_eps

Absolute tolerance for filtering numerically tiny Benders cut coefficients.

When constructing an optimality cut, any state-variable coefficient (reduced cost or row dual) whose absolute value is below this threshold is dropped — both the coefficient and its corresponding RHS adjustment are skipped. This removes solver numerical noise that would otherwise produce ill-conditioned cuts.

Inspired by PLP's OptiEPS mechanism (default 1e-8 there).

Default: 0.0 (no filtering — all coefficients are kept). Typical useful values: 1e-12 to 1e-8.

OptReal gtopt::SddpOptions::cut_coeff_max

Maximum allowed absolute coefficient in a Benders cut row.

When the largest state-variable coefficient in a newly built cut exceeds this threshold, the entire row (all coefficients, the α weight, and the RHS) is uniformly divided by max_coeff / cut_coeff_max. This preserves the constraint's feasible set while improving numerical conditioning.

A warning is logged each time a cut is rescaled.

Default: 0.0 (disabled — no rescaling). Typical useful values: 1e6 to 1e8.

std::optional<CutCoeffMode> gtopt::SddpOptions::cut_coeff_mode

How Benders cut coefficients are extracted from solved subproblems.

  • reduced_cost (default): uses reduced costs of fixed dependent columns.
  • row_dual: adds explicit coupling constraint rows and reads their duals (PLP-style).

Both are mathematically equivalent; row_dual may be preferred for cross-validation with PLP or when LP solver presolve affects reduced-cost reporting for fixed variables.

OptInt gtopt::SddpOptions::forward_max_fallbacks

Maximum algorithm fallback attempts for forward-pass solves.

Controls how many alternative algorithms the solver tries when a forward-pass LP returns non-optimal. Default: 2 (full cycle).

std::optional<SolverOptions> gtopt::SddpOptions::forward_solver_options

Optional LP solver configuration for SDDP forward pass.

When set, these options are merged with the global PlanningOptions::solver_options. Forward-pass-specific options take precedence over the global ones.

Typical use: use barrier for the forward pass (fresh solves) while using dual simplex for the backward pass (warm-started resolves).

std::optional<MissingCutVarMode> gtopt::SddpOptions::missing_cut_var_mode

How to handle cuts referencing state variables not in the model.

  • skip_coeff (default): drop the missing coefficient, load the cut.
  • skip_cut: skip the entire cut if any missing variable has a non-zero coefficient.

OptName gtopt::SddpOptions::named_cuts_file

CSV file with named-variable cuts for hot-start across all phases.

Unlike boundary cuts (which apply only to the last phase), these cuts include a phase column indicating which phase they belong to. The solver resolves named state-variable headers (reservoir / battery / junction) to LP column indices in the specified phase, then adds each cut as:

α_phase ≥ rhs + Σ_i coeff_i · state_var_i[phase]

Format:

name,iteration,scene,phase,rhs,Reservoir1,Reservoir2,...
hs_1_1_3,1,1,3,-5000.0,0.25,0.75,...

If empty, no named hot-start cuts are loaded.

std::optional<RecoveryMode> gtopt::SddpOptions::recovery_mode

Recovery mode: none (0), cuts (1), or full (2). Controls what is recovered from a previous run:

  • none: no recovery (cold start).
  • cuts: recover only Benders cuts.
  • full: recover cuts + state variable solutions (default).

OptBool gtopt::SddpOptions::save_aperture_lp

Save LP files for infeasible apertures to the log directory.

When true, each infeasible aperture clone is written as error_aperture_sc_<scene>_ph_<phase>_ap_<uid>.lp in the log directory. Useful for debugging but expensive in large cases. Default: false (disabled).

OptReal gtopt::SddpOptions::scale_alpha

Scale divisor for future cost variable α (default: 1000).

The LP alpha variable is α_lp = α / scale_alpha, with an objective coefficient of scale_alpha so that the physical contribution is preserved. Analogous to PLP's varphi scale — improves numerical conditioning when α values are orders of magnitude larger than other LP variables.

OptBool gtopt::SddpOptions::simulation_mode

Run in simulation mode: no training iterations (max_iterations=0), forward-only evaluation of the policy from loaded cuts. No cuts are saved. Default: false.

std::optional<StateVariableLookupMode> gtopt::SddpOptions::state_variable_lookup_mode

How update_lp elements obtain reservoir/battery volume between phases.

Controls the fallback in StorageLP::physical_eini for nonlinear LP coefficient updates (seepage, production factor, discharge limit). Does NOT affect SDDP state-variable chaining or cut generation.

  • warm_start (default): volume from warm-start solution, recovered state file, or vini. No cross-phase lookup.
  • cross_phase: volume from the previous phase's efin within the same forward pass.

OptReal gtopt::SddpOptions::stationary_tol

Tolerance for stationary-gap convergence criterion.

When the relative change in the convergence gap over the last stationary_window iterations falls below this value, the gap is considered stationary (no longer improving). This triggers convergence in two situations:

  1. Standalone: gap is stationary → declare convergence even if gap > convergence_tol (non-zero gap accepted).
  2. Combined with convergence_confidence: when the CI test fails (gap > z*σ) but the gap is stationary → declare convergence (the non-zero gap has stabilised and further iterations won't help).

Formula (after min_iterations and stationary_window completed): gap_change = |gap[i] − gap[i − window]| / max(1e-10, gap[i − window]) if gap_change < stationary_tol → gap is stationary

Default: 0.01 (1%). Set to 0.0 to disable.