Skip to content
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
3 changes: 2 additions & 1 deletion docs/src/apireference.md
Original file line number Diff line number Diff line change
Expand Up @@ -84,10 +84,11 @@ AbstractOptimizer
optimize!
```

List of attributes optimizers attributes
List of optimizers attributes

```@docs
SolverName
Silent
```

List of attributes useful for optimizers
Expand Down
21 changes: 17 additions & 4 deletions src/Utilities/cachingoptimizer.jl
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,11 @@ function reset_optimizer(m::CachingOptimizer, optimizer::MOI.AbstractOptimizer)
@assert MOI.is_empty(optimizer)
m.optimizer = optimizer
m.state = EMPTY_OPTIMIZER
for attr in MOI.get(m.model_cache, MOI.ListOfOptimizerAttributesSet())
value = MOI.get(m.model_cache, attr)
optimizer_value = attribute_value_map(m.model_to_optimizer_map, value)
MOI.set(m.optimizer, attr, optimizer_value)
end
return
end

Expand Down Expand Up @@ -501,16 +506,24 @@ function MOI.get(m::CachingOptimizer, IdxT::Type{<:MOI.Index}, name::String)
return MOI.get(m.model_cache, IdxT, name)
end

# TODO: MOI.set for MOI.AbstractOptimizerAttribute.
function MOI.set(model::CachingOptimizer, attr::MOI.AbstractOptimizerAttribute,
value)
optimizer_value = attribute_value_map(model.model_to_optimizer_map, value)
if model.optimizer !== nothing
MOI.set(model.optimizer, attr, optimizer_value)
end
MOI.set(model.model_cache, attr, value)
end

function MOI.get(model::CachingOptimizer, attr::MOI.AbstractOptimizerAttribute)
if state(model) == NO_OPTIMIZER
# TODO: Copyable attributes (e.g., `Silent`, `TimeLimit`) should also be
# stored in the cache so we could return the value stored in the cache
# instead. However, for non-copyable attributes( e.g. `SolverName`) the
# error is appropriate.
error("Cannot query $(attr) from caching optimizer because no " *
"optimizer is attached.")
end
# TODO: Copyable attributes (e.g., TimeLimit) could also be stored in the
# cache. When MOI.set is implemented for MOI.AbstractOptimizerAttribute,
# make sure this case is handled correctly.
return attribute_value_map(model.optimizer_to_model_map,
MOI.get(model.optimizer, attr))
end
Expand Down
10 changes: 8 additions & 2 deletions src/Utilities/mockoptimizer.jl
Original file line number Diff line number Diff line change
Expand Up @@ -151,7 +151,9 @@ MOI.set(mock::MockOptimizer, ::MockModelAttribute, value::Integer) = (mock.attri
function MOI.supports(mock::MockOptimizer, attr::MOI.AbstractModelAttribute)
return MOI.supports(mock.inner_model, attr)
end
function MOI.set(mock::MockOptimizer, attr::MOI.AbstractModelAttribute, value)
function MOI.set(mock::MockOptimizer,
attr::Union{MOI.AbstractModelAttribute,
MOI.AbstractOptimizerAttribute}, value)
MOI.set(mock.inner_model, attr, value)
end
MOI.set(mock::MockOptimizer, attr::MOI.ObjectiveFunction, value) = MOI.set(mock.inner_model, attr, xor_variables(value))
Expand All @@ -164,7 +166,11 @@ MOI.set(mock::MockOptimizer, ::MockConstraintAttribute, idx::MOI.ConstraintIndex
MOI.set(mock::MockOptimizer, ::MOI.ConstraintDual, idx::MOI.ConstraintIndex, value) = (mock.condual[xor_index(idx)] = value)
MOI.set(mock::MockOptimizer, ::MOI.ConstraintBasisStatus, idx::MOI.ConstraintIndex, value) = (mock.con_basis[xor_index(idx)] = value)

MOI.get(mock::MockOptimizer, attr::MOI.AbstractModelAttribute) = MOI.get(mock.inner_model, attr)
function MOI.get(mock::MockOptimizer,
attr::Union{MOI.AbstractModelAttribute,
MOI.AbstractOptimizerAttribute})
return MOI.get(mock.inner_model, attr)
end
MOI.get(mock::MockOptimizer, attr::Union{MOI.ListOfVariableIndices,
MOI.ListOfConstraintIndices}) = xor_index.(MOI.get(mock.inner_model, attr))
MOI.get(mock::MockOptimizer, attr::MOI.ObjectiveFunction) = xor_variables(MOI.get(mock.inner_model, attr))
Expand Down
21 changes: 21 additions & 0 deletions src/attributes.jl
Original file line number Diff line number Diff line change
Expand Up @@ -337,6 +337,27 @@ An optimizer attribute for the string identifying the solver/optimizer.
"""
struct SolverName <: AbstractOptimizerAttribute end

"""
Silent

An optimizer attribute for silencing the output of an optimizer. When `set`
to `true`, it takes precedence over any other attribute controlling verbosity
and requires the solver to produce no output. The default value is `false`
which has no effect. In this case the verbosity is controlled by other
attributes.

## Note

Every optimizer should have verbosity on by default. For instance, if a solver
has a solver-specific log level attribute, the MOI implementation should set it
to `1` by default. If the user sets `Silent` to `true`, then the log level
should be set to `0`, even if the user specifically sets a value of log level.
If the value of `Silent` is `false` then the log level set to the solver is the
value given by the user for this solver-specific parameter or `1` if none is
given.
"""
struct Silent <: AbstractOptimizerAttribute end

## Model attributes

"""
Expand Down
33 changes: 31 additions & 2 deletions test/Utilities/cachingoptimizer.jl
Original file line number Diff line number Diff line change
Expand Up @@ -30,16 +30,45 @@
exception = ErrorException(
"Cannot query $(attr) from caching optimizer because no optimizer" *
" is attached.")
@test_throws Exception MOI.get(model, MOI.SolverName())
@test_throws exception MOI.get(model, attr)
attr = MOI.Silent()
exception = ErrorException(
"Cannot query $(attr) from caching optimizer because no optimizer" *
" is attached.")
@test_throws exception MOI.get(model, attr)

attr = MOI.ResultCount()
exception = ErrorException(
"Cannot query $(attr) from caching optimizer because no optimizer" *
" is attached.")
@test_throws Exception MOI.get(model, MOI.ResultCount())
@test_throws exception MOI.get(model, attr)
end
end

@testset "Copyable solver attributes" begin
cache = MOIU.UniversalFallback(ModelForCachingOptimizer{Float64}())
cached = MOIU.CachingOptimizer(cache, MOIU.MANUAL)
MOI.set(cached, MOI.Silent(), true)
mock = MOIU.MockOptimizer(MOIU.UniversalFallback(ModelForMock{Float64}()))
MOIU.reset_optimizer(cached, mock)
@test MOI.get(mock, MOI.Silent())
@test MOI.get(cached, MOI.Silent())
MOI.set(cached, MOI.Silent(), false)
@test !MOI.get(mock, MOI.Silent())
@test !MOI.get(cached, MOI.Silent())
mock = MOIU.MockOptimizer(MOIU.UniversalFallback(ModelForMock{Float64}()))
MOIU.reset_optimizer(cached, mock)
@test !MOI.get(mock, MOI.Silent())
@test !MOI.get(cached, MOI.Silent())
MOI.set(cached, MOI.Silent(), true)
@test MOI.get(mock, MOI.Silent())
@test MOI.get(cached, MOI.Silent())
mock = MOIU.MockOptimizer(MOIU.UniversalFallback(ModelForMock{Float64}()))
MOIU.reset_optimizer(cached, mock)
@test MOI.get(mock, MOI.Silent())
@test MOI.get(cached, MOI.Silent())
end

@testset "CachingOptimizer MANUAL mode" begin
m = MOIU.CachingOptimizer(ModelForCachingOptimizer{Float64}(), MOIU.MANUAL)
@test MOIU.state(m) == MOIU.NO_OPTIMIZER
Expand Down