diff --git a/examples/no_strong_duality.jl b/examples/no_strong_duality.jl new file mode 100644 index 000000000..819fa56fd --- /dev/null +++ b/examples/no_strong_duality.jl @@ -0,0 +1,27 @@ +# Copyright 2017-19, Oscar Dowson. +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +using SDDP, GLPK, Test + +function no_strong_duality() + model = SDDP.PolicyGraph( + SDDP.Graph( + :root, + [:node], + [(:root => :node, 1.0), (:node => :node, 0.5)] + ), + optimizer = with_optimizer(GLPK.Optimizer), + lower_bound = 0.0) do sp, t + @variable(sp, x, SDDP.State, initial_value = 1.0) + @stageobjective(sp, x.out) + @constraint(sp, x.in == x.out) + end + + SDDP.train(model, iteration_limit = 20) + + @test SDDP.calculate_bound(model) ≈ 2.0 atol=1e-8 +end + +no_strong_duality() diff --git a/src/algorithm.jl b/src/algorithm.jl index 223cf62d0..35b91f2f7 100644 --- a/src/algorithm.jl +++ b/src/algorithm.jl @@ -936,14 +936,14 @@ end # Internal function: helper to conduct a single simulation. Users should use the # documented, user-facing function SDDP.simulate instead. function _simulate(model::PolicyGraph{T}, - variables::Vector{Symbol} = Symbol[]; - sampling_scheme::AbstractSamplingScheme = - InSampleMonteCarlo(), - custom_recorders = Dict{Symbol, Function}()) where {T} + variables::Vector{Symbol}; + sampling_scheme::AbstractSamplingScheme, + custom_recorders::Dict{Symbol, Function}, + require_duals::Bool) where {T} # Sample a scenario path. scenario_path, terminated_due_to_cycle = sample_scenario( - model, sampling_scheme - ) + model, sampling_scheme) + # Storage for the simulation results. simulation = Dict{Symbol, Any}[] # The incoming state values. @@ -1024,7 +1024,8 @@ end variables::Vector{Symbol} = Symbol[]; sampling_scheme::AbstractSamplingScheme = InSampleMonteCarlo(), - custom_recorders = Dict{Symbol, Function}() + custom_recorders = Dict{Symbol, Function}(), + require_duals::Bool = true )::Vector{Vector{Dict{Symbol, Any}}} Perform a simulation of the policy model with `number_replications` replications @@ -1067,17 +1068,19 @@ The value of the dual in the first stage of the second replication can be accessed as: simulation_results[2][1][:constraint_dual] + +If you do not require dual variables (or if they are not available), pass +`require_duals = false`. """ function simulate(model::PolicyGraph, number_replications::Int = 1, variables::Vector{Symbol} = Symbol[]; sampling_scheme::AbstractSamplingScheme = InSampleMonteCarlo(), - custom_recorders = Dict{Symbol, Function}()) - return [_simulate( - model, - variables; - sampling_scheme = sampling_scheme, - custom_recorders = custom_recorders) - for i in 1:number_replications] + custom_recorders = Dict{Symbol, Function}(), + require_duals::Bool = true) + return map(i -> _simulate( + model, variables; sampling_scheme = sampling_scheme, + custom_recorders = custom_recorders, require_duals = require_duals), + 1:number_replications) end