From e728a6ca0fa5b579408f7be3287944717bbfcf1f Mon Sep 17 00:00:00 2001 From: odow Date: Wed, 24 Jan 2024 16:47:31 +1300 Subject: [PATCH 1/3] [Utilities] throw correct error if get_fallback fails --- src/Utilities/results.jl | 82 +++++++++++++++++++++++----------------- 1 file changed, 48 insertions(+), 34 deletions(-) diff --git a/src/Utilities/results.jl b/src/Utilities/results.jl index a53722935c..b7a22aa4cd 100644 --- a/src/Utilities/results.jl +++ b/src/Utilities/results.jl @@ -37,17 +37,21 @@ the `ObjectiveFunction` value. """ function get_fallback(model::MOI.ModelLike, attr::MOI.ObjectiveValue) MOI.check_result_index_bounds(model, attr) - F = MOI.get(model, MOI.ObjectiveFunctionType()) - f = MOI.get(model, MOI.ObjectiveFunction{F}()) - obj = eval_variables(model, f) do vi - return MOI.get(model, MOI.VariablePrimal(attr.result_index), vi) - end - if is_ray(MOI.get(model, MOI.PrimalStatus())) - # Dual infeasibility certificates do not include the primal - # objective constant. - obj -= MOI.constant(f, typeof(obj)) + try + F = MOI.get(model, MOI.ObjectiveFunctionType()) + f = MOI.get(model, MOI.ObjectiveFunction{F}()) + obj = eval_variables(model, f) do vi + return MOI.get(model, MOI.VariablePrimal(attr.result_index), vi) + end + if is_ray(MOI.get(model, MOI.PrimalStatus())) + # Dual infeasibility certificates do not include the primal + # objective constant. + obj -= MOI.constant(f, typeof(obj)) + end + return obj + catch + throw(MOI.GetAttributeNotAllowed(attr)) end - return obj end # MOI.DualObjectiveValue @@ -152,20 +156,24 @@ function get_fallback( ::Type{T}, )::T where {T} MOI.check_result_index_bounds(model, attr) - value = zero(T) # sum will not work if there are zero constraints - for (F, S) in MOI.get(model, MOI.ListOfConstraintTypesPresent()) - value += _dual_objective_value(model, F, S, T, attr.result_index)::T - end - if MOI.get(model, MOI.ObjectiveSense()) != MOI.MAX_SENSE - value = -value - end - if !is_ray(MOI.get(model, MOI.DualStatus())) - # The objective constant should not be present in rays - F = MOI.get(model, MOI.ObjectiveFunctionType()) - f = MOI.get(model, MOI.ObjectiveFunction{F}()) - value += MOI.constant(f, T) + try + value = zero(T) # sum will not work if there are zero constraints + for (F, S) in MOI.get(model, MOI.ListOfConstraintTypesPresent()) + value += _dual_objective_value(model, F, S, T, attr.result_index)::T + end + if MOI.get(model, MOI.ObjectiveSense()) != MOI.MAX_SENSE + value = -value + end + if !is_ray(MOI.get(model, MOI.DualStatus())) + # The objective constant should not be present in rays + F = MOI.get(model, MOI.ObjectiveFunctionType()) + f = MOI.get(model, MOI.ObjectiveFunction{F}()) + value += MOI.constant(f, T) + end + return value::T + catch + throw(MOI.GetAttributeNotAllowed(attr)) end - return value::T end # MOI.ConstraintPrimal @@ -186,16 +194,18 @@ function get_fallback( idx::MOI.ConstraintIndex, ) MOI.check_result_index_bounds(model, attr) - # If there is an error getting ConstraintFunction, we instead want to - # re-throw the attribute for ConstraintPrimal, not ConstraintFunction. - f = MOI.get(model, MOI.ConstraintFunction(), idx) - c = eval_variables(model, f) do vi - return MOI.get(model, MOI.VariablePrimal(attr.result_index), vi) - end - if is_ray(MOI.get(model, MOI.PrimalStatus())) - c -= MOI.constant(f, typeof(c)) + try + f = MOI.get(model, MOI.ConstraintFunction(), idx) + c = eval_variables(model, f) do vi + return MOI.get(model, MOI.VariablePrimal(attr.result_index), vi) + end + if is_ray(MOI.get(model, MOI.PrimalStatus())) + c -= MOI.constant(f, typeof(c)) + end + return c + catch + throw(MOI.GetAttributeNotAllowed(attr)) end - return c end # MOI.ConstraintDual @@ -485,6 +495,10 @@ function get_fallback( ci::MOI.ConstraintIndex{<:Union{MOI.VariableIndex,MOI.VectorOfVariables}}, ) MOI.check_result_index_bounds(model, attr) - f = MOI.get(model, MOI.ConstraintFunction(), ci) - return _variable_dual(model, attr, ci, f) + try + f = MOI.get(model, MOI.ConstraintFunction(), ci) + return _variable_dual(model, attr, ci, f) + catch + throw(MOI.GetAttributeNotAllowed(attr)) + end end From 67c15a20dd1e1a9d69b1ec0d4a3d2c61adbd9797 Mon Sep 17 00:00:00 2001 From: odow Date: Thu, 25 Jan 2024 15:56:45 +1300 Subject: [PATCH 2/3] Update --- src/Utilities/mockoptimizer.jl | 12 ++++++------ test/Bridges/bridge_optimizer.jl | 7 +++---- test/Utilities/cachingoptimizer.jl | 4 ++-- test/Utilities/mockoptimizer.jl | 26 +++++++------------------- 4 files changed, 18 insertions(+), 31 deletions(-) diff --git a/src/Utilities/mockoptimizer.jl b/src/Utilities/mockoptimizer.jl index 81bad27593..02beb7ba4a 100644 --- a/src/Utilities/mockoptimizer.jl +++ b/src/Utilities/mockoptimizer.jl @@ -620,7 +620,8 @@ function MOI.get( end primal = get(mock.callback_variable_primal, xor_index(idx), nothing) if primal === nothing - error("No mock callback primal is set for variable `", idx, "`.") + msg = "No mock callback primal is set for variable `$idx`." + throw(MOI.GetAttributeNotAllowed(attr, msg)) end return primal end @@ -749,14 +750,13 @@ function _safe_get_result( index_name = index isa MOI.VariableIndex ? "variable" : "constraint" result_to_value = get(dict, xor_index(index), nothing) if result_to_value === nothing - error("No mock $name is set for ", index_name, " `", index, "`.") + msg = "No mock $name is set for $index_name `$index`." + throw(MOI.GetAttributeNotAllowed(attr, msg)) end value = get(result_to_value, attr.result_index, nothing) if value === nothing - error( - "No mock $name is set for $(index_name) `$(index)` at result " * - "index `$(attr.result_index)`.", - ) + msg = "No mock $name is set for $index_name `$index` at result index `$(attr.result_index)`." + throw(MOI.GetAttributeNotAllowed(attr, msg)) end return value end diff --git a/test/Bridges/bridge_optimizer.jl b/test/Bridges/bridge_optimizer.jl index 9493f4c0e4..5faa0f8373 100644 --- a/test/Bridges/bridge_optimizer.jl +++ b/test/Bridges/bridge_optimizer.jl @@ -124,10 +124,9 @@ function test_CallbackVariablePrimal() y = MOI.get(mock, MOI.ListOfVariableIndices())[1] z = MOI.add_variable(bridged) attr = MOI.CallbackVariablePrimal(nothing) - @test_throws( - ErrorException("No mock callback primal is set for variable `$z`."), - MOI.get(bridged, attr, z), - ) + msg = "No mock callback primal is set for variable `$z`." + err = MOI.GetAttributeNotAllowed(attr, msg) + @test_throws err MOI.get(bridged, attr, z) MOI.set(mock, attr, y, 1.0) MOI.set(mock, attr, z, 2.0) @test MOI.get(bridged, attr, z) == 2.0 diff --git a/test/Utilities/cachingoptimizer.jl b/test/Utilities/cachingoptimizer.jl index 6113ffbf33..67f161db1b 100644 --- a/test/Utilities/cachingoptimizer.jl +++ b/test/Utilities/cachingoptimizer.jl @@ -357,8 +357,8 @@ function test_mapping_of_variables() @testset "CallbackVariablePrimal" begin attr = MOI.CallbackVariablePrimal(nothing) - err = - ErrorException("No mock callback primal is set for variable `$y`.") + msg = "No mock callback primal is set for variable `$y`." + err = MOI.GetCallbackNotAllowed(attr, msg) @test_throws err MOI.get(model, attr, x) MOI.set(mock, attr, y, 1.0) @test_throws MOI.InvalidIndex(x) MOI.get(mock, attr, x) diff --git a/test/Utilities/mockoptimizer.jl b/test/Utilities/mockoptimizer.jl index f39f7a2f65..2edf7810ab 100644 --- a/test/Utilities/mockoptimizer.jl +++ b/test/Utilities/mockoptimizer.jl @@ -53,7 +53,7 @@ function test_optimizer_solve_with_result() MOI.set(optimizer, MOI.ObjectiveFunction{MOI.VariableIndex}(), v[1]) MOI.set(optimizer, MOI.ResultCount(), 1) @test_throws( - ErrorException("No mock primal is set for variable `$(v[1])`."), + MOI.GetAttributeNotAllowed{MOI.VariablePrimal}, MOI.get(optimizer, MOI.VariablePrimal(), v[1]) ) @test_throws( @@ -87,15 +87,11 @@ function test_optimizer_solve_with_result() optimizer.eval_objective_value = true @test MOI.get(optimizer, MOI.ObjectiveValue()) == 3.0 @test_throws( - ErrorException( - "No mock primal is set for variable `$(v[1])` at result index `2`.", - ), + MOI.GetAttributeNotAllowed(MOI.ObjectiveValue(2)), MOI.get(optimizer, MOI.ObjectiveValue(2)) ) @test_throws( - ErrorException( - "No mock dual is set for constraint `$c1` at result index `1`.", - ), + MOI.GetAttributeNotAllowed(MOI.DualObjectiveValue()), MOI.get(optimizer, MOI.DualObjectiveValue()) ) @test MOI.get(optimizer, MOI.DualObjectiveValue(2)) == 5.9 @@ -104,31 +100,23 @@ function test_optimizer_solve_with_result() @test MOI.get(optimizer, MOI.VariablePrimal(), v) == [3.0, 2.0] @test MOI.get(optimizer, MOI.VariablePrimal(), v[1]) == 3.0 @test_throws( - ErrorException( - "No mock primal is set for variable `$(v[1])` at result index `2`.", - ), + MOI.GetAttributeNotAllowed{MOI.VariablePrimal}, MOI.get(optimizer, MOI.VariablePrimal(2), v[1]) ) @test MOI.get(optimizer, MOI.ConstraintPrimal(), c1) == 3.0 @test MOI.get(optimizer, MOI.ConstraintPrimal(), soc) == [3.0, 2.0] @test_throws( - ErrorException( - "No mock primal is set for variable `$(v[1])` at result index `2`.", - ), + MOI.GetAttributeNotAllowed(MOI.ConstraintPrimal(2)), @show MOI.get(optimizer, MOI.ConstraintPrimal(2), c1) ) @test_throws( - ErrorException( - "No mock primal is set for variable `$(v[1])` at result index `2`.", - ), + MOI.GetAttributeNotAllowed(MOI.ConstraintPrimal(2)), MOI.get(optimizer, MOI.ConstraintPrimal(2), soc) ) @test MOI.get(optimizer, MOI.ConstraintDual(2), c1) == 5.9 @test MOI.get(optimizer, MOI.ConstraintDual(2), soc) == [1.0, 2.0] @test_throws( - ErrorException( - "No mock dual is set for constraint `$c1` at result index `1`.", - ), + MOI.GetAttributeNotAllowed{MOI.ConstraintDual}, MOI.get(optimizer, MOI.ConstraintDual(1), c1) ) end From 0bf811ff5fe02a64505ae76e4c2669e23b8e8472 Mon Sep 17 00:00:00 2001 From: odow Date: Thu, 25 Jan 2024 16:01:59 +1300 Subject: [PATCH 3/3] Fix --- test/Utilities/cachingoptimizer.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/Utilities/cachingoptimizer.jl b/test/Utilities/cachingoptimizer.jl index 67f161db1b..55a7360fdb 100644 --- a/test/Utilities/cachingoptimizer.jl +++ b/test/Utilities/cachingoptimizer.jl @@ -358,7 +358,7 @@ function test_mapping_of_variables() @testset "CallbackVariablePrimal" begin attr = MOI.CallbackVariablePrimal(nothing) msg = "No mock callback primal is set for variable `$y`." - err = MOI.GetCallbackNotAllowed(attr, msg) + err = MOI.GetAttributeNotAllowed(attr, msg) @test_throws err MOI.get(model, attr, x) MOI.set(mock, attr, y, 1.0) @test_throws MOI.InvalidIndex(x) MOI.get(mock, attr, x)