Skip to content

Fix get_fallback of DualObjectiveValue with HyperRectangle #2755

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
May 10, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 29 additions & 11 deletions src/Utilities/results.jl
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,29 @@
return set_dot(constant, dual, set)
end

function _dual_objective_value(

Check warning on line 111 in src/Utilities/results.jl

View check run for this annotation

Codecov / codecov/patch

src/Utilities/results.jl#L111

Added line #L111 was not covered by tests
model::MOI.ModelLike,
ci::MOI.ConstraintIndex{<:MOI.AbstractVectorFunction,<:MOI.HyperRectangle},
::Type{T},
result_index::Integer,
) where {T}
func_constant =

Check warning on line 117 in src/Utilities/results.jl

View check run for this annotation

Codecov / codecov/patch

src/Utilities/results.jl#L117

Added line #L117 was not covered by tests
MOI.constant(MOI.get(model, MOI.ConstraintFunction(), ci), T)
set = MOI.get(model, MOI.ConstraintSet(), ci)
dual = MOI.get(model, MOI.ConstraintDual(result_index), ci)
constant = map(eachindex(func_constant)) do i
return func_constant[i] - if dual[i] < zero(dual[i])

Check warning on line 122 in src/Utilities/results.jl

View check run for this annotation

Codecov / codecov/patch

src/Utilities/results.jl#L119-L122

Added lines #L119 - L122 were not covered by tests
# The dual is negative so it is in the dual of the MOI.LessThan cone
# hence the upper bound of the Interval set is tight
set.upper[i]

Check warning on line 125 in src/Utilities/results.jl

View check run for this annotation

Codecov / codecov/patch

src/Utilities/results.jl#L125

Added line #L125 was not covered by tests
else
# the lower bound is tight
set.lower[i]

Check warning on line 128 in src/Utilities/results.jl

View check run for this annotation

Codecov / codecov/patch

src/Utilities/results.jl#L128

Added line #L128 was not covered by tests
end
end
return set_dot(constant, dual, set)

Check warning on line 131 in src/Utilities/results.jl

View check run for this annotation

Codecov / codecov/patch

src/Utilities/results.jl#L131

Added line #L131 was not covered by tests
end

function _dual_objective_value(
model::MOI.ModelLike,
::Type{F},
Expand All @@ -116,23 +139,18 @@
result_index::Integer,
) where {T,F<:MOI.AbstractFunction,S<:MOI.AbstractSet}
value = zero(T)
if F == variable_function_type(S) && !_has_constant(S)
return value # Shortcut
end
for ci in MOI.get(model, MOI.ListOfConstraintIndices{F,S}())
value += _dual_objective_value(model, ci, T, result_index)
end
return value
end

function _dual_objective_value(
::MOI.ModelLike,
::Type{MOI.VectorOfVariables},
::Type{<:MOI.AbstractVectorSet},
::Type{T},
::Integer,
) where {T}
# No constant in the function nor set so no contribution to the dual
# objective value.
return zero(T)
end
_has_constant(::Type{<:MOI.AbstractScalarSet}) = true
_has_constant(::Type{<:MOI.AbstractVectorSet}) = false
_has_constant(::Type{<:MOI.HyperRectangle}) = true

Check warning on line 153 in src/Utilities/results.jl

View check run for this annotation

Codecov / codecov/patch

src/Utilities/results.jl#L153

Added line #L153 was not covered by tests

"""
get_fallback(
Expand Down
56 changes: 56 additions & 0 deletions test/Utilities/results.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
# Copyright (c) 2017: Miles Lubin and contributors
# Copyright (c) 2017: Google Inc.
#
# Use of this source code is governed by an MIT-style license that can be found
# in the LICENSE.md file or at https://opensource.org/licenses/MIT.

module TestResults

using Test

import MathOptInterface as MOI

function runtests()
for name in names(@__MODULE__; all = true)
if startswith("$(name)", "test_")
@testset "$(name)" begin
getfield(@__MODULE__, name)()
end
end
end
return
end

test_hyperrectangle_Int() = _test_hyperrectangle(Int)

test_hyperrectangle_Float64() = _test_hyperrectangle(Float64)

function _test_hyperrectangle(T)
model = MOI.Utilities.MockOptimizer(
MOI.Utilities.UniversalFallback(MOI.Utilities.Model{T}()),
T,
)
x = MOI.add_variables(model, 2)
c1 = MOI.add_constraint(
model,
MOI.VectorOfVariables(x),
MOI.HyperRectangle(T[3, -7], T[5, -2]),
)
c2 = MOI.add_constraint(
model,
MOI.Utilities.vectorize(x .+ T[11, 13]),
MOI.HyperRectangle(T[-T(6), -T(4)], [T(3), T(2)]),
)
MOI.set(model, MOI.ConstraintDual(), c1, T[4, -3])
MOI.set(model, MOI.ConstraintDual(), c2, T[-2, 5])
@test -53 == @inferred MOI.Utilities.get_fallback(
model,
MOI.DualObjectiveValue(),
T,
)
return
end

end # module TestResults

TestResults.runtests()
Loading