From 183512b6620f3af50f3ad04f2be3fc652d5416a4 Mon Sep 17 00:00:00 2001 From: odow Date: Thu, 9 Jun 2022 12:50:14 +1200 Subject: [PATCH 1/5] Add GetAttributeNotAllowed error --- src/attributes.jl | 32 ++++++++++++++++++++++++++++---- test/attributes.jl | 46 ++++++++++++++++++++++++++++++++-------------- test/errors.jl | 15 +++++++++++++++ 3 files changed, 75 insertions(+), 18 deletions(-) diff --git a/src/attributes.jl b/src/attributes.jl index 16d7a3503f..24d6bed6df 100644 --- a/src/attributes.jl +++ b/src/attributes.jl @@ -100,6 +100,26 @@ SetAttributeNotAllowed(attr::AnyAttribute) = SetAttributeNotAllowed(attr, "") operation_name(err::SetAttributeNotAllowed) = "Setting attribute $(err.attr)" message(err::SetAttributeNotAllowed) = err.message +""" + struct GetAttributeNotAllowed{AttrType} <: NotAllowedError + attr::AttrType + message::String + end + +An error indicating that the attribute `attr` cannot be got for some reason (see +the error string). +""" +struct GetAttributeNotAllowed{AttrType<:AnyAttribute} <: NotAllowedError + attr::AttrType + message::String +end + +GetAttributeNotAllowed(attr::AnyAttribute) = GetAttributeNotAllowed(attr, "") + +operation_name(err::GetAttributeNotAllowed) = "Getting attribute $(err.attr)" + +message(err::GetAttributeNotAllowed) = err.message + """ AbstractSubmittable @@ -341,7 +361,8 @@ function get_fallback( attr::Union{AbstractModelAttribute,AbstractOptimizerAttribute}, ) return throw( - ArgumentError( + GetAttributeNotAllowed( + attr, "$(typeof(model)) does not support getting the attribute $(attr).", ), ) @@ -353,7 +374,8 @@ function get_fallback( ::VariableIndex, ) return throw( - ArgumentError( + GetAttributeNotAllowed( + attr, "$(typeof(model)) does not support getting the attribute $(attr).", ), ) @@ -365,7 +387,8 @@ function get_fallback( ::ConstraintIndex, ) return throw( - ArgumentError( + GetAttributeNotAllowed( + attr, "$(typeof(model)) does not support getting the attribute $(attr).", ), ) @@ -373,7 +396,8 @@ end function get_fallback(::ModelLike, attr::AnyAttribute, args...) return throw( - ArgumentError( + GetAttributeNotAllowed( + attr, "Unable to get attribute $(attr): invalid arguments $(args).", ), ) diff --git a/test/attributes.jl b/test/attributes.jl index 8ae448e096..f14fcc4d58 100644 --- a/test/attributes.jl +++ b/test/attributes.jl @@ -150,30 +150,48 @@ function test_get_fallback() model = DummyModelWithAdd() x = MOI.add_variable(model) c = MOI.add_constraint(model, x, MOI.EqualTo(0.0)) - err = ArgumentError( - "$(typeof(model)) does not support getting the attribute " * - "$(MOI.SolveTimeSec()).", + @test_throws( + MOI.GetAttributeNotAllowed( + MOI.SolveTimeSec(), + "$(typeof(model)) does not support getting the attribute " * + "$(MOI.SolveTimeSec()).", + ), + MOI.get(model, MOI.SolveTimeSec()), ) - @test_throws(err, MOI.get(model, MOI.SolveTimeSec())) output = Ref{Cdouble}() - @test_throws(err, MOI.get!(output, model, MOI.SolveTimeSec())) - errv = ArgumentError( - "$(typeof(model)) does not support getting the attribute " * - "$(MOI.VariablePrimal()).", + @test_throws( + MOI.GetAttributeNotAllowed( + MOI.SolveTimeSec(), + "$(typeof(model)) does not support getting the attribute " * + "$(MOI.SolveTimeSec()).", + ), + MOI.get!(output, model, MOI.SolveTimeSec()), ) - @test_throws(errv, MOI.get(model, MOI.VariablePrimal(), x)) - errc = ArgumentError( - "$(typeof(model)) does not support getting the attribute " * - "$(MOI.ConstraintPrimal()).", + @test_throws( + MOI.GetAttributeNotAllowed( + MOI.VariablePrimal(), + "$(typeof(model)) does not support getting the attribute " * + "$(MOI.VariablePrimal()).", + ), + MOI.get(model, MOI.VariablePrimal(), x), + ) + @test_throws( + MOI.GetAttributeNotAllowed( + MOI.ConstraintPrimal(), + "$(typeof(model)) does not support getting the attribute " * + "$(MOI.ConstraintPrimal()).", + ), + MOI.get(model, MOI.ConstraintPrimal(), c), ) - @test_throws(errc, MOI.get(model, MOI.ConstraintPrimal(), c)) @test_throws( - ArgumentError( + MOI.GetAttributeNotAllowed( + MOI.VariablePrimal(), "Unable to get attribute $(MOI.VariablePrimal()): invalid " * "arguments $((c,)).", ), MOI.get(model, MOI.VariablePrimal(), c), ) + return end function test_ConstraintBasisStatus_fallback() diff --git a/test/errors.jl b/test/errors.jl index 92b8ba0b00..b412056476 100644 --- a/test/errors.jl +++ b/test/errors.jl @@ -334,6 +334,21 @@ function test_compute_conflict_fallback() return end +function test_get_fallback_error() + model = MOI.Utilities.Model{Float64}() + @test_throws( + MOI.GetAttributeNotAllowed, + MOI.get(model, MOI.SolveTimeSec()), + ) + err = MOI.GetAttributeNotAllowed(MOI.SolveTimeSec(), "") + @test sprint(showerror, err) == + "$(typeof(err)): Getting attribute $(MOI.SolveTimeSec()) cannot be " * + "performed. You may want to use a `CachingOptimizer` in " * + "`AUTOMATIC` mode or you may need to call `reset_optimizer` before " * + "doing this operation if the `CachingOptimizer` is in `MANUAL` mode." + return +end + function runtests() for name in names(@__MODULE__; all = true) if startswith("$name", "test_") From 1a441f5b66c63e00757bc039c3bf301c5910e52c Mon Sep 17 00:00:00 2001 From: odow Date: Thu, 9 Jun 2022 12:59:10 +1200 Subject: [PATCH 2/5] Add test case --- test/attributes.jl | 51 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 51 insertions(+) diff --git a/test/attributes.jl b/test/attributes.jl index f14fcc4d58..294b5817a1 100644 --- a/test/attributes.jl +++ b/test/attributes.jl @@ -233,6 +233,57 @@ function test_attribute_value_type() Float64 end +MOI.Utilities.@model( + _Model1777, + (), + (MOI.LessThan,), + (MOI.Nonnegatives,), + (), + (), + (MOI.ScalarAffineFunction,), + (MOI.VectorOfVariables,), + () +) + +function MOI.supports_constraint( + ::_Model1777, + ::Type{MOI.VectorOfVariables}, + ::Type{MOI.Reals}, +) + return false +end + +function MOI.supports_add_constrained_variables( + ::_Model1777, + ::Type{MOI.Nonnegatives}, +) + return true +end + +MOI.supports_add_constrained_variables(::_Model1777, ::Type{MOI.Reals}) = false + +function MOI.get( + model::_Model1777, + attr::MOI.ConstraintFunction, + ci::MOI.ConstraintIndex, +) + return MOI.get_fallback(model, attr, ci) +end + +function test_issue_1777() + model = MOI.Utilities.CachingOptimizer( + MOI.Utilities.UniversalFallback(MOI.Utilities.Model{Float64}()), + MOI.Bridges.full_bridge_optimizer(_Model1777{Float64}(), Float64), + ) + x = MOI.add_variable(model) + c = MOI.add_constraint(model, 1.0 * x, MOI.LessThan(1.0)) + MOI.Utilities.attach_optimizer(model) + MOI.set(model, MOI.ConstraintSet(), c, MOI.LessThan(2.0)) + @test MOI.get(model, MOI.ConstraintSet(), c) == MOI.LessThan(2.0) + @test MOI.Utilities.state(model) == MOI.Utilities.EMPTY_OPTIMIZER + return +end + function runtests() for name in names(@__MODULE__; all = true) if startswith("$name", "test_") From 2f11686adea28a39030b9fb2c2a096c46c732f2c Mon Sep 17 00:00:00 2001 From: odow Date: Thu, 9 Jun 2022 13:47:22 +1200 Subject: [PATCH 3/5] Fix CachingOptimizer fallback --- src/Utilities/cachingoptimizer.jl | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/Utilities/cachingoptimizer.jl b/src/Utilities/cachingoptimizer.jl index 92a60c976a..2598a829bb 100644 --- a/src/Utilities/cachingoptimizer.jl +++ b/src/Utilities/cachingoptimizer.jl @@ -939,11 +939,11 @@ function MOI.get( model.model_to_optimizer_map[index], ) catch err - if err isa ArgumentError # Thrown if .optimizer doesn't support attr - return get_fallback(model, attr, index) - else + # Thrown if .optimizer doesn't support attr + if !(err isa MOI.GetAttributeNotAllowed) rethrow(err) end + return get_fallback(model, attr, index) end end @@ -965,11 +965,11 @@ function MOI.get( [model.model_to_optimizer_map[i] for i in indices], ) catch err - if err isa ArgumentError # Thrown if .optimizer doesn't support attr - return [get_fallback(model, attr, i) for i in indices] - else + # Thrown if .optimizer doesn't support attr + if !(err isa MOI.GetAttributeNotAllowed) rethrow(err) end + return [get_fallback(model, attr, i) for i in indices] end end From f1da8fb71c29bef73291926c4ad6c480255faefe Mon Sep 17 00:00:00 2001 From: Oscar Dowson Date: Thu, 9 Jun 2022 14:50:31 +1200 Subject: [PATCH 4/5] Update attributes.jl --- src/attributes.jl | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/attributes.jl b/src/attributes.jl index 24d6bed6df..8d4b2e2b87 100644 --- a/src/attributes.jl +++ b/src/attributes.jl @@ -112,9 +112,11 @@ the error string). struct GetAttributeNotAllowed{AttrType<:AnyAttribute} <: NotAllowedError attr::AttrType message::String -end -GetAttributeNotAllowed(attr::AnyAttribute) = GetAttributeNotAllowed(attr, "") + function GetAttributeNotAllowed(attr::AnyAttribute, message::String = "") + return new(attr, message) + end +end operation_name(err::GetAttributeNotAllowed) = "Getting attribute $(err.attr)" From b98269e717b9481e466e7af04fbd157ec501de8f Mon Sep 17 00:00:00 2001 From: Oscar Dowson Date: Thu, 9 Jun 2022 14:57:20 +1200 Subject: [PATCH 5/5] Update src/attributes.jl --- src/attributes.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/attributes.jl b/src/attributes.jl index 8d4b2e2b87..b532778fee 100644 --- a/src/attributes.jl +++ b/src/attributes.jl @@ -114,7 +114,7 @@ struct GetAttributeNotAllowed{AttrType<:AnyAttribute} <: NotAllowedError message::String function GetAttributeNotAllowed(attr::AnyAttribute, message::String = "") - return new(attr, message) + return new{typeof(attr)}(attr, message) end end