@@ -88,6 +88,26 @@ function _dual_objective_value(
8888 )
8989end
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+
91111function _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)
109122end
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)
132138end
133139
134140function _dual_objective_value (
0 commit comments