|
52 | 52 |
|
53 | 53 | # MOI.DualObjectiveValue |
54 | 54 |
|
55 | | -function _constraint_constant( |
56 | | - model::MOI.ModelLike, |
57 | | - ci::MOI.ConstraintIndex{ |
58 | | - <:MOI.AbstractVectorFunction, |
59 | | - <:MOI.AbstractVectorSet, |
60 | | - }, |
61 | | - ::Type{T}, |
62 | | -) where {T} |
63 | | - return MOI.constant(MOI.get(model, MOI.ConstraintFunction(), ci), T) |
64 | | -end |
65 | | - |
66 | | -function _constraint_constant( |
67 | | - model::MOI.ModelLike, |
68 | | - ci::MOI.ConstraintIndex{ |
69 | | - <:MOI.AbstractScalarFunction, |
70 | | - <:MOI.AbstractScalarSet, |
71 | | - }, |
72 | | - ::Type{T}, |
73 | | -) where {T} |
74 | | - return MOI.constant(MOI.get(model, MOI.ConstraintFunction(), ci), T) - |
75 | | - MOI.constant(MOI.get(model, MOI.ConstraintSet(), ci)) |
76 | | -end |
77 | | - |
78 | | -function _dual_objective_value( |
79 | | - model::MOI.ModelLike, |
80 | | - ci::MOI.ConstraintIndex, |
81 | | - ::Type{T}, |
82 | | - result_index::Integer, |
83 | | -) where {T} |
84 | | - return set_dot( |
85 | | - _constraint_constant(model, ci, T), |
86 | | - MOI.get(model, MOI.ConstraintDual(result_index), ci), |
87 | | - MOI.get(model, MOI.ConstraintSet(), ci), |
88 | | - ) |
89 | | -end |
90 | | - |
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 | | - |
111 | | -function _dual_objective_value( |
112 | | - model::MOI.ModelLike, |
113 | | - ci::MOI.ConstraintIndex{<:MOI.AbstractScalarFunction,<:MOI.Interval}, |
114 | | - ::Type{T}, |
115 | | - result_index::Integer, |
116 | | -) where {T} |
117 | | - 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 = _constant_minus_bound(constant, set.lower, set.upper, dual) |
121 | | - return set_dot(constant, dual, set) |
122 | | -end |
123 | | - |
124 | | -function _dual_objective_value( |
125 | | - model::MOI.ModelLike, |
126 | | - ci::MOI.ConstraintIndex{<:MOI.AbstractVectorFunction,<:MOI.HyperRectangle}, |
127 | | - ::Type{T}, |
128 | | - result_index::Integer, |
129 | | -) where {T} |
130 | | - func_constant = |
131 | | - MOI.constant(MOI.get(model, MOI.ConstraintFunction(), ci), T) |
132 | | - set = MOI.get(model, MOI.ConstraintSet(), ci) |
133 | | - dual = MOI.get(model, MOI.ConstraintDual(result_index), ci) |
134 | | - constants = map(enumerate(func_constant)) do (i, c) |
135 | | - return _constant_minus_bound(c, set.lower[i], set.upper[i], dual[i]) |
136 | | - end |
137 | | - return set_dot(constants, dual, set) |
138 | | -end |
139 | | - |
140 | | -function _dual_objective_value( |
141 | | - model::MOI.ModelLike, |
142 | | - ::Type{F}, |
143 | | - ::Type{S}, |
144 | | - ::Type{T}, |
145 | | - result_index::Integer, |
146 | | -) where {T,F<:MOI.AbstractFunction,S<:MOI.AbstractSet} |
147 | | - value = zero(T) |
148 | | - if F == variable_function_type(S) && !_has_constant(S) |
149 | | - return value # Shortcut |
150 | | - end |
151 | | - for ci in MOI.get(model, MOI.ListOfConstraintIndices{F,S}()) |
152 | | - value += _dual_objective_value(model, ci, T, result_index) |
153 | | - end |
154 | | - return value |
155 | | -end |
156 | | - |
157 | | -_has_constant(::Type{<:MOI.AbstractScalarSet}) = true |
158 | | -_has_constant(::Type{<:MOI.AbstractVectorSet}) = false |
159 | | -_has_constant(::Type{<:MOI.HyperRectangle}) = true |
160 | | - |
161 | 55 | """ |
162 | 56 | get_fallback( |
163 | 57 | model::MOI.ModelLike, |
@@ -192,6 +86,62 @@ function get_fallback( |
192 | 86 | return value::T |
193 | 87 | end |
194 | 88 |
|
| 89 | +_has_constant(::Type{<:MOI.AbstractScalarSet}) = true |
| 90 | +_has_constant(::Type{<:MOI.AbstractVectorSet}) = false |
| 91 | +_has_constant(::Type{<:MOI.HyperRectangle}) = true |
| 92 | + |
| 93 | +function _dual_objective_value( |
| 94 | + model::MOI.ModelLike, |
| 95 | + ::Type{F}, |
| 96 | + ::Type{S}, |
| 97 | + ::Type{T}, |
| 98 | + result_index::Integer, |
| 99 | +)::T where {T,F<:MOI.AbstractFunction,S<:MOI.AbstractSet} |
| 100 | + value = zero(T) |
| 101 | + if F == variable_function_type(S) && !_has_constant(S) |
| 102 | + return value # Shortcut |
| 103 | + end |
| 104 | + for ci in MOI.get(model, MOI.ListOfConstraintIndices{F,S}()) |
| 105 | + constant = MOI.constant(MOI.get(model, MOI.ConstraintFunction(), ci), T) |
| 106 | + set = MOI.get(model, MOI.ConstraintSet(), ci) |
| 107 | + dual = MOI.get(model, MOI.ConstraintDual(result_index), ci) |
| 108 | + value += _dual_objective_dot(constant, dual, set) |
| 109 | + end |
| 110 | + return value |
| 111 | +end |
| 112 | + |
| 113 | +_dual_objective_dot(x, y, set) = set_dot(x, y, set) |
| 114 | + |
| 115 | +_dual_objective_dot(x, y, set::MOI.EqualTo) = (x - set.value) * y |
| 116 | + |
| 117 | +_dual_objective_dot(x, y, set::MOI.LessThan) = (x - set.upper) * y |
| 118 | + |
| 119 | +_dual_objective_dot(x, y, set::MOI.GreaterThan) = (x - set.lower) * y |
| 120 | + |
| 121 | +function _dual_objective_dot(x, y, set::MOI.Interval) |
| 122 | + if isfinite(set.lower) && (!isfinite(set.upper) || y > zero(y)) |
| 123 | + return (x - set.lower) * y |
| 124 | + elseif isfinite(upper) && (!isfinite(set.lower) || y < zero(y)) |
| 125 | + return (x - set.upper) * y |
| 126 | + end |
| 127 | + return x * y |
| 128 | +end |
| 129 | + |
| 130 | +function _dual_objective_dot(x, y, set::MOI.HyperRectangle) |
| 131 | + @assert length(x) == length(y) == MOI.dimension(set) |
| 132 | + ret = zero(eltype(x)) |
| 133 | + for (xi, yi, li, ui) in zip(x, y, set.lower, set.upper) |
| 134 | + if isfinite(li) && (!isfinite(ui) || yi > zero(yi)) |
| 135 | + ret += (xi - li) * yi |
| 136 | + elseif isfinite(upper) && (!isfinite(li) || yi < zero(yi)) |
| 137 | + ret += (xi - ui) * yi |
| 138 | + else |
| 139 | + ret += xi * yi |
| 140 | + end |
| 141 | + end |
| 142 | + return ret |
| 143 | +end |
| 144 | + |
195 | 145 | # MOI.ConstraintPrimal |
196 | 146 |
|
197 | 147 | """ |
|
0 commit comments