Skip to content

Commit

Permalink
Document set_optimizer and remove optimizer argument from optimize!
Browse files Browse the repository at this point in the history
Closes #2073
Closes #2074
  • Loading branch information
mlubin committed Oct 19, 2019
1 parent 0ee8dba commit 51e4c6c
Show file tree
Hide file tree
Showing 7 changed files with 67 additions and 79 deletions.
6 changes: 4 additions & 2 deletions docs/src/solvers.md
Original file line number Diff line number Diff line change
Expand Up @@ -67,9 +67,11 @@ function:
with_optimizer
```

The factory can be provided either at model construction time or at
[`optimize!`](@ref) time:
The factory can be provided either at model construction time by calling
[`set_optimizer`](@ref). An optimizer must be set before a call to
[`optimize!`](@ref).
```@docs
set_optimizer
NoOptimizer
JuMP.optimize!
```
Expand Down
17 changes: 7 additions & 10 deletions src/JuMP.jl
Original file line number Diff line number Diff line change
Expand Up @@ -149,16 +149,12 @@ mutable struct Model <: AbstractModel
end

"""
Model(; caching_mode::MOIU.CachingOptimizerMode=MOIU.AUTOMATIC,
bridge_constraints::Bool=true)
Model(; caching_mode::MOIU.CachingOptimizerMode=MOIU.AUTOMATIC)
Return a new JuMP model without any optimizer; the model is stored the model in
a cache. The mode of the `CachingOptimizer` storing this cache is
`caching_mode`. The optimizer can be set later in the [`optimize!`](@ref)
call. If `bridge_constraints` is true, constraints that are not supported by the
optimizer are automatically bridged to equivalent supported constraints when
an appropriate transformation is defined in the `MathOptInterface.Bridges`
module or is defined in another module and is explicitely added.
`caching_mode`. Use [`set_optimizer`](@ref) to set the optimizer before
calling [`optimize!`](@ref).
"""
function Model(; caching_mode::MOIU.CachingOptimizerMode=MOIU.AUTOMATIC,
solver=nothing)
Expand All @@ -180,7 +176,8 @@ end
Return a new JuMP model using the optimizer factory `optimizer_factory` to
create the optimizer. The optimizer factory can be created by the
[`with_optimizer`](@ref) function.
[`with_optimizer`](@ref) function. See [`set_optimizer`](@ref) for the
description of the `bridge_constraints` argument.
## Examples
Expand Down Expand Up @@ -613,8 +610,8 @@ struct OptimizeNotCalled <: Exception end
"""
struct NoOptimizer <: Exception end
No optimizer is set. The optimizer can be provided at the [`Model`](@ref)
constructor or at the [`optimize!`](@ref) call with [`with_optimizer`](@ref).
No optimizer is set. The optimizer can be provided to the [`Model`](@ref)
constructor or by calling [`set_optimizer`](@ref).
"""
struct NoOptimizer <: Exception end

Expand Down
60 changes: 26 additions & 34 deletions src/optimizer_interface.jl
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,24 @@ function MOIU.attach_optimizer(model::Model)
MOIU.attach_optimizer(backend(model))
end

"""
set_optimizer(model::Model, optimizer_factory::OptimizerFactory;
bridge_constraints::Bool=true)
Creates a new `MathOptInterface.AbstractOptimizer` instance using the optimizer
factory and sets it as the optimizer of `model`.
If `bridge_constraints` is true, constraints that are not supported by the
optimizer are automatically bridged to equivalent supported constraints when
an appropriate transformation is defined in the `MathOptInterface.Bridges`
module or is defined in another module and is explicitly added.
## Examples
```julia
model = Model()
set_optimizer(model, with_optimizer(GLPK.Optimizer))
```
"""
function set_optimizer(model::Model, optimizer_factory::OptimizerFactory;
bridge_constraints::Bool=true)
error_if_direct_mode(model, :set_optimizer)
Expand Down Expand Up @@ -68,40 +86,20 @@ function solve(::Model)
end

"""
optimize!(model::Model,
optimizer_factory::Union{Nothing, OptimizerFactory}=nothing;
bridge_constraints::Bool=true,
optimize!(model::Model;
ignore_optimize_hook=(model.optimize_hook === nothing),
kwargs...)
Optimize the model. If `optimizer_factory` is not `nothing`, it first sets the
optimizer to a new one created using the optimizer factory. The factory can be
created using the [`with_optimizer`](@ref) function. If `optimizer_factory` is
`nothing` and no optimizer was set to `model` before calling this function, a
[`NoOptimizer`](@ref) error is thrown.
Optimize the model. If an optimizer has not been set yet (see
[`set_optimizer`](@ref)), a [`NoOptimizer`](@ref) error is thrown.
Keyword arguments `kwargs` are passed to the `optimize_hook`. An error is
thrown if `optimize_hook` is `nothing` and keyword arguments are provided.
## Examples
The optimizer factory can either be given in the [`Model`](@ref) constructor
as follows:
```julia
model = Model(with_optimizer(GLPK.Optimizer))
# ...fill model with variables, constraints and objectives...
# Solve the model with GLPK
optimize!(model)
```
or in the `optimize!` call as follows:
```julia
model = Model()
# ...fill model with variables, constraints and objectives...
# Solve the model with GLPK
optimize!(model, with_optimizer(GLPK.Optimizer))
```
"""
function optimize!(model::Model,
# TODO: Remove the optimizer_factory and bridge_constraints
# arguments when the deprecation error below is removed.
optimizer_factory::Union{Nothing, OptimizerFactory}=nothing;
bridge_constraints::Bool=true,
ignore_optimize_hook=(model.optimize_hook === nothing),
Expand All @@ -114,15 +112,9 @@ function optimize!(model::Model,
end

if optimizer_factory !== nothing
if mode(model) == DIRECT
error("An optimizer factory cannot be provided at the `optimize` call in DIRECT mode.")
end
if MOIU.state(backend(model)) != MOIU.NO_OPTIMIZER
error("An optimizer factory cannot both be provided in the `Model` constructor and at the `optimize` call.")
end
set_optimizer(model, optimizer_factory,
bridge_constraints=bridge_constraints)
MOIU.attach_optimizer(model)
# This argument was deprecated in JuMP 0.21.
error("The optimizer factory argument is no longer accepted by " *
"`optimize!`. Call `set_optimizer` before `optimize!`.")
end

# If the user or an extension has provided an optimize hook, call
Expand Down
9 changes: 5 additions & 4 deletions test/constraint.jl
Original file line number Diff line number Diff line change
Expand Up @@ -528,10 +528,11 @@ end
function test_shadow_price(model_string, constraint_dual, constraint_shadow)
model = JuMP.Model()
MOIU.loadfromstring!(JuMP.backend(model), model_string)
JuMP.optimize!(model, with_optimizer(MOIU.MockOptimizer,
MOIU.Model{Float64}(),
eval_objective_value=false,
eval_variable_constraint_dual=false))
set_optimizer(model, with_optimizer(MOIU.MockOptimizer,
MOIU.Model{Float64}(),
eval_objective_value=false,
eval_variable_constraint_dual=false))
JuMP.optimize!(model)
mock_optimizer = JuMP.backend(model).optimizer.model
MOI.set(mock_optimizer, MOI.TerminationStatus(), MOI.OPTIMAL)
MOI.set(mock_optimizer, MOI.DualStatus(), MOI.FEASIBLE_POINT)
Expand Down
25 changes: 8 additions & 17 deletions test/generate_and_solve.jl
Original file line number Diff line number Diff line change
Expand Up @@ -42,9 +42,10 @@ using JuMP
MOIU.loadfromstring!(model, modelstring)
MOIU.test_models_equal(JuMP.backend(m).model_cache, model, ["x","y"], ["c", "xub", "ylb"])

JuMP.optimize!(m, with_optimizer(MOIU.MockOptimizer,
MOIU.Model{Float64}(),
eval_objective_value=false))
set_optimizer(m, with_optimizer(MOIU.MockOptimizer,
MOIU.Model{Float64}(),
eval_objective_value=false))
JuMP.optimize!(m)

mockoptimizer = JuMP.backend(m).optimizer.model
MOI.set(mockoptimizer, MOI.TerminationStatus(), MOI.OPTIMAL)
Expand Down Expand Up @@ -199,9 +200,10 @@ using JuMP
MOIU.loadfromstring!(model, modelstring)
MOIU.test_models_equal(JuMP.backend(m).model_cache, model, ["x","y"], ["c1", "c2", "c3"])

JuMP.optimize!(m, with_optimizer(MOIU.MockOptimizer,
MOIU.Model{Float64}(),
eval_objective_value=false))
set_optimizer(m, with_optimizer(MOIU.MockOptimizer,
MOIU.Model{Float64}(),
eval_objective_value=false))
JuMP.optimize!(m)

mockoptimizer = JuMP.backend(m).optimizer.model
MOI.set(mockoptimizer, MOI.TerminationStatus(), MOI.OPTIMAL)
Expand Down Expand Up @@ -370,17 +372,6 @@ using JuMP

end

@testset "Provide factory in `optimize` in Direct mode" begin
mockoptimizer = MOIU.MockOptimizer(MOIU.Model{Float64}())
model = JuMP.direct_model(mockoptimizer)
@test_throws ErrorException JuMP.optimize!(model, with_optimizer(MOIU.MockOptimizer, MOIU.Model{Float64}()))
end

@testset "Provide factory both in `Model` and `optimize`" begin
model = Model(with_optimizer(MOIU.MockOptimizer, MOIU.Model{Float64}()))
@test_throws ErrorException JuMP.optimize!(model, with_optimizer(MOIU.MockOptimizer, MOIU.Model{Float64}()))
end

@testset "Solver doesn't support nonlinear constraints" begin
model = Model(with_optimizer(MOIU.MockOptimizer,
MOIU.Model{Float64}()))
Expand Down
14 changes: 8 additions & 6 deletions test/lp_sensitivity.jl
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,10 @@
function test_lp_rhs_perturbation_range(model_string, primal_solution, basis_status, feasibility_ranges)
model = JuMP.Model()
MOIU.loadfromstring!(JuMP.backend(model), model_string)
JuMP.optimize!(model, with_optimizer(MOIU.MockOptimizer,
MOIU.Model{Float64}(),
eval_variable_constraint_dual=false))
set_optimizer(model, with_optimizer(MOIU.MockOptimizer,
MOIU.Model{Float64}(),
eval_variable_constraint_dual=false))
JuMP.optimize!(model)
mock_optimizer = JuMP.backend(model).optimizer.model
MOI.set(mock_optimizer, MOI.TerminationStatus(), MOI.OPTIMAL)

Expand Down Expand Up @@ -106,9 +107,10 @@ end
function test_lp_objective_perturbation_range(model_string, dual_solution, basis_status, optimality_ranges)
model = JuMP.Model()
MOIU.loadfromstring!(JuMP.backend(model), model_string)
JuMP.optimize!(model, with_optimizer(MOIU.MockOptimizer,
MOIU.Model{Float64}(),
eval_variable_constraint_dual=true))
set_optimizer(model, with_optimizer(MOIU.MockOptimizer,
MOIU.Model{Float64}(),
eval_variable_constraint_dual=true))
JuMP.optimize!(model)
mock_optimizer = JuMP.backend(model).optimizer.model
MOI.set(mock_optimizer, MOI.TerminationStatus(), MOI.OPTIMAL)
MOI.set(mock_optimizer, MOI.DualStatus(), MOI.FEASIBLE_POINT)
Expand Down
15 changes: 9 additions & 6 deletions test/model.jl
Original file line number Diff line number Diff line change
Expand Up @@ -240,12 +240,13 @@ function test_model()
@test 1.0 == @inferred JuMP.value(c)
@test 2.0 == @inferred JuMP.dual(c)
end
@testset "with_optimizer at optimize!" begin
@testset "with_optimizer with set_optimizer" begin
model = Model()
@variable(model, x)
c = @constraint(model, x in Nonnegative())
JuMP.add_bridge(model, NonnegativeBridge)
JuMP.optimize!(model, factory)
set_optimizer(model, factory)
JuMP.optimize!(model)
@test 1.0 == @inferred JuMP.value(x)
@test 1.0 == @inferred JuMP.value(c)
@test 2.0 == @inferred JuMP.dual(c)
Expand All @@ -267,13 +268,14 @@ function test_model()
@test 1.0 == @inferred JuMP.value(c)
@test 2.0 == @inferred JuMP.dual(c)
end
@testset "with_optimizer at optimize!" begin
@testset "with_optimizer with set_optimizer" begin
err = MOI.UnsupportedConstraint{MOI.SingleVariable,
Nonnegative}()
model = Model()
@variable(model, x)
c = @constraint(model, x in Nonnegative())
@test_throws err JuMP.optimize!(model, factory)
set_optimizer(model, factory)
@test_throws err JuMP.optimize!(model)
JuMP.add_bridge(model, NonnegativeBridge)
JuMP.optimize!(model)
@test 1.0 == @inferred JuMP.value(x)
Expand All @@ -293,13 +295,14 @@ function test_model()
@test 1.0 == @inferred JuMP.value(c)
@test 2.0 == @inferred JuMP.dual(c)
end
@testset "with_optimizer at optimize!" begin
@testset "with_optimizer with set_optimizer" begin
model = Model()
@variable(model, x)
constraint = ScalarConstraint(x, Nonnegative())
bc = BridgeableConstraint(constraint, NonnegativeBridge)
c = add_constraint(model, bc)
JuMP.optimize!(model, factory)
set_optimizer(model, factory)
JuMP.optimize!(model)
@test 1.0 == @inferred JuMP.value(x)
@test 1.0 == @inferred JuMP.value(c)
@test 2.0 == @inferred JuMP.dual(c)
Expand Down

0 comments on commit 51e4c6c

Please sign in to comment.