Skip to content

Commit 9ecf7d0

Browse files
authored
Merge 964d1af into 36912e1
2 parents 36912e1 + 964d1af commit 9ecf7d0

2 files changed

Lines changed: 80 additions & 11 deletions

File tree

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: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
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(
43+
model,
44+
MOI.DualObjectiveValue(),
45+
T,
46+
)
47+
end
48+
49+
end
50+
51+
TestResults.runtests()

0 commit comments

Comments
 (0)