@@ -124,26 +124,46 @@ end
124124function  MOI. get (
125125    model:: MOI.ModelLike ,
126126    a:: Union{MOI.ConstraintDual,MOI.ConstraintDualStart} ,
127-     bridge:: _AbstractSlackBridge ,
128- )
127+     bridge:: _AbstractSlackBridge{T}  ,
128+ )  where  {T} 
129129    #  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
133151end 
134152
135153function  MOI. set (
136154    model:: MOI.ModelLike ,
137155    attr:: MOI.ConstraintDualStart ,
138-     bridge:: _AbstractSlackBridge ,
156+     bridge:: _AbstractSlackBridge{T}  ,
139157    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.
145160    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 
147167    return 
148168end 
149169
209229struct  ScalarSlackBridge{T,F,S} < :
210230       _AbstractSlackBridge{T,MOI. VariableIndex,MOI. EqualTo{T},F,S}
211231    slack:: MOI.VariableIndex 
232+     set:: S 
212233    slack_in_set:: MOI.ConstraintIndex{MOI.VariableIndex,S} 
213234    equality:: MOI.ConstraintIndex{F,MOI.EqualTo{T}} 
214235end 
@@ -226,7 +247,7 @@ function bridge_constraint(
226247    slack, slack_in_set =  MOI. add_constrained_variable (model, s)
227248    new_f =  MOI. Utilities. operate (- , T, f, slack)
228249    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)
230251end 
231252
232253#  Start by allowing all scalar constraints:
341362struct  VectorSlackBridge{T,F,S} < :
342363       _AbstractSlackBridge{T,MOI. VectorOfVariables,MOI. Zeros,F,S}
343364    slack:: Vector{MOI.VariableIndex} 
365+     set:: S 
344366    slack_in_set:: MOI.ConstraintIndex{MOI.VectorOfVariables,S} 
345367    equality:: MOI.ConstraintIndex{F,MOI.Zeros} 
346368end 
@@ -358,7 +380,7 @@ function bridge_constraint(
358380    slack, slack_in_set =  MOI. add_constrained_variables (model, s)
359381    new_f =  MOI. Utilities. operate (- , T, f, MOI. VectorOfVariables (slack))
360382    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)
362384end 
363385
364386function  MOI. supports_constraint (
0 commit comments