Implementation of the dynamic SDDiP algorithm
The implementation of DynamicSDDiP is contained in the src folder and consists of a multitude of files.
General functions
The first group of files is not related to steps of SDDiP but provides some general and auxiliary functions:
DynamicSDDiP.jl: General definition of the module.typedefs.jl: Defines all kinds of structs that are either required for the configuration of parameters for the algorithm or required within the algorithm, e.g. to store cut information.solverHandling.jl: Contains functionality to configure the solvers for the subproblems occuring in SDDiP, including setting some solver options. The solvers and (some of) their options can be specified by the user in theAppliedSolversstruct and are then processed in this file.logging.jl: Defines the logging process for our version of SDDiP. Mostly borrowed from SDDP.jl, but adjusted to the specifics of our requirements. In particular, much more information is logged per iteration, see Understanding the logging output.stopping.jl: Contains functionality for the stopping behavior of SDDiP. Mostly borrowed from SDDP.jl, but adapted to fit our logging process. Additionally, a deterministic stopping criterion can be used if the problem is not stochastic.objective.jl: Sets the objective function for a subproblem. Mostly borrowed from SDDP.jl, but adapted to our setting.state.jl: Contains functionality to deal with state variables. The main functionality is borrowed from SDDP.jl, but we had to make some adjustments. In particular, when setting up subproblems with Lipschitz regularization, state binarization and setting up auxiliary problems we need to make sure that we properly store state variable bounds, integer or binary requirements etc. in order to be able to restore them later.
State space handling and regularization
The second group of files provides some functionality for state binarization (see Binarization and non-convex cuts) and Lipschitz regularization (see Setting algorithmic parameters).
binarization.jl: Contains functionality for applying a temporary state binarization in the backward pass subproblems.- The code is written in such a way that the binary approximation is applied before a subproblem (or its dual) is solved and removed again afterwards. This procedure requires to cache some information on the original state variables in order to be able to recreate them later.
regularizations.jl: Contains functionality for applying a Lipschitz regularization to the subproblems.- The code is written in such a way that a regularization is applied before a subproblem is solved and removed again afterwards. The reason is that in the backward pass a different version of the subproblem has to be considered, which is easier to set up from the initial problem. This procedure requires to cache some information on the state variables and the original objective in order to recreate the original subproblem afterwards.
- The Lipschitz regularization initially leads to a non-linear objective function. The subproblem is then linearized by introducing additional linear constraints (with the specific steps depending on the chosen regularization norm).
- When a regularization is applied in the backward pass, a different set of functions is used, as it has to be accounted for a potential state binarization.
sigmaTest.jl: If Lipschitz regularization is applied in the forward pass, the function in this file performs a forward pass without regularization to see if thesigmaparameter is sufficiently large to ensure equivalence between the regularized and the non-regularized problem. This file is not relevant for the experiments in our paper.
Algorithmic backbone
The third group of files provides the main algorithmic backbone of SDDiP and mostly re-uses code from SDDP.jl.
algorithmMain.jl: Contains the main functions to start the SDDiP solution process.solve: Function that is called to start the solution process.- Initializes the logging, the stopping rules, the binary approximation of the state variables (if
state_approximation_regime == BinaryApproximation) and the Lipschitz regularization (ifregularization_regime == Regularization). - Note that it is required to re-initialize the Bellman functions after the standard SDDP.jl set-up in order to use our extended Bellman function and cut specification, which also allows for non-convex cuts.
- Start the finalization of the log-files after SDDiP has terminated.
- Initializes the logging, the stopping rules, the binary approximation of the state variables (if
solve_DynamicSDDiP- Makes sure to store some state variable information in a way that is required for the algorithm, especially if a temporary binarization is used in the cut generation process.
- Starts the logging process.
- Calls master_loop to start the actual solution process.
master_loop- Actual loop that calls the iteration function for each iteration.
- Calls the iteration logger.
- Calls
convergence_handler, a function that is required for the case where non-convex cuts are generated, and thus a Lipschitz regularization and a dynamic state binarization are used. The function checks if convergence according to the stopping criterion has been achieved and if the parameterssigmaorbinary_precisionshould be updated. For the experiments in this paper, this part is irrelevant.
iteration- Calls the
forward_passfunction. - Performs a refinement of the state binarization if required.
- Calls the
backward_passfunction. - Calls the
calculate_boundfunction to solve the first-stage problem and compute a lower bound (for minimization; otherwise an upper bound). - Updates the best found solution.
- Prepares and triggers iteration logging.
- Calls the
forward_pass.jl: Contains the main forward pass functionality, i.e. sampling a scenario and solving the forward pass subproblems. This is mostly borrowed from SDDP.jl. However, there are some notable changes:- Values $\theta_n^i$ of the cut approximation are stored in
epi_state. - Applies a Lipschitz regularization to the forward pass subproblem if required. Removes it afterwards.
- No coverage of objective or belief states.
- Values $\theta_n^i$ of the cut approximation are stored in
backward_pass.jl: Contains the main backward pass functionality, i.e. considering all realizations, calling functions fromdual.jlto solve the dual subproblems, updating the approximations of the value functions by calling functionsbellman.jland solving the first-stage problem incalculate_bound. This is mostly borrowed from SDDP.jl. However, there are some notable changes:- Passes the
epi_stateinformation to the subproblem solution. - No coverage of objective or belief states.
- Contains a loop to iterate over a list of
cut_generation_regimethat has been specified in thealgo_params. If certain criteria are met, cuts are generated using one regime after the other. For more information, see Setting algorithmic parameters. - If a temporary state binarization is used, the
anchor_state(which may deviate from the incumbent) is computed here. - If the dual restriction approach from Chen and Luedtke's paper is applied, the dual space will be restricted to a span of coefficients from previous Benders cuts. Using function
update_Benders_cut_listit is ensured that these coefficients are stored when (strengthened) Benders cuts are generated.
- Passes the
Dual problems and cut generation
The fourth group of files provides the functionality for solving dual subproblems and generating different types of cuts.
dual.jl: Contains functionality for solving the dual subproblems. Especially, for each type ofduality_regime(type of cuts) there exists a variant of functionget_dual_solution.jl.- Includes initializing the dual multipliers according to
dual_initialization_regime. - Includes applying a potential Lipschitz regularization in the backward pass according to
state_approximation_regimeandregularization_regime. - Includes solving the primal problem to get a bound on the dual objective value. * #
- Includes setting user-defined dual bounds from
dual_bound_regime. - Includes calling a function for solving a Lagrangian dual problem if required. Those functions are included in
lagrange.jl(for standard Lagrangian cuts) orlagrange_unified.jl(for our new Lagrangian cuts). - Includes calling a function to determine coefficients for the linear normalization function if Lagrangian LN cuts should be generated.
- Includes storing the (optimal) dual multipliers in the right format afterwards.
- Includes initializing the dual multipliers according to
As described in our paper, a badly chosen core point candidate may lead to an unbounded normalized Lagrangian dual problem, and a failure of generating a cut. Therefore, we try to identify potential unboundedness in advance. We do so by checking for infeasibility of a related primal problem (for theoretical details, we refer to our paper). This check is done in function detect_unboundedness. If potential unboundedness is detected, we may either generate a strengthened Benders cut instead of an LN Lagrangian cut, or introduce artificial bounds to the dual problem.
Note that in certain cases ($\pi_{n0} \approx 0$, $(u_n, u_{n0}) \approx 0)$ we do not generate cuts in order to avoid numerical issues or adding redundant cuts.
lagrange.jl: Contains functionality to solve the standard Lagrangian dual problem from SDDiP.- Includes solving the inner relaxation and the outer problem using Kelley's cutting-plane method or a level bundle method.
- Includes the option to solve an augmented problem.
- Includes functionality for
MinimalNormChoice. - Includes the option to use suboptimal multipliers as well for approximations in the outer problem.
lagrange_preparation.jl: Contains some auxiliary functions required forlagrange.jl.- Includes relaxing and restoring constraints.
- Includes setting multiplier bounds.
- Includes regularization preparation. Note that here a weighted variant of
norm_liftedis used. - Includes initializing dual multipliers.
- Includes storing optimal dual multipliers and a status check for the solution.
lagrange_unified.jl: Same aslagrange.jlbut catered to normalized Lagrangian dual problems. This means that an additional multiplier $\pi_{n0}$ is considered, normalizations are used and dual space restriction is possible.lagrange_unified_preparation.jl: Same aslagrange_preparation.jlbut catered to normalized Lagrangian dual problems. In particular, contains functions to execute the normalization or dual space restriction.lagrange_unified_core.jl: Contains functionality for the computation of core point candidates when generating LN Lagrangian cuts.- Includes functions
get_core_pointandget_normalization_coefficientsfor different type of heuristics. - Includes functionality to solve primal auxiliary problems for unboundedness detection.
- Includes functions
Updating the value function approximations
The fifth group of files provides the functionality for updating the approximations of the value functions by adding new cut constraints.
bellman_jl: Contains all kinds of functions to model cuts given the dual multipliers obtained indual.jl. The main structure of the code follows that in SDDP.jl. However, the code contains many adjustments and extensions for handling our new types of Lagrangian cuts and non-convex cuts (see Binarization and non-convex cuts).- Extension of general SDDP.jl functions to the case of
NonlinearCut(e.g. usinganchor_points,sigma). In particular, the functionrepresent_cut_projection_closureis implemented forSOS1andBigMascut_projection_regime. It models the (linearized) KKT constraints representing a non-convex cut. - Extension of general SDDP.jl functions to the case of deep or LN Lagrangian cuts (e.g. using
epi_statesanddual_0_var). - Some added functionality to handle numerical issues and cut redundance (e.g.
add_cut_flag,check_for_cut_away). - No coverage of objective or belief states.
- Extension of general SDDP.jl functions to the case of
cut_selection.jl: Contains functionality for cut selection schemes. Mostly borrowed from SDDP.jl but slightly adjusted so that also non-convex cuts can be used.
This page was generated using Literate.jl.