diff --git a/src/Utilities/cachingoptimizer.jl b/src/Utilities/cachingoptimizer.jl index 4c721ddebc..8cc42c29a8 100644 --- a/src/Utilities/cachingoptimizer.jl +++ b/src/Utilities/cachingoptimizer.jl @@ -113,14 +113,28 @@ mode(m::CachingOptimizer) = m.mode """ reset_optimizer(m::CachingOptimizer, optimizer::MOI.AbstractOptimizer) -Sets or resets `m` to have the given empty optimizer. Can be called -from any state. The `CachingOptimizer` will be in state `EMPTY_OPTIMIZER` after the call. +Sets or resets `m` to have the given empty optimizer `optimizer`. + +Can be called from any state. An assertion error will be thrown if `optimizer` +is not empty. + +The `CachingOptimizer` `m` will be in state `EMPTY_OPTIMIZER` after the call. """ 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()) + # Skip attributes which don't apply to the new optimizer. + if attr isa MOI.RawParameter + # Even if the optimizer claims to `supports` `attr`, the value + # might have a different meaning (e.g., two solvers with `logLevel` + # as a RawParameter). To be on the safe side, just skip all raw + # parameters. + continue + elseif !MOI.is_copyable(attr) || !MOI.supports(m.optimizer, attr) + continue + end value = MOI.get(m.model_cache, attr) optimizer_value = map_indices(m.model_to_optimizer_map, value) MOI.set(m.optimizer, attr, optimizer_value) diff --git a/test/Utilities/cachingoptimizer.jl b/test/Utilities/cachingoptimizer.jl index 9c614dc475..977486f61e 100644 --- a/test/Utilities/cachingoptimizer.jl +++ b/test/Utilities/cachingoptimizer.jl @@ -652,3 +652,31 @@ end MOIU.reset_optimizer(model, optimizer) constrained_variables_test(model) end + +struct Issue1220 <: MOI.AbstractOptimizer + optimizer_attributes::Dict{Any,Any} + Issue1220() = new(Dict{Any,Any}()) +end +MOI.is_empty(model::Issue1220) = isempty(model.optimizer_attributes) +function MOI.get(model::Issue1220, ::MOI.ListOfOptimizerAttributesSet) + return collect(keys(model.optimizer_attributes)) +end +MOI.supports(::Issue1220, ::MOI.AbstractOptimizerAttribute) = true +MOI.supports(::Issue1220, ::MOI.NumberOfThreads) = false +function MOI.get(model::Issue1220, attr::MOI.AbstractOptimizerAttribute) + return model.optimizer_attributes[attr] +end +function MOI.set(model::Issue1220, attr::MOI.AbstractOptimizerAttribute, value) + model.optimizer_attributes[attr] = value + return value +end +@testset "Issue1220_dont_pass_raw_parameter" begin + model = MOIU.CachingOptimizer(Issue1220(), Issue1220()) + MOI.set(model, MOI.Silent(), true) + MOI.set(model, MOI.RawParameter("foo"), "bar") + MOI.set(model, MOI.NumberOfThreads(), 1) + MOIU.reset_optimizer(model, Issue1220()) + @test MOI.get(model, MOI.Silent()) == true + @test_throws KeyError MOI.get(model, MOI.RawParameter("foo")) + @test_throws KeyError MOI.get(model, MOI.NumberOfThreads()) +end