55# in the LICENSE.md file or at https://opensource.org/licenses/MIT.
66
77"""
8- FeasibilityRelaxation(
9- penalties = Dict{MOI.ConstraintIndex,Float64}(),
8+ PenaltyRelaxation(
9+ penalties = Dict{MOI.ConstraintIndex,Float64}();
10+ default::Union{Nothing,T} = 1.0,
1011 )
1112
1213A problem modifier that, when passed to [`MOI.modify`](@ref), destructively
13- modifies the model in-place to create a feasibility relaxation.
14+ modifies the model in-place to create a penalized relaxation of the constraints .
1415
1516!!! warning
1617 This is a destructive routine that modifies the model in-place. If you don't
@@ -19,26 +20,33 @@ modifies the model in-place to create a feasibility relaxation.
1920
2021## Reformulation
2122
22- The feasibility relaxation modifies constraints of the form ``f(x) \\ in S`` into
23+ The penalty relaxation modifies constraints of the form ``f(x) \\ in S`` into
2324``f(x) + y - z \\ in S``, where ``y, z \\ ge 0``, and then it introduces a penalty
2425term into the objective of ``a \\ times (y + z)`` (if minimizing, else ``-a``),
2526where `a` is the value in the `penalties` dictionary associated with the
26- constraint that is being relaxed. If no value exists, the default is `1.0 `.
27+ constraint that is being relaxed. If no value exists, the default is `default `.
2728
2829When `S` is [`MOI.LessThan`](@ref) or [`MOI.GreaterThan`](@ref), we omit `y` or
2930`z` respectively as a performance optimization.
3031
32+ ## Relax a subset of constraints
33+
34+ To relax a subset of constraints, pass a `penalties` dictionary` and set
35+ `default = nothing`.
36+
3137## Supported constraint types
3238
33- The feasibility relaxation is currently limited to modifying
39+ The penalty relaxation is currently limited to modifying
3440[`MOI.ScalarAffineFunction`](@ref) and [`MOI.ScalarQuadraticFunction`](@ref)
3541constraints in the linear sets [`MOI.LessThan`](@ref), [`MOI.GreaterThan`](@ref),
3642[`MOI.EqualTo`](@ref) and [`MOI.Interval`](@ref).
3743
3844It does not include variable bound or integrality constraints, because these
3945cannot be modified in-place.
4046
41- ## Example
47+ To modify variable bounds, rewrite them as linear constraints.
48+
49+ ## Examples
4250
4351```jldoctest; setup=:(import MathOptInterface; const MOI = MathOptInterface)
4452julia> model = MOI.Utilities.Model{Float64}();
@@ -47,90 +55,118 @@ julia> x = MOI.add_variable(model);
4755
4856julia> c = MOI.add_constraint(model, 1.0 * x, MOI.LessThan(2.0));
4957
50- julia> MOI.modify(model, MOI.Utilities.FeasibilityRelaxation(Dict(c => 2.0) ))
58+ julia> MOI.modify(model, MOI.Utilities.PenaltyRelaxation(default = 2.0))
5159
5260julia> print(model)
5361Minimize ScalarAffineFunction{Float64}:
5462 0.0 + 2.0 v[2]
5563
5664Subject to:
5765
66+ ScalarAffineFunction{Float64}-in-LessThan{Float64}
67+ 0.0 + 1.0 v[1] - 1.0 v[2] <= 2.0
68+
69+ VariableIndex-in-GreaterThan{Float64}
70+ v[2] >= 0.0
71+ ```
72+
73+ ```jldoctest; setup=:(import MathOptInterface; const MOI = MathOptInterface)
74+ julia> model = MOI.Utilities.Model{Float64}();
75+
76+ julia> x = MOI.add_variable(model);
77+
78+ julia> c = MOI.add_constraint(model, 1.0 * x, MOI.LessThan(2.0));
79+
80+ julia> MOI.modify(model, MOI.Utilities.PenaltyRelaxation(Dict(c => 3.0)))
81+
82+ julia> print(model)
83+ Minimize ScalarAffineFunction{Float64}:
84+ 0.0 + 3.0 v[2]
85+
86+ Subject to:
87+
5888ScalarAffineFunction{Float64}-in-LessThan{Float64}
5989 0.0 + 1.0 v[1] - 1.0 v[2] <= 2.0
6090
6191VariableIndex-in-GreaterThan{Float64}
6292 v[2] >= 0.0
6393```
6494"""
65- mutable struct FeasibilityRelaxation{T}
95+ mutable struct PenaltyRelaxation{T}
96+ default:: Union{Nothing,T}
6697 penalties:: Dict{MOI.ConstraintIndex,T}
67- scale:: T
68- function FeasibilityRelaxation(p:: Dict{MOI.ConstraintIndex,T} ) where {T}
69- return new{T}(p, zero(T))
98+
99+ function PenaltyRelaxation(
100+ p:: Dict{MOI.ConstraintIndex,T} ;
101+ default:: T = one(T),
102+ ) where {T}
103+ return new{T}(default, p)
70104 end
71105end
72106
73- function FeasibilityRelaxation( )
74- return FeasibilityRelaxation (Dict{MOI. ConstraintIndex,Float64}())
107+ function PenaltyRelaxation(; kwargs ... )
108+ return PenaltyRelaxation (Dict{MOI. ConstraintIndex,Float64}(); kwargs ... )
75109end
76110
77- function FeasibilityRelaxation(d:: Dict{<:MOI.ConstraintIndex,T} ) where {T}
78- return FeasibilityRelaxation(convert(Dict{MOI. ConstraintIndex,T}, d))
111+ function PenaltyRelaxation(
112+ d:: Dict{<:MOI.ConstraintIndex,T} ;
113+ kwargs... ,
114+ ) where {T}
115+ return PenaltyRelaxation(convert(Dict{MOI. ConstraintIndex,T}, d); kwargs... )
79116end
80117
81118function MOI. modify(
82119 model:: MOI.ModelLike ,
83- relax:: FeasibilityRelaxation {T} ,
120+ relax:: PenaltyRelaxation {T} ,
84121) where {T}
85122 sense = MOI. get(model, MOI. ObjectiveSense())
86123 if sense == MOI. FEASIBILITY_SENSE
87- relax. scale = one(T)
88124 MOI. set(model, MOI. ObjectiveSense(), MOI. MIN_SENSE)
89125 f = zero(MOI. ScalarAffineFunction{T})
90126 MOI. set(model, MOI. ObjectiveFunction{typeof(f)}(), f)
91- elseif sense == MOI. MIN_SENSE
92- relax. scale = one(T)
93- elseif sense == MOI. MAX_SENSE
94- relax. scale = - one(T)
95127 end
96128 for (F, S) in MOI. get(model, MOI. ListOfConstraintTypesPresent())
97- _modify_feasibility_relaxation (model, relax, F, S)
129+ _modify_penalty_relaxation (model, relax, F, S)
98130 end
99131 return
100132end
101133
102- function _modify_feasibility_relaxation (
134+ function _modify_penalty_relaxation (
103135 model:: MOI.ModelLike ,
104- relax:: FeasibilityRelaxation ,
136+ relax:: PenaltyRelaxation ,
105137 :: Type{F} ,
106138 :: Type{S} ,
107139) where {F,S}
108140 for ci in MOI. get(model, MOI. ListOfConstraintIndices{F,S}())
109- MOI. modify(model, ci, relax)
141+ if relax. default != = nothing || haskey(relax. penalties, ci)
142+ MOI. modify(model, ci, relax)
143+ end
110144 end
111145 return
112146end
113147
114148function MOI. modify(
115149 :: MOI.ModelLike ,
116150 :: MOI.ConstraintIndex ,
117- :: FeasibilityRelaxation ,
151+ :: PenaltyRelaxation ,
118152)
119153 return # Silently skip modifying other constraint types.
120154end
121155
122156function MOI. modify(
123157 model:: MOI.ModelLike ,
124158 ci:: MOI.ConstraintIndex{F,<:MOI.AbstractScalarSet} ,
125- relax:: FeasibilityRelaxation {T} ,
159+ relax:: PenaltyRelaxation {T} ,
126160) where {T,F<: Union{MOI.ScalarAffineFunction{T},MOI.ScalarQuadraticFunction{T}} }
127161 y = MOI. add_variable(model)
128162 z = MOI. add_variable(model)
129163 MOI. add_constraint(model, y, MOI. GreaterThan(zero(T)))
130164 MOI. add_constraint(model, z, MOI. GreaterThan(zero(T)))
131165 MOI. modify(model, ci, MOI. ScalarCoefficientChange(y, one(T)))
132166 MOI. modify(model, ci, MOI. ScalarCoefficientChange(z, - one(T)))
133- a = relax. scale * get(relax. penalties, ci, one(T))
167+ sense = MOI. get(model, MOI. ObjectiveSense())
168+ scale = sense == MOI. MIN_SENSE ? one(T) : - one(T)
169+ a = scale * get(relax. penalties, ci, relax. default)
134170 O = MOI. get(model, MOI. ObjectiveFunctionType())
135171 obj = MOI. ObjectiveFunction{O}()
136172 MOI. modify(model, obj, MOI. ScalarCoefficientChange(y, a))
@@ -141,13 +177,15 @@ end
141177function MOI. modify(
142178 model:: MOI.ModelLike ,
143179 ci:: MOI.ConstraintIndex{F,MOI.GreaterThan{T}} ,
144- relax:: FeasibilityRelaxation {T} ,
180+ relax:: PenaltyRelaxation {T} ,
145181) where {T,F<: Union{MOI.ScalarAffineFunction{T},MOI.ScalarQuadraticFunction{T}} }
146182 # Performance optimization: we don't need the z relaxation variable.
147183 y = MOI. add_variable(model)
148184 MOI. add_constraint(model, y, MOI. GreaterThan(zero(T)))
149185 MOI. modify(model, ci, MOI. ScalarCoefficientChange(y, one(T)))
150- a = relax. scale * get(relax. penalties, ci, one(T))
186+ sense = MOI. get(model, MOI. ObjectiveSense())
187+ scale = sense == MOI. MIN_SENSE ? one(T) : - one(T)
188+ a = scale * get(relax. penalties, ci, relax. default)
151189 O = MOI. get(model, MOI. ObjectiveFunctionType())
152190 obj = MOI. ObjectiveFunction{O}()
153191 MOI. modify(model, obj, MOI. ScalarCoefficientChange(y, a))
@@ -157,13 +195,15 @@ end
157195function MOI. modify(
158196 model:: MOI.ModelLike ,
159197 ci:: MOI.ConstraintIndex{F,MOI.LessThan{T}} ,
160- relax:: FeasibilityRelaxation {T} ,
198+ relax:: PenaltyRelaxation {T} ,
161199) where {T,F<: Union{MOI.ScalarAffineFunction{T},MOI.ScalarQuadraticFunction{T}} }
162200 # Performance optimization: we don't need the y relaxation variable.
163201 z = MOI. add_variable(model)
164202 MOI. add_constraint(model, z, MOI. GreaterThan(zero(T)))
165203 MOI. modify(model, ci, MOI. ScalarCoefficientChange(z, - one(T)))
166- a = relax. scale * get(relax. penalties, ci, one(T))
204+ sense = MOI. get(model, MOI. ObjectiveSense())
205+ scale = sense == MOI. MIN_SENSE ? one(T) : - one(T)
206+ a = scale * get(relax. penalties, ci, relax. default)
167207 O = MOI. get(model, MOI. ObjectiveFunctionType())
168208 obj = MOI. ObjectiveFunction{O}()
169209 MOI. modify(model, obj, MOI. ScalarCoefficientChange(z, a))
0 commit comments