Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Write MOF files by default #284

Merged
merged 2 commits into from
Dec 17, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Project.toml
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ HTTP = "0.8.1"
JSON = "0.21"
JuMP = "~0.20"
JuliaFormatter = "0.1.37"
MathOptFormat = "0.2"
MathOptFormat = "0.4"
RecipesBase = "0.7"
Reexport = "0.2"
TimerOutputs = "0.5"
Expand Down
10 changes: 2 additions & 8 deletions docs/src/guides/debug_a_model.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,13 +53,8 @@ Now to write out the problem to a file. We'll get a few warnings because some
variables and constraints don't have names. They don't matter, so ignore them.

```jldoctest tutorial_eight; filter=r"MathOptFormat\ .+?MathOptFormat\.jl"
julia> SDDP.write_subproblem_to_file(model[1], "subproblem", format=:lp)
julia> SDDP.write_subproblem_to_file(model[1], "subproblem.lp")

```

We can check the file by reading it back in again.

```jldoctest tutorial_eight
julia> read("subproblem.lp") |> String |> print
minimize
obj: 1.1 x_out + 1 x2
Expand All @@ -80,8 +75,7 @@ are not in the original problem formulation.
```jldoctest tutorial_eight; filter=r"MathOptFormat\ .+?MathOptFormat\.jl"
julia> SDDP.parameterize(model[1], 3.3)

julia> SDDP.write_subproblem_to_file(model[1], "subproblem", format=:lp)

julia> SDDP.write_subproblem_to_file(model[1], "subproblem.lp")

julia> read("subproblem.lp") |> String |> print
minimize
Expand Down
53 changes: 17 additions & 36 deletions src/algorithm.jl
Original file line number Diff line number Diff line change
Expand Up @@ -209,46 +209,23 @@ stage_objective_value(stage_objective::Real) = stage_objective
stage_objective_value(stage_objective) = JuMP.value(stage_objective)

"""
write_subproblem_to_file(node::Node, filename::String; format=:both)
write_subproblem_to_file(node::Node, filename::String; throw_error::Bool = false)

Write the subproblem contained in `node` to the file `filename`.

`format` should be one of `:mps`, `:lp`, or `:both`.
"""
function write_subproblem_to_file(
node::Node,
filename::String;
format::Symbol = :both,
throw_error::Bool = false,
)
if format ∉ (:mps, :lp, :both)
error("Invalid `format=$(format)`. Must be `:mps`, `:lp`, or `:both`.")
end
if format == :mps || format == :both
mps = MathOptFormat.MPS.Model()
MOI.copy_to(mps, JuMP.backend(node.subproblem))
MOI.write_to_file(mps, filename * ".mps")
end
if format == :lp || format == :both
lp = MathOptFormat.LP.Model()
MOI.copy_to(lp, JuMP.backend(node.subproblem))
MOI.write_to_file(lp, filename * ".lp")
end
function write_subproblem_to_file(node::Node, filename::String; throw_error::Bool = false)
model = MathOptFormat.Model(filename = filename)
MOI.copy_to(model, JuMP.backend(node.subproblem))
MOI.write_to_file(model, filename)
if throw_error
error(
"Unable to retrieve dual solution from ",
node.index,
".",
"\n Termination status: ",
JuMP.termination_status(node.subproblem),
"\n Primal status: ",
JuMP.primal_status(node.subproblem),
"\n Dual status: ",
JuMP.dual_status(node.subproblem),
".\n An MPS file was written to `subproblem.mps` and an LP file ",
"written to `subproblem.lp`. See ",
"https://odow.github.io/SDDP.jl/latest/tutorial/06_warnings/#Numerical-stability-1",
" for more information.",
"Unable to retrieve solution from $(node.index).\n",
" Termination status: $(JuMP.termination_status(node.subproblem))\n",
" Primal status: $(JuMP.primal_status(node.subproblem))\n",
" Dual status: $(JuMP.dual_status(node.subproblem)).\n",
"A MathOptFormat file was written to `$(filename)`.\n",
"See https://odow.github.io/SDDP.jl/latest/tutorial/06_warnings/#Numerical-stability-1",
"\nfor more information.",
)
end
end
Expand Down Expand Up @@ -295,7 +272,11 @@ function solve_subproblem(

# Test for primal feasibility.
if JuMP.primal_status(node.subproblem) != JuMP.MOI.FEASIBLE_POINT
write_subproblem_to_file(node, "subproblem", throw_error = true)
write_subproblem_to_file(
node,
"subproblem_$(node.index).mof.json",
throw_error = true,
)
end
# If require_duals = true, check for dual feasibility and return a dict with
# the dual on the fixed constraint associated with each incoming state
Expand Down
13 changes: 8 additions & 5 deletions src/modeling_aids.jl
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.

function find_min(x::Vector{T}, y::T) where {T <: Real}
function find_min(x::Vector{T}, y::T) where {T<:Real}
best_i = 0
best_z = Inf
for i = 1:length(x)
Expand All @@ -40,7 +40,7 @@ end
function lattice_approximation(f::Function, states::Vector{Int}, scenarios::Int)
path = f()::Vector{Float64}
support = [fill(path[t], states[t]) for t = 1:length(states)]
probability = [zeros(states[t - 1], states[t]) for t = 2:length(states)]
probability = [zeros(states[t-1], states[t]) for t = 2:length(states)]
prepend!(probability, Ref(zeros(1, states[1])))
distance = 0.0
for n = 1:scenarios
Expand All @@ -55,7 +55,8 @@ function lattice_approximation(f::Function, states::Vector{Int}, scenarios::Int)
min_dist, best_idx = find_min(support[t], path[t])
dist += min_dist^2
probability[t][last_index, best_idx] += 1.0
support[t][best_idx] -= min_dist * (support[t][best_idx] - path[t]) / (3000 + n)^0.75
support[t][best_idx] -=
min_dist * (support[t][best_idx] - path[t]) / (3000 + n)^0.75
last_index = best_idx
end
distance = (distance * (n - 1) + dist) / n
Expand Down Expand Up @@ -114,7 +115,9 @@ nodes between stages. Alternatively, `budget` can be a `Vector{Int}`, which deta
number of Markov state to have in each stage.
"""
function MarkovianGraph(
simulator::Function; budget::Union{Int, Vector{Int}}, scenarios::Int = 1000
simulator::Function;
budget::Union{Int,Vector{Int}},
scenarios::Int = 1000,
)
scenarios = max(scenarios, 10)
states = allocate_support_budget(simulator, budget, scenarios)
Expand All @@ -127,7 +130,7 @@ function MarkovianGraph(
for t = 2:length(support)
for (j, sj) in enumerate(support[t])
add_node(g, (t, sj))
for (i, si) in enumerate(support[t - 1])
for (i, si) in enumerate(support[t-1])
add_edge(g, (t - 1, si) => (t, sj), probability[t][i, j])
end
end
Expand Down
17 changes: 12 additions & 5 deletions test/algorithm.jl
Original file line number Diff line number Diff line change
Expand Up @@ -161,11 +161,18 @@ end
@constraint(node, x.out <= -1)
@stageobjective(node, x.out)
end
@test_throws Exception SDDP.train(model; iteration_limit = 1, print_level = 0)
@test isfile("subproblem.mps")
rm("subproblem.mps")
@test isfile("subproblem.lp")
rm("subproblem.lp")
ex = ErrorException("""
Unable to retrieve solution from 1.
Termination status: INFEASIBLE
Primal status: NO_SOLUTION
Dual status: INFEASIBILITY_CERTIFICATE.
A MathOptFormat file was written to `subproblem_1.mof.json`.
See https://odow.github.io/SDDP.jl/latest/tutorial/06_warnings/#Numerical-stability-1
for more information.""")

@test_throws ex SDDP.train(model; iteration_limit = 1, print_level = 0)
@test isfile("subproblem_1.mof.json")
rm("subproblem_1.mof.json")
end

@testset "refine_at_similar_nodes" begin
Expand Down
4 changes: 1 addition & 3 deletions test/modeling_aids.jl
Original file line number Diff line number Diff line change
Expand Up @@ -34,9 +34,7 @@ end
end

@testset "lattice_approximation" begin
support, probability = SDDP.lattice_approximation(
() -> rand(5), [1, 2, 3, 4, 5], 100
)
support, probability = SDDP.lattice_approximation(() -> rand(5), [1, 2, 3, 4, 5], 100)
for (t, s) in enumerate(support)
@test length(s) == t
@test all(x -> 0 <= x <= 1, s)
Expand Down