Skip to content

Commit 195870f

Browse files
committed
Fix get_fallback of DualObjectiveValue with HyperRectangle
1 parent 8113edf commit 195870f

File tree

2 files changed

+75
-11
lines changed

2 files changed

+75
-11
lines changed

src/Utilities/results.jl

Lines changed: 28 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,28 @@ 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 = MOI.constant(MOI.get(model, MOI.ConstraintFunction(), ci), T)
118+
set = MOI.get(model, MOI.ConstraintSet(), ci)
119+
dual = MOI.get(model, MOI.ConstraintDual(result_index), ci)
120+
constant = map(eachindex(func_constant)) do i
121+
func_constant[i] - if dual[i] < zero(dual[i])
122+
# The dual is negative so it is in the dual of the MOI.LessThan cone
123+
# hence the upper bound of the Interval set is tight
124+
set.upper[i]
125+
else
126+
# the lower bound is tight
127+
set.lower[i]
128+
end
129+
end
130+
return set_dot(constant, dual, set)
131+
end
132+
111133
function _dual_objective_value(
112134
model::MOI.ModelLike,
113135
::Type{F},
@@ -116,23 +138,18 @@ function _dual_objective_value(
116138
result_index::Integer,
117139
) where {T,F<:MOI.AbstractFunction,S<:MOI.AbstractSet}
118140
value = zero(T)
141+
if F == variable_function_type(S) && !_has_constant(S)
142+
return value # Shortcut
143+
end
119144
for ci in MOI.get(model, MOI.ListOfConstraintIndices{F,S}())
120145
value += _dual_objective_value(model, ci, T, result_index)
121146
end
122147
return value
123148
end
124149

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
150+
_has_constant(::Type{<:MOI.AbstractScalarSet}) = true
151+
_has_constant(::Type{<:MOI.AbstractVectorSet}) = false
152+
_has_constant(::Type{<:MOI.HyperRectangle}) = true
136153

137154
"""
138155
get_fallback(

test/Utilities/results.jl

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
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) $T" for T in [Int, Float64]
17+
getfield(@__MODULE__, name)(T)
18+
end
19+
end
20+
end
21+
return
22+
end
23+
24+
function test_hyperrectangle(T)
25+
model = MOI.Utilities.MockOptimizer(
26+
MOI.Utilities.UniversalFallback(MOI.Utilities.Model{T}()),
27+
T,
28+
)
29+
x = MOI.add_variables(model, 2)
30+
c1 = MOI.add_constraint(
31+
model,
32+
MOI.VectorOfVariables(x),
33+
MOI.HyperRectangle(T[3, -7], T[5, -2]),
34+
)
35+
c2 = MOI.add_constraint(
36+
model,
37+
MOI.Utilities.vectorize(x .+ T[11, 13]),
38+
MOI.HyperRectangle(T[-T(6), -T(4)], [T(3), T(2)]),
39+
)
40+
MOI.set(model, MOI.ConstraintDual(), c1, T[4, -3])
41+
MOI.set(model, MOI.ConstraintDual(), c2, T[-2, 5])
42+
@test -53 == @inferred MOI.Utilities.get_fallback(model, MOI.DualObjectiveValue(), T)
43+
end
44+
45+
end
46+
47+
TestResults.runtests()

0 commit comments

Comments
 (0)