Access variables from a previous stage

A common question is "how do I use a variable from a previous stage in a constraint?"

Info

If you want to use a variable from a previous stage, it must be a state variable.

Here are some examples:

Access a first-stage decision in a future stage

This is often useful if your first-stage decisions are capacity-expansion type decisions (e.g., you choose first how much capacity to add, but because it takes time to build, it only shows up in some future stage).

julia> using SDDP, HiGHS
julia> SDDP.LinearPolicyGraph( stages = 10, sense = :Max, upper_bound = 100.0, optimizer = HiGHS.Optimizer, ) do sp, t # Capacity of the generator. Decided in the first stage. @variable(sp, capacity >= 0, SDDP.State, initial_value = 0) # Quantity of water stored. @variable(sp, reservoir >= 0, SDDP.State, initial_value = 0) # Quantity of water to use for electricity generation in current stage. @variable(sp, generation >= 0) if t == 1 # There are no constraints in the first stage, but we need to push the # initial value of the reservoir to the next stage. @constraint(sp, reservoir.out == reservoir.in) # Since we're maximizing profit, subtract cost of capacity. @stageobjective(sp, -capacity.out) else # Water balance constraint. @constraint(sp, balance, reservoir.out - reservoir.in + generation == 0) # Generation limit. @constraint(sp, generation <= capacity.in) # Push capacity to the next stage. @constraint(sp, capacity.out == capacity.in) # Maximize generation. @stageobjective(sp, generation) # Random inflow in balance constraint. SDDP.parameterize(sp, rand(4)) do w set_normalized_rhs(balance, w) end end endA policy graph with 10 nodes. Node indices: 1, ..., 10

Access a decision from N stages ago

This is often useful if have some inventory problem with a lead-time on orders.

julia> using SDDP, HiGHS
julia> SDDP.LinearPolicyGraph( stages = 10, sense = :Max, upper_bound = 100, optimizer = HiGHS.Optimizer, ) do sp, t # Current inventory on hand. @variable(sp, inventory >= 0, SDDP.State, initial_value = 0) # Inventory pipeline. # pipeline[1].out are orders placed today. # pipeline[5].in are orders that arrive today and can be added to the # current inventory. # Stock moves up one slot in the pipeline each stage. @variable(sp, pipeline[1:5], SDDP.State, initial_value = 0) # The number of units to order today. @variable(sp, 0 <= buy <= 10) # The number of units to sell today. @variable(sp, sell >= 0) # Buy orders get placed in the pipeline. @constraint(sp, pipeline[1].out == buy) # Stock moves up one slot in the pipeline each stage. @constraint(sp, [i=2:5], pipeline[i].out == pipeline[i-1].in) # Stock balance constraint. @constraint(sp, inventory.out == inventory.in - sell + pipeline[5].in) # Maximize quantity of sold items. @stageobjective(sp, sell) endA policy graph with 10 nodes. Node indices: 1, ..., 10
Warning

You must initialize the same number of state variables in every stage, even if they are not used in that stage.