@@ -124,26 +124,46 @@ end
124
124
function MOI. get (
125
125
model:: MOI.ModelLike ,
126
126
a:: Union{MOI.ConstraintDual,MOI.ConstraintDualStart} ,
127
- bridge:: _AbstractSlackBridge ,
128
- )
127
+ bridge:: _AbstractSlackBridge{T} ,
128
+ ) where {T}
129
129
# The dual constraint on slack (since it is free) is
130
- # -dual_slack_in_set + dual_equality = 0 so the two duals are
131
- # equal and we can return either one of them.
132
- return MOI. get (model, a, bridge. slack_in_set)
130
+ # `-dual_slack_in_set + dual_equality = 0` so the two duals are
131
+ # equal (modulo a rescaling for things like symmetric matrices) and we can
132
+ # return either one of them.
133
+ #
134
+ # We decide to use the dual of the equality constraints because the
135
+ # `slack_in_set` constraint might be bridged by a variable bridge that does
136
+ # not support `ConstraintDual`. This is the case if the adjoint of the
137
+ # linear map on which the bridge is based is not invertible, for example,
138
+ # `Variable.ZerosBridge` or `SumOfSquares.Bridges.Variable.KernelBridge`.
139
+ dual = MOI. get (model, a, bridge. equality)
140
+ if dual === nothing
141
+ return nothing
142
+ elseif dual isa AbstractVector
143
+ # The equality constraints gives the term <dual, primal> with the
144
+ # standard inner product but <dual, primal>_PSD is like scaling each
145
+ # entry of dual and primal by the entry of SetDotScalingVector. To undo,
146
+ # we need to divide by the square.
147
+ scale = MOI. Utilities. SetDotScalingVector {T} (bridge. set)
148
+ return dual ./ scale .^ 2
149
+ end
150
+ return dual
133
151
end
134
152
135
153
function MOI. set (
136
154
model:: MOI.ModelLike ,
137
155
attr:: MOI.ConstraintDualStart ,
138
- bridge:: _AbstractSlackBridge ,
156
+ bridge:: _AbstractSlackBridge{T} ,
139
157
value,
140
- )
141
- # As the slack appears `+slack` in `slack_in_set` and `-slack` in equality,
142
- # giving `value` to both will cancel it out in the Lagrangian.
143
- # Giving `value` to `bridge.equality` will put the function in the
144
- # Lagrangian as expected.
158
+ ) where {T}
159
+ # See comments in MOI.get for why we need to rescale, etc.
145
160
MOI. set (model, attr, bridge. slack_in_set, value)
146
- MOI. set (model, attr, bridge. equality, value)
161
+ if value isa AbstractVector
162
+ scale = MOI. Utilities. SetDotScalingVector {T} (bridge. set)
163
+ MOI. set (model, attr, bridge. equality, value .* scale .^ 2 )
164
+ else
165
+ MOI. set (model, attr, bridge. equality, value)
166
+ end
147
167
return
148
168
end
149
169
209
229
struct ScalarSlackBridge{T,F,S} < :
210
230
_AbstractSlackBridge{T,MOI. VariableIndex,MOI. EqualTo{T},F,S}
211
231
slack:: MOI.VariableIndex
232
+ set:: S
212
233
slack_in_set:: MOI.ConstraintIndex{MOI.VariableIndex,S}
213
234
equality:: MOI.ConstraintIndex{F,MOI.EqualTo{T}}
214
235
end
@@ -226,7 +247,7 @@ function bridge_constraint(
226
247
slack, slack_in_set = MOI. add_constrained_variable (model, s)
227
248
new_f = MOI. Utilities. operate (- , T, f, slack)
228
249
equality = MOI. add_constraint (model, new_f, MOI. EqualTo (zero (T)))
229
- return ScalarSlackBridge {T,F,S} (slack, slack_in_set, equality)
250
+ return ScalarSlackBridge {T,F,S} (slack, s, slack_in_set, equality)
230
251
end
231
252
232
253
# Start by allowing all scalar constraints:
341
362
struct VectorSlackBridge{T,F,S} < :
342
363
_AbstractSlackBridge{T,MOI. VectorOfVariables,MOI. Zeros,F,S}
343
364
slack:: Vector{MOI.VariableIndex}
365
+ set:: S
344
366
slack_in_set:: MOI.ConstraintIndex{MOI.VectorOfVariables,S}
345
367
equality:: MOI.ConstraintIndex{F,MOI.Zeros}
346
368
end
@@ -358,7 +380,7 @@ function bridge_constraint(
358
380
slack, slack_in_set = MOI. add_constrained_variables (model, s)
359
381
new_f = MOI. Utilities. operate (- , T, f, MOI. VectorOfVariables (slack))
360
382
equality = MOI. add_constraint (model, new_f, MOI. Zeros (d))
361
- return VectorSlackBridge {T,F,S} (slack, slack_in_set, equality)
383
+ return VectorSlackBridge {T,F,S} (slack, s, slack_in_set, equality)
362
384
end
363
385
364
386
function MOI. supports_constraint (
0 commit comments