From 0ad2f55cbd17a59a1eb73164f966f11be3bb8093 Mon Sep 17 00:00:00 2001 From: Oscar Dowson Date: Tue, 15 Sep 2026 12:53:25 +1200 Subject: [PATCH 1/2] Fix get_fallback for DualObjectiveValue with non-affine objective --- src/Utilities/results.jl | 12 +++++++++--- test/Utilities/test_results.jl | 24 ++++++++++++++++++++++++ 2 files changed, 33 insertions(+), 3 deletions(-) diff --git a/src/Utilities/results.jl b/src/Utilities/results.jl index 4bc810f3d6..d1f199334d 100644 --- a/src/Utilities/results.jl +++ b/src/Utilities/results.jl @@ -74,6 +74,14 @@ function get_fallback( if status == MOI.NO_SOLUTION throw(MOI.GetAttributeNotAllowed(attr, "No dual solution is available")) end + F = MOI.get(model, MOI.ObjectiveFunctionType()) + if !(F <: Union{MOI.VariableIndex,MOI.ScalarAffineFunction}) + err = MOI.GetAttributeNotAllowed( + attr, + "Cannot get the dual objective with an objective function of type `$F`", + ) + throw(err) + end 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 @@ -83,9 +91,7 @@ function get_fallback( end if !is_ray(status) # 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) + value += MOI.constant(MOI.get(model, MOI.ObjectiveFunction{F}()), T) end return value::T end diff --git a/test/Utilities/test_results.jl b/test/Utilities/test_results.jl index 43d0b3a476..6b0c685dda 100644 --- a/test/Utilities/test_results.jl +++ b/test/Utilities/test_results.jl @@ -291,6 +291,30 @@ function test_get_fallback_DualObjectiveValue() return end +function test_get_fallback_DualObjectiveValue_Quadratic() + T = Float64 + model = MOI.Utilities.MockOptimizer( + MOI.Utilities.UniversalFallback(MOI.Utilities.Model{T}()), + T, + ) + x = MOI.add_variable(model) + MOI.set(model, MOI.ObjectiveSense(), MOI.MIN_SENSE) + f = 1.0 * x * x + MOI.set(model, MOI.ObjectiveFunction{typeof(f)}(), f) + MOI.set(model, MOI.ResultCount(), 1) + MOI.set(model, MOI.PrimalStatus(), MOI.FEASIBLE_POINT) + MOI.set(model, MOI.DualStatus(), MOI.FEASIBLE_POINT) + MOI.set(model, MOI.VariablePrimal(), x, 0.0) + @test_throws( + MOI.GetAttributeNotAllowed( + MOI.DualObjectiveValue(), + "Cannot get the dual objective with an objective function of type `$(typeof(f))`", + ), + MOI.Utilities.get_fallback(model, MOI.DualObjectiveValue(), T), + ) + return +end + end # module TestResults TestResults.runtests() From 0768b65e95a8dc9d5933ff78785b43f89b0f984d Mon Sep 17 00:00:00 2001 From: Oscar Dowson Date: Wed, 16 Sep 2026 14:52:21 +1200 Subject: [PATCH 2/2] Update --- test/Bridges/Objective/test_QuadratizeBridge.jl | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/test/Bridges/Objective/test_QuadratizeBridge.jl b/test/Bridges/Objective/test_QuadratizeBridge.jl index 79834bdd87..ce874222e8 100644 --- a/test/Bridges/Objective/test_QuadratizeBridge.jl +++ b/test/Bridges/Objective/test_QuadratizeBridge.jl @@ -71,7 +71,8 @@ function test_solve_result_index() (MOI.VariableIndex, MOI.GreaterThan{Float64}) => [1.0], ), ) - MOI.Test.test_solve_result_index(model, MOI.Test.Config()) + config = MOI.Test.Config(; exclude = Any[MOI.DualObjectiveValue]) + MOI.Test.test_solve_result_index(model, config) return end