Skip to content

Commit 846f878

Browse files
committed
[Utililties] fix dual objective value with open intervals
1 parent 2b3a763 commit 846f878

File tree

1 file changed

+24
-18
lines changed

1 file changed

+24
-18
lines changed

src/Utilities/results.jl

Lines changed: 24 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,26 @@ function _dual_objective_value(
8888
)
8989
end
9090

91+
"""
92+
Given lower <= f(x) <= upper [dual], return the expression to be multiplied by
93+
the dual variable. This is one of the following cases:
94+
95+
1. f(x) - lower: if `lower > -Inf` and the lower bound is binding (either no
96+
`upper` or `dual > 0`)
97+
2. f(x) - upper: if `upper < Inf` and the upper bound is binding (either no
98+
`lower` or `dual < 0`)
99+
3. f(x): if `lower = -Inf` and `upper = Inf` or `dual = 0`
100+
"""
101+
function _constant_minus_bound(constant, lower, upper, dual)
102+
if isfinite(lower) && (!isfinite(upper) || dual > zero(dual))
103+
return constant - lower
104+
elseif isfinite(upper) && (!isfinite(lower) || dual < zero(dual))
105+
return constant - upper
106+
else
107+
return constant
108+
end
109+
end
110+
91111
function _dual_objective_value(
92112
model::MOI.ModelLike,
93113
ci::MOI.ConstraintIndex{<:MOI.AbstractScalarFunction,<:MOI.Interval},
@@ -97,14 +117,7 @@ function _dual_objective_value(
97117
constant = MOI.constant(MOI.get(model, MOI.ConstraintFunction(), ci), T)
98118
set = MOI.get(model, MOI.ConstraintSet(), ci)
99119
dual = MOI.get(model, MOI.ConstraintDual(result_index), ci)
100-
if dual < zero(dual)
101-
# The dual is negative so it is in the dual of the MOI.LessThan cone
102-
# hence the upper bound of the Interval set is tight
103-
constant -= set.upper
104-
else
105-
# the lower bound is tight
106-
constant -= set.lower
107-
end
120+
constant = _constant_minus_bound(constant, set.lower, set.upper, dual)
108121
return set_dot(constant, dual, set)
109122
end
110123

@@ -118,17 +131,10 @@ function _dual_objective_value(
118131
MOI.constant(MOI.get(model, MOI.ConstraintFunction(), ci), T)
119132
set = MOI.get(model, MOI.ConstraintSet(), ci)
120133
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
134+
constants = map(enumerate(func_constant)) do (i, c)
135+
return _constant_minus_bound(c, set.lower[i], set.upper[i], dual[i])
130136
end
131-
return set_dot(constant, dual, set)
137+
return set_dot(constants, dual, set)
132138
end
133139

134140
function _dual_objective_value(

0 commit comments

Comments
 (0)