From d56a83748398983e3a28ea676657df06481f5773 Mon Sep 17 00:00:00 2001 From: odow Date: Fri, 1 Nov 2024 17:03:50 +1300 Subject: [PATCH 1/5] [Utilities] ignore attributes in UniversalFallback if set to nothing --- src/Utilities/universalfallback.jl | 25 +++++++++++++++++-------- 1 file changed, 17 insertions(+), 8 deletions(-) diff --git a/src/Utilities/universalfallback.jl b/src/Utilities/universalfallback.jl index 0895206931..93a7a091b9 100644 --- a/src/Utilities/universalfallback.jl +++ b/src/Utilities/universalfallback.jl @@ -464,8 +464,10 @@ function MOI.get( listattr::MOI.ListOfOptimizerAttributesSet, ) list = MOI.get(uf.model, listattr) - for attr in keys(uf.optattr) - push!(list, attr) + for (attr, value) in uf.optattr + if value !== nothing + push!(list, attr) + end end return list end @@ -475,8 +477,10 @@ function MOI.get(uf::UniversalFallback, listattr::MOI.ListOfModelAttributesSet) if uf.objective !== nothing push!(list, MOI.ObjectiveFunction{typeof(uf.objective)}()) end - for attr in keys(uf.modattr) - push!(list, attr) + for (attr, value) in uf.modattr + if value !== nothing + push!(list, attr) + end end return list end @@ -486,8 +490,10 @@ function MOI.get( listattr::MOI.ListOfVariableAttributesSet, ) list = MOI.get(uf.model, listattr) - for attr in keys(uf.varattr) - push!(list, attr) + for (attr, value) in uf.varattr + if value !== nothing + push!(list, attr) + end end return list end @@ -498,8 +504,11 @@ function MOI.get( ) where {F,S} list = MOI.get(uf.model, listattr) for (attr, dict) in uf.conattr - if any(k -> k isa MOI.ConstraintIndex{F,S}, keys(dict)) - push!(list, attr) + for (k, v) in dict + if v !== nothing && k isa MOI.ConstraintIndex{F,S} + push!(list, attr) + break + end end end # ConstraintName isn't stored in conattr, but in the .con_to_name dictionary From 3cd8f3eb61f099b29c1ac7a6b2b918421e90fc55 Mon Sep 17 00:00:00 2001 From: Oscar Dowson Date: Sat, 2 Nov 2024 09:22:42 +1300 Subject: [PATCH 2/5] Update src/Utilities/universalfallback.jl MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: BenoƮt Legat --- src/Utilities/universalfallback.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Utilities/universalfallback.jl b/src/Utilities/universalfallback.jl index 93a7a091b9..f1496db015 100644 --- a/src/Utilities/universalfallback.jl +++ b/src/Utilities/universalfallback.jl @@ -491,7 +491,7 @@ function MOI.get( ) list = MOI.get(uf.model, listattr) for (attr, value) in uf.varattr - if value !== nothing + if any(!isnothing, values(value)) push!(list, attr) end end From 57fb0ad0f993472f54260d4b0c0a52d4d6c3ecd2 Mon Sep 17 00:00:00 2001 From: odow Date: Mon, 4 Nov 2024 08:20:48 +1300 Subject: [PATCH 3/5] Add tests --- src/Utilities/universalfallback.jl | 2 +- test/Utilities/universalfallback.jl | 93 +++++++++++++++-------------- 2 files changed, 50 insertions(+), 45 deletions(-) diff --git a/src/Utilities/universalfallback.jl b/src/Utilities/universalfallback.jl index f1496db015..a4f5a4ed27 100644 --- a/src/Utilities/universalfallback.jl +++ b/src/Utilities/universalfallback.jl @@ -505,7 +505,7 @@ function MOI.get( list = MOI.get(uf.model, listattr) for (attr, dict) in uf.conattr for (k, v) in dict - if v !== nothing && k isa MOI.ConstraintIndex{F,S} + if k isa MOI.ConstraintIndex{F,S} && !isnothing(v) push!(list, attr) break end diff --git a/test/Utilities/universalfallback.jl b/test/Utilities/universalfallback.jl index 8777c76687..8fc02108d2 100644 --- a/test/Utilities/universalfallback.jl +++ b/test/Utilities/universalfallback.jl @@ -68,42 +68,52 @@ end ### The tests ### -function test_MOI_Test() - inner = ModelForUniversalFallback{Float64}() - model = MOI.Utilities.UniversalFallback(inner) - MOI.Test.runtests( - model, - MOI.Test.Config(exclude = Any[MOI.optimize!]), - exclude = String[ - # UniversalFallback fails all these tests because it supports - # everything - "test_attribute_", - "test_model_supports_constraint_", - "test_model_copy_to_Unsupported", - # Bugs in UniversalFallback - "test_model_LowerBoundAlreadySet", - "test_model_UpperBoundAlreadySet", - "test_add_parameter", - ], - ) - return -end - -function _test_Optimizer_Model_attributes(uf, model, attr, listattr) +# function test_MOI_Test() +# inner = ModelForUniversalFallback{Float64}() +# model = MOI.Utilities.UniversalFallback(inner) +# MOI.Test.runtests( +# model, +# MOI.Test.Config(exclude = Any[MOI.optimize!]), +# exclude = String[ +# # UniversalFallback fails all these tests because it supports +# # everything +# "test_attribute_", +# "test_model_supports_constraint_", +# "test_model_copy_to_Unsupported", +# # Bugs in UniversalFallback +# "test_model_LowerBoundAlreadySet", +# "test_model_UpperBoundAlreadySet", +# "test_add_parameter", +# ], +# ) +# return +# end + +function _test_Optimizer_Model_attributes( + uf::MOI.Utilities.UniversalFallback, + model::MOI.ModelLike, + attr::Union{MOI.AbstractOptimizerAttribute,MOI.AbstractModelAttribute}, + list::Union{MOI.ListOfOptimizerAttributesSet,MOI.ListOfModelAttributesSet}, +) @test !MOI.supports(model, attr) @test MOI.supports(uf, attr) - @test isempty(MOI.get(uf, listattr)) + @test isempty(MOI.get(uf, list)) MOI.set(uf, attr, 0) @test MOI.get(uf, attr) == 0 - @test MOI.get(uf, listattr) == [attr] + @test MOI.get(uf, list) == [attr] + MOI.set(uf, attr, nothing) + @test isempty(MOI.get(uf, list)) return end function _test_Variable_Constraint_attributes( - uf, - model, - attr, - listattr, + uf::MOI.Utilities.UniversalFallback, + model::MOI.ModelLike, + attr::Union{MOI.AbstractVariableAttribute,MOI.AbstractConstraintAttribute}, + listattr::Union{ + MOI.ListOfVariableAttributesSet, + MOI.ListOfConstraintAttributesSet, + }, I::Type{<:MOI.Index}, addfun, x, @@ -114,6 +124,11 @@ function _test_Variable_Constraint_attributes( @test MOI.supports(uf, attr, I) @test isempty(MOI.get(uf, listattr)) MOI.set(uf, attr, [x, y], [2, 0]) + @test MOI.get(uf, listattr) == [attr] + MOI.set(uf, attr, x, nothing) + MOI.set(uf, attr, y, nothing) + @test isempty(MOI.get(uf, listattr)) + MOI.set(uf, attr, [x, y], [2, 0]) @test MOI.get(uf, attr, z) === nothing @test !MOI.is_empty(uf) @test MOI.get(uf, listattr) == [attr] @@ -235,18 +250,13 @@ function test_supported_constraint_attributes() cx = _add_constraint(uf, x, 0.0) cy = _add_constraint(uf, y, 1.0) cz = _add_constraint(uf, z, 2.0) + F, S = MOI.ScalarAffineFunction{Float64}, MOI.LessThan{Float64} _test_Variable_Constraint_attributes( uf, model, MOI.Test.UnknownConstraintAttribute(), - MOI.ListOfConstraintAttributesSet{ - MOI.ScalarAffineFunction{Float64}, - MOI.LessThan{Float64}, - }(), - MOI.ConstraintIndex{ - MOI.ScalarAffineFunction{Float64}, - MOI.LessThan{Float64}, - }, + MOI.ListOfConstraintAttributesSet{F,S}(), + MOI.ConstraintIndex{F,S}, uf -> _add_constraint(uf, x, 0.0), cx, cy, @@ -282,18 +292,13 @@ function test_unsupported_constraint_attributes() cx = _add_constraint(uf, x, 0.0) cy = _add_constraint(uf, y, 1.0) cz = _add_constraint(uf, z, 2.0) + F, S = MOI.ScalarAffineFunction{Float64}, MOI.EqualTo{Float64} _test_Variable_Constraint_attributes( uf, model, MOI.Test.UnknownConstraintAttribute(), - MOI.ListOfConstraintAttributesSet{ - MOI.ScalarAffineFunction{Float64}, - MOI.EqualTo{Float64}, - }(), - MOI.ConstraintIndex{ - MOI.ScalarAffineFunction{Float64}, - MOI.EqualTo{Float64}, - }, + MOI.ListOfConstraintAttributesSet{F,S}(), + MOI.ConstraintIndex{F,S}, uf -> _add_constraint(uf, x, 0.0), cx, cy, From f388b6ff9bf295817bffe40a1835aba120a2114b Mon Sep 17 00:00:00 2001 From: odow Date: Wed, 6 Nov 2024 09:22:30 +1300 Subject: [PATCH 4/5] Update --- src/Utilities/universalfallback.jl | 36 +++++++++++--------------- test/Utilities/universalfallback.jl | 40 ++++++++++++++--------------- 2 files changed, 35 insertions(+), 41 deletions(-) diff --git a/src/Utilities/universalfallback.jl b/src/Utilities/universalfallback.jl index a4f5a4ed27..009d52d8c6 100644 --- a/src/Utilities/universalfallback.jl +++ b/src/Utilities/universalfallback.jl @@ -464,10 +464,8 @@ function MOI.get( listattr::MOI.ListOfOptimizerAttributesSet, ) list = MOI.get(uf.model, listattr) - for (attr, value) in uf.optattr - if value !== nothing - push!(list, attr) - end + for attr in keys(uf.optattr) + push!(list, attr) end return list end @@ -477,10 +475,8 @@ function MOI.get(uf::UniversalFallback, listattr::MOI.ListOfModelAttributesSet) if uf.objective !== nothing push!(list, MOI.ObjectiveFunction{typeof(uf.objective)}()) end - for (attr, value) in uf.modattr - if value !== nothing - push!(list, attr) - end + for attr in keys(uf.modattr) + push!(list, attr) end return list end @@ -490,10 +486,8 @@ function MOI.get( listattr::MOI.ListOfVariableAttributesSet, ) list = MOI.get(uf.model, listattr) - for (attr, value) in uf.varattr - if any(!isnothing, values(value)) - push!(list, attr) - end + for attr in keys(uf.varattr) + push!(list, attr) end return list end @@ -504,11 +498,8 @@ function MOI.get( ) where {F,S} list = MOI.get(uf.model, listattr) for (attr, dict) in uf.conattr - for (k, v) in dict - if k isa MOI.ConstraintIndex{F,S} && !isnothing(v) - push!(list, attr) - break - end + if any(Base.Fix2(isa, MOI.ConstraintIndex{F,S}), keys(dict)) + push!(list, attr) end end # ConstraintName isn't stored in conattr, but in the .con_to_name dictionary @@ -703,17 +694,20 @@ function MOI.get( ) end +_set_or_delete(dict, key, value) = (dict[key] = value) +_set_or_delete(dict, key, ::Nothing) = delete!(dict, key) + function _set( uf::UniversalFallback, attr::MOI.AbstractOptimizerAttribute, value, ) - uf.optattr[attr] = value + _set_or_delete(uf.optattr, attr, value) return end function _set(uf::UniversalFallback, attr::MOI.AbstractModelAttribute, value) - uf.modattr[attr] = value + _set_or_delete(uf.modattr, attr, value) return end @@ -726,7 +720,7 @@ function _set( if !haskey(uf.varattr, attr) uf.varattr[attr] = Dict{MOI.VariableIndex,Any}() end - uf.varattr[attr][vi] = value + _set_or_delete(uf.varattr[attr], vi, value) return end @@ -739,7 +733,7 @@ function _set( if !haskey(uf.conattr, attr) uf.conattr[attr] = Dict{MOI.ConstraintIndex,Any}() end - uf.conattr[attr][ci] = value + _set_or_delete(uf.conattr[attr], ci, value) return end diff --git a/test/Utilities/universalfallback.jl b/test/Utilities/universalfallback.jl index 8fc02108d2..814bd9e125 100644 --- a/test/Utilities/universalfallback.jl +++ b/test/Utilities/universalfallback.jl @@ -68,26 +68,26 @@ end ### The tests ### -# function test_MOI_Test() -# inner = ModelForUniversalFallback{Float64}() -# model = MOI.Utilities.UniversalFallback(inner) -# MOI.Test.runtests( -# model, -# MOI.Test.Config(exclude = Any[MOI.optimize!]), -# exclude = String[ -# # UniversalFallback fails all these tests because it supports -# # everything -# "test_attribute_", -# "test_model_supports_constraint_", -# "test_model_copy_to_Unsupported", -# # Bugs in UniversalFallback -# "test_model_LowerBoundAlreadySet", -# "test_model_UpperBoundAlreadySet", -# "test_add_parameter", -# ], -# ) -# return -# end +function test_MOI_Test() + inner = ModelForUniversalFallback{Float64}() + model = MOI.Utilities.UniversalFallback(inner) + MOI.Test.runtests( + model, + MOI.Test.Config(exclude = Any[MOI.optimize!]), + exclude = String[ + # UniversalFallback fails all these tests because it supports + # everything + "test_attribute_", + "test_model_supports_constraint_", + "test_model_copy_to_Unsupported", + # Bugs in UniversalFallback + "test_model_LowerBoundAlreadySet", + "test_model_UpperBoundAlreadySet", + "test_add_parameter", + ], + ) + return +end function _test_Optimizer_Model_attributes( uf::MOI.Utilities.UniversalFallback, From 51c8cdf5aacd9243516cd21c0ba91d81730c3d38 Mon Sep 17 00:00:00 2001 From: odow Date: Wed, 6 Nov 2024 10:22:03 +1300 Subject: [PATCH 5/5] Update --- src/Utilities/universalfallback.jl | 6 ++++-- test/Utilities/universalfallback.jl | 1 + 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/Utilities/universalfallback.jl b/src/Utilities/universalfallback.jl index 009d52d8c6..4b69179c0f 100644 --- a/src/Utilities/universalfallback.jl +++ b/src/Utilities/universalfallback.jl @@ -486,8 +486,10 @@ function MOI.get( listattr::MOI.ListOfVariableAttributesSet, ) list = MOI.get(uf.model, listattr) - for attr in keys(uf.varattr) - push!(list, attr) + for (attr, dict) in uf.varattr + if !isempty(dict) + push!(list, attr) + end end return list end diff --git a/test/Utilities/universalfallback.jl b/test/Utilities/universalfallback.jl index 814bd9e125..fae6c8df3f 100644 --- a/test/Utilities/universalfallback.jl +++ b/test/Utilities/universalfallback.jl @@ -103,6 +103,7 @@ function _test_Optimizer_Model_attributes( @test MOI.get(uf, list) == [attr] MOI.set(uf, attr, nothing) @test isempty(MOI.get(uf, list)) + MOI.set(uf, attr, 0) return end