@@ -21,8 +21,7 @@ constraint.
2121The penalty relaxation modifies constraints of the form ``f(x) \\ in S`` into
2222``f(x) + y - z \\ in S``, where ``y, z \\ ge 0``, and then it introduces a penalty
2323term into the objective of ``a \\ times (y + z)`` (if minimizing, else ``-a``),
24- where `a` is the value in the `penalties` dictionary associated with the
25- constraint that is being relaxed. If no value exists, the default is `default`.
24+ where ``a`` is `penalty`
2625
2726When `S` is [`MOI.LessThan`](@ref) or [`MOI.GreaterThan`](@ref), we omit `y` or
2827`z` respectively as a performance optimization.
@@ -60,26 +59,14 @@ julia> f isa MOI.ScalarAffineFunction{Float64}
6059true
6160```
6261"""
63- struct ScalarPenaltyRelaxation{T}
62+ struct ScalarPenaltyRelaxation{T} # <: MOI.AbstractFunctionModification
63+ # We don't make this a subtype of AbstractFunctionModification to avoid some
64+ # ambiguities with generic methods in Utilities and Bridges. The underlying
65+ # reason is that these reformulations can be written using the high-level
66+ # MOI API, so we don't need special handling for bridges and utilities.
6467 penalty:: T
6568end
6669
67- function MOI. supports (
68- :: MOI.ModelLike ,
69- :: ScalarPenaltyRelaxation{T} ,
70- :: Type{<:MOI.ConstraintIndex{F,<:MOI.AbstractScalarSet}} ,
71- ) where {T,F<: Union{MOI.ScalarAffineFunction{T},MOI.ScalarQuadraticFunction{T}} }
72- return true
73- end
74-
75- function MOI. supports (
76- :: MOI.ModelLike ,
77- :: ScalarPenaltyRelaxation ,
78- :: Type{<:MOI.ConstraintIndex} ,
79- )
80- return false
81- end
82-
8370function _change_set_to_min_if_necessary (
8471 :: Type{T} ,
8572 model:: MOI.ModelLike ,
@@ -94,6 +81,15 @@ function _change_set_to_min_if_necessary(
9481 return MOI. MIN_SENSE
9582end
9683
84+ function MOI. modify (
85+ :: MOI.ModelLike ,
86+ :: MOI.ConstraintIndex ,
87+ :: ScalarPenaltyRelaxation ,
88+ )
89+ # A generic fallback if modification is not supported.
90+ return nothing
91+ end
92+
9793function MOI. modify (
9894 model:: MOI.ModelLike ,
9995 ci:: MOI.ConstraintIndex{F,<:MOI.AbstractScalarSet} ,
@@ -167,17 +163,13 @@ modifies the model in-place to create a penalized relaxation of the constraints.
167163
168164## Reformulation
169165
170- The penalty relaxation modifies constraints of the form ``f(x) \\ in S`` into
171- ``f(x) + y - z \\ in S``, where ``y, z \\ ge 0``, and then it introduces a penalty
172- term into the objective of ``a \\ times (y + z)`` (if minimizing, else ``-a``),
173- where `a` is the value in the `penalties` dictionary associated with the
174- constraint that is being relaxed.
166+ See [`Utilities.ScalarPenaltyRelaxation`](@ref) for details of the
167+ reformulation.
175168
176- If no value exists for the constraint in `penalties`, the penalty is `default`.
177- If `default` is also `nothing`, then the constraint is skipped.
178-
179- When `S` is [`MOI.LessThan`](@ref) or [`MOI.GreaterThan`](@ref), we omit `y` or
180- `z` respectively as a performance optimization.
169+ For each constraint `ci`, the penalty passed to [`Utilities.ScalarPenaltyRelaxation`](@ref)
170+ is `get(penalties, ci, default)`. If the value is `nothing`, because `ci` does
171+ not exist in `penalties` and `default = nothing`, then the constraint is
172+ skipped.
181173
182174## Return value
183175
@@ -299,12 +291,12 @@ function _modify_penalty_relaxation(
299291 if penalty === nothing
300292 continue
301293 end
302- attr = ScalarPenaltyRelaxation (penalty)
303- if ! MOI . supports (model, attr, MOI . ConstraintIndex{F,S})
304- @warn (" Skipping PenaltyRelaxation of constraints of type $F -in-$S " )
294+ delta = MOI . modify (model, ci, ScalarPenaltyRelaxation (penalty) )
295+ if delta === nothing
296+ @warn (" Skipping PenaltyRelaxation for constraints of type $F -in-$S " )
305297 return
306298 end
307- map[ci] = MOI . modify (model, ci, attr)
299+ map[ci] = delta
308300 end
309- return map
301+ return
310302end
0 commit comments