Skip to content

Commit 2ecfa90

Browse files
authored
[Utilities] fix get_fallback of DualObjectiveValue with HyperRectangle (#2755)
1 parent 4e26305 commit 2ecfa90

File tree

2 files changed

+85
-11
lines changed

2 files changed

+85
-11
lines changed

src/Utilities/results.jl

Lines changed: 29 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,29 @@ function _dual_objective_value(
108108
return set_dot(constant, dual, set)
109109
end
110110

111+
function _dual_objective_value(
112+
model::MOI.ModelLike,
113+
ci::MOI.ConstraintIndex{<:MOI.AbstractVectorFunction,<:MOI.HyperRectangle},
114+
::Type{T},
115+
result_index::Integer,
116+
) where {T}
117+
func_constant =
118+
MOI.constant(MOI.get(model, MOI.ConstraintFunction(), ci), T)
119+
set = MOI.get(model, MOI.ConstraintSet(), ci)
120+
dual = MOI.get(model, MOI.ConstraintDual(result_index), ci)
121+
constant = map(eachindex(func_constant)) do i
122+
return func_constant[i] - if dual[i] < zero(dual[i])
123+
# The dual is negative so it is in the dual of the MOI.LessThan cone
124+
# hence the upper bound of the Interval set is tight
125+
set.upper[i]
126+
else
127+
# the lower bound is tight
128+
set.lower[i]
129+
end
130+
end
131+
return set_dot(constant, dual, set)
132+
end
133+
111134
function _dual_objective_value(
112135
model::MOI.ModelLike,
113136
::Type{F},
@@ -116,23 +139,18 @@ function _dual_objective_value(
116139
result_index::Integer,
117140
) where {T,F<:MOI.AbstractFunction,S<:MOI.AbstractSet}
118141
value = zero(T)
142+
if F == variable_function_type(S) && !_has_constant(S)
143+
return value # Shortcut
144+
end
119145
for ci in MOI.get(model, MOI.ListOfConstraintIndices{F,S}())
120146
value += _dual_objective_value(model, ci, T, result_index)
121147
end
122148
return value
123149
end
124150

125-
function _dual_objective_value(
126-
::MOI.ModelLike,
127-
::Type{MOI.VectorOfVariables},
128-
::Type{<:MOI.AbstractVectorSet},
129-
::Type{T},
130-
::Integer,
131-
) where {T}
132-
# No constant in the function nor set so no contribution to the dual
133-
# objective value.
134-
return zero(T)
135-
end
151+
_has_constant(::Type{<:MOI.AbstractScalarSet}) = true
152+
_has_constant(::Type{<:MOI.AbstractVectorSet}) = false
153+
_has_constant(::Type{<:MOI.HyperRectangle}) = true
136154

137155
"""
138156
get_fallback(

test/Utilities/results.jl

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
# Copyright (c) 2017: Miles Lubin and contributors
2+
# Copyright (c) 2017: Google Inc.
3+
#
4+
# Use of this source code is governed by an MIT-style license that can be found
5+
# in the LICENSE.md file or at https://opensource.org/licenses/MIT.
6+
7+
module TestResults
8+
9+
using Test
10+
11+
import MathOptInterface as MOI
12+
13+
function runtests()
14+
for name in names(@__MODULE__; all = true)
15+
if startswith("$(name)", "test_")
16+
@testset "$(name)" begin
17+
getfield(@__MODULE__, name)()
18+
end
19+
end
20+
end
21+
return
22+
end
23+
24+
test_hyperrectangle_Int() = _test_hyperrectangle(Int)
25+
26+
test_hyperrectangle_Float64() = _test_hyperrectangle(Float64)
27+
28+
function _test_hyperrectangle(T)
29+
model = MOI.Utilities.MockOptimizer(
30+
MOI.Utilities.UniversalFallback(MOI.Utilities.Model{T}()),
31+
T,
32+
)
33+
x = MOI.add_variables(model, 2)
34+
c1 = MOI.add_constraint(
35+
model,
36+
MOI.VectorOfVariables(x),
37+
MOI.HyperRectangle(T[3, -7], T[5, -2]),
38+
)
39+
c2 = MOI.add_constraint(
40+
model,
41+
MOI.Utilities.vectorize(x .+ T[11, 13]),
42+
MOI.HyperRectangle(T[-T(6), -T(4)], [T(3), T(2)]),
43+
)
44+
MOI.set(model, MOI.ConstraintDual(), c1, T[4, -3])
45+
MOI.set(model, MOI.ConstraintDual(), c2, T[-2, 5])
46+
@test -53 == @inferred MOI.Utilities.get_fallback(
47+
model,
48+
MOI.DualObjectiveValue(),
49+
T,
50+
)
51+
return
52+
end
53+
54+
end # module TestResults
55+
56+
TestResults.runtests()

0 commit comments

Comments
 (0)