martinbiel / StochasticPrograms.jl

Julia package for formulating and analyzing stochastic recourse models.
MIT License
75 stars 25 forks source link

Fix instantiation for vector of decisions #5

Closed rtwalker closed 4 years ago

rtwalker commented 4 years ago

Firstly, this is really a fantastic package, and I was very excited to see the recent updates! Thanks for all the work that has gone into making it great.

I ran into an issue that (I think) I was able to diagnose and remedy. It occurred while I was trying to instantiate a model using an LShaped.Optimizer, where the model had a vector of decision variables as opposed to scalar decisions.

To convert the Quick Start example to a MWE,

simple_model = @stochastic_model begin
    @stage 1 begin
        @parameters begin
            b = [40, 20]
            c = [100, 150]
        end
        @decision(model, x[i = 1:2])
        @objective(model, Min, sum(c[i]*x[i] for i in 1:2))
        @constraint(model, sum(x[i] for i in 1:2) <= 120)
        @constraint(model, [i = 1:2], x[i] >= b[i])
    end
    @stage 2 begin
        @uncertain q₁ q₂ d₁ d₂
        @variable(model, 0 <= y₁ <= d₁)
        @variable(model, 0 <= y₂ <= d₂)
        @objective(model, Max, q₁*y₁ + q₂*y₂)
        @constraint(model, 6*y₁ + 10*y₂ <= 60*x[1])
        @constraint(model, 8*y₁ + 5*y₂ <= 80*x[2])
    end
end

ξ₁ = Scenario(q₁ = 24.0, q₂ = 28.0, d₁ = 500.0, d₂ = 100.0, probability = 0.4)
ξ₂ = Scenario(q₁ = 28.0, q₂ = 32.0, d₁ = 300.0, d₂ = 300.0, probability = 0.6)

julia> sp_lshaped = instantiate(simple_model, [ξ₁, ξ₂], optimizer = LShaped.Optimizer)

would give the following error on master:

ERROR: type #decision has no field scalar_variables
Stacktrace:
 [1] getproperty(::Function, ::Symbol) at ./Base.jl:33
 [2] add_variable(::Model, ::VariablesConstrainedOnCreation{StochasticPrograms.MultipleKnownSet{Float64},VectorShape,ScalarVariable{Float64,Float64,Float64,Float64}}, ::Array{String,1}) at /Users/ryanwalker/.julia/dev/StochasticPrograms/src/types/decisions/macros.jl:68
 [3] #4 at /Users/ryanwalker/.julia/packages/JuMP/YXK4e/src/macros.jl:79 [inlined]
 [4] (::var"#4#14")(::Model, ::NamedTuple{(),Tuple{}}) at ./none:0
 [5] generate_vertical!(::StochasticPrograms.ScenarioProblems{Scenario{NamedTuple{(:q₁, :q₂, :d₁, :d₂),NTuple{4,Float64}}}}, ::var"#4#14", ::var"#12#22", ::NamedTuple{(),Tuple{}}, ::NamedTuple{(),Tuple{}}, ::Decisions, ::Nothing) at /Users/ryanwalker/.julia/dev/StochasticPrograms/src/methods/vertical/generation.jl:65
 [6] generate!(::StochasticProgram{2,Tuple{StochasticPrograms.Stage{NamedTuple{(),Tuple{}}},StochasticPrograms.Stage{NamedTuple{(),Tuple{}}}},VerticalStructure{2,1,Tuple{StochasticPrograms.ScenarioProblems{Scenario{NamedTuple{(:q₁, :q₂, :d₁, :d₂),NTuple{4,Float64}}}}}}}, ::VerticalStructure{2,1,Tuple{StochasticPrograms.ScenarioProblems{Scenario{NamedTuple{(:q₁, :q₂, :d₁, :d₂),NTuple{4,Float64}}}}}}, ::Int64) at /Users/ryanwalker/.julia/dev/StochasticPrograms/src/methods/vertical/generation.jl:40
 [7] generate! at /Users/ryanwalker/.julia/dev/StochasticPrograms/src/methods/vertical/generation.jl:6 [inlined]
 [8] generate!(::StochasticProgram{2,Tuple{StochasticPrograms.Stage{NamedTuple{(),Tuple{}}},StochasticPrograms.Stage{NamedTuple{(),Tuple{}}}},VerticalStructure{2,1,Tuple{StochasticPrograms.ScenarioProblems{Scenario{NamedTuple{(:q₁, :q₂, :d₁, :d₂),NTuple{4,Float64}}}}}}}) at /Users/ryanwalker/.julia/dev/StochasticPrograms/src/methods/generation.jl:92
 [9] instantiate(::StochasticModel{2,Tuple{StageParameters{NamedTuple{(),Tuple{}}},StageParameters{NamedTuple{(),Tuple{}}}}}, ::Array{Scenario{NamedTuple{(:q₁, :q₂, :d₁, :d₂),NTuple{4,Float64}}},1}; instantiation::StochasticPrograms.UnspecifiedInstantiation, optimizer::Type{T} where T, defer::Bool, direct_model::Bool, kw::Base.Iterators.Pairs{Union{},Union{},Tuple{},NamedTuple{(),Tuple{}}}) at /Users/ryanwalker/.julia/dev/StochasticPrograms/src/methods/api.jl:37
 [10] top-level scope at REPL[22]:1

With this change, I get the expected behavior

julia> sp_lshaped = instantiate(simple_model, [ξ₁, ξ₂], optimizer = LShaped.Optimizer)
Stochastic program with:
 * 2 decision variables
 * 2 scenarios of type Scenario
Structure: Vertical
Solver name: L-shaped with disaggregate cuts

I haven't had any issues since going forward with this change locally, so hopefully it really is a simple fix!