Getting started
Installation
using Pkg
Pkg.add("DecisionRules")DecisionRules.jl builds policies with Flux.jl and subproblems with JuMP; training requires a DiffOpt-compatible solver for the stage problems (Ipopt for smooth NLPs, HiGHS for LPs/MIPs). For GPU-accelerated training of large NLPs, install the companion package DecisionRulesExa.jl (see GPU Acceleration with DecisionRulesExa.jl).
Anatomy of a training run
Every TS-DDR training run assembles the same five ingredients:
- Stage subproblems — one JuMP model per stage, wrapped with
DiffOpt.diff_optimizerso Lagrange duals and sensitivities are available. The incoming state, the uncertainty, and the policy's target state enter as parameters. - A policy — a Flux model mapping $[w_t;\, x_{t-1}]$ to a target state $\hat{x}_t$ (see Target-state policies).
- An uncertainty sampler — how trajectories $w_{1:T}$ are drawn; the three supported formats (independent pools, joint-scenario pools, trajectory samplers) are the subject of Uncertainty Sampling.
- A training formulation — deterministic equivalent, stage-wise, multiple shooting, or strict (see Three training formulations and Strict mode: penalty-free gradient signal).
- An evaluation protocol — out-of-sample stage-wise rollout via
RolloutEvaluation, with target- or realized-state feedback (see Evaluation semantics).
Quick start
using DecisionRules, JuMP, DiffOpt, Flux, Ipopt
# Build per-stage subproblems in JuMP (DiffOpt-enabled)
# subproblems, state_params_in, state_params_out, uncertainty_samples, initial_state = ...
# Define a policy: maps [uncertainty; state] → target state
policy = Chain(
Dense(policy_input_dim(num_uncertainties, num_states), 64, relu),
Dense(64, num_states),
)
# Train via stage-wise decomposition
train_multistage(
policy, initial_state, subproblems,
state_params_in, state_params_out, uncertainty_samples;
num_batches=100, optimizer=Flux.Adam(1e-3),
)Choosing a training formulation
| Formulation | Horizon coupling | Gradient source |
|---|---|---|
| Deterministic Equivalent | Full horizon, one large NLP | Duals on the coupled problem |
| Stage-wise (single shooting) | Sequential rollout | Duals + DiffOpt per stage |
| Multiple Shooting | Windowed sub-horizons | DiffOpt per window, continuity penalties |
| Strict subproblems | Sequential rollout, no slack | Pure shadow-price duals |
As a rule of thumb:
- start with stage-wise training — closed-loop, smallest solves, fewest assumptions;
- move to the deterministic equivalent (or its GPU implementation) when the per-stage solves are large and horizon-coupled gradient signal pays off;
- use multiple shooting as the middle ground on long horizons;
- switch to strict mode whenever you can construct a feasibility-guaranteeing policy — one that bounds its output to the one-stage reachable set $R(x, w)$ of the dynamics. Constructing $R$ is problem-specific (cheap for resource-balance dynamics with box bounds). The battery-storage AC-OPF specification shows both the battery-dynamic interval and the additional network-feasibility gate needed before strict mode is accepted. Strict mode eliminates the target-slack penalty and its tuning entirely, and the dual $\lambda_t$ becomes the pure shadow price.
Robustness and hardware
- Solver or differentiation failures during training are handled by the pluggable gradient fallback system — by default a failed iteration logs a warning and is skipped.
- Problems with large stage NLPs train an order of magnitude faster on GPU through DecisionRulesExa.jl, which implements the strict deterministic equivalent with ExaModels + MadNLP/cuDSS.
Where to go next
- Theory: multistage stochastic optimization, the TS-DDR framework, SDDP and inconsistent formulations, extensions.
- Worked problems: stochastic battery-storage AC-OPF, rocket control, and stochastic lot-sizing.
- API Reference: every exported symbol.