5
5
# in the LICENSE.md file or at https://opensource.org/licenses/MIT.
6
6
7
7
"""
8
- FeasibilityRelaxation(
9
- penalties = Dict{MOI.ConstraintIndex,Float64}(),
8
+ PenaltyRelaxation(
9
+ penalties = Dict{MOI.ConstraintIndex,Float64}();
10
+ default::Union{Nothing,T} = 1.0,
10
11
)
11
12
12
13
A 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 .
14
15
15
16
!!! warning
16
17
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.
19
20
20
21
## Reformulation
21
22
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
23
24
``f(x) + y - z \\ in S``, where ``y, z \\ ge 0``, and then it introduces a penalty
24
25
term into the objective of ``a \\ times (y + z)`` (if minimizing, else ``-a``),
25
26
where `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 `.
27
28
28
29
When `S` is [`MOI.LessThan`](@ref) or [`MOI.GreaterThan`](@ref), we omit `y` or
29
30
`z` respectively as a performance optimization.
30
31
32
+ ## Relax a subset of constraints
33
+
34
+ To relax a subset of constraints, pass a `penalties` dictionary` and set
35
+ `default = nothing`.
36
+
31
37
## Supported constraint types
32
38
33
- The feasibility relaxation is currently limited to modifying
39
+ The penalty relaxation is currently limited to modifying
34
40
[`MOI.ScalarAffineFunction`](@ref) and [`MOI.ScalarQuadraticFunction`](@ref)
35
41
constraints in the linear sets [`MOI.LessThan`](@ref), [`MOI.GreaterThan`](@ref),
36
42
[`MOI.EqualTo`](@ref) and [`MOI.Interval`](@ref).
37
43
38
44
It does not include variable bound or integrality constraints, because these
39
45
cannot be modified in-place.
40
46
41
- ## Example
47
+ To modify variable bounds, rewrite them as linear constraints.
48
+
49
+ ## Examples
42
50
43
51
```jldoctest; setup=:(import MathOptInterface; const MOI = MathOptInterface)
44
52
julia> model = MOI.Utilities.Model{Float64}();
@@ -47,90 +55,118 @@ julia> x = MOI.add_variable(model);
47
55
48
56
julia> c = MOI.add_constraint(model, 1.0 * x, MOI.LessThan(2.0));
49
57
50
- julia> MOI.modify(model, MOI.Utilities.FeasibilityRelaxation(Dict(c => 2.0) ))
58
+ julia> MOI.modify(model, MOI.Utilities.PenaltyRelaxation(default = 2.0))
51
59
52
60
julia> print(model)
53
61
Minimize ScalarAffineFunction{Float64}:
54
62
0.0 + 2.0 v[2]
55
63
56
64
Subject to:
57
65
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
+
58
88
ScalarAffineFunction{Float64}-in-LessThan{Float64}
59
89
0.0 + 1.0 v[1] - 1.0 v[2] <= 2.0
60
90
61
91
VariableIndex-in-GreaterThan{Float64}
62
92
v[2] >= 0.0
63
93
```
64
94
"""
65
- mutable struct FeasibilityRelaxation{T}
95
+ mutable struct PenaltyRelaxation{T}
96
+ default:: Union{Nothing,T}
66
97
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)
70
104
end
71
105
end
72
106
73
- function FeasibilityRelaxation ( )
74
- return FeasibilityRelaxation (Dict {MOI.ConstraintIndex,Float64} ())
107
+ function PenaltyRelaxation (; kwargs ... )
108
+ return PenaltyRelaxation (Dict {MOI.ConstraintIndex,Float64} (); kwargs ... )
75
109
end
76
110
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... )
79
116
end
80
117
81
118
function MOI. modify (
82
119
model:: MOI.ModelLike ,
83
- relax:: FeasibilityRelaxation {T} ,
120
+ relax:: PenaltyRelaxation {T} ,
84
121
) where {T}
85
122
sense = MOI. get (model, MOI. ObjectiveSense ())
86
123
if sense == MOI. FEASIBILITY_SENSE
87
- relax. scale = one (T)
88
124
MOI. set (model, MOI. ObjectiveSense (), MOI. MIN_SENSE)
89
125
f = zero (MOI. ScalarAffineFunction{T})
90
126
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)
95
127
end
96
128
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)
98
130
end
99
131
return
100
132
end
101
133
102
- function _modify_feasibility_relaxation (
134
+ function _modify_penalty_relaxation (
103
135
model:: MOI.ModelLike ,
104
- relax:: FeasibilityRelaxation ,
136
+ relax:: PenaltyRelaxation ,
105
137
:: Type{F} ,
106
138
:: Type{S} ,
107
139
) where {F,S}
108
140
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
110
144
end
111
145
return
112
146
end
113
147
114
148
function MOI. modify (
115
149
:: MOI.ModelLike ,
116
150
:: MOI.ConstraintIndex ,
117
- :: FeasibilityRelaxation ,
151
+ :: PenaltyRelaxation ,
118
152
)
119
153
return # Silently skip modifying other constraint types.
120
154
end
121
155
122
156
function MOI. modify (
123
157
model:: MOI.ModelLike ,
124
158
ci:: MOI.ConstraintIndex{F,<:MOI.AbstractScalarSet} ,
125
- relax:: FeasibilityRelaxation {T} ,
159
+ relax:: PenaltyRelaxation {T} ,
126
160
) where {T,F<: Union{MOI.ScalarAffineFunction{T},MOI.ScalarQuadraticFunction{T}} }
127
161
y = MOI. add_variable (model)
128
162
z = MOI. add_variable (model)
129
163
MOI. add_constraint (model, y, MOI. GreaterThan (zero (T)))
130
164
MOI. add_constraint (model, z, MOI. GreaterThan (zero (T)))
131
165
MOI. modify (model, ci, MOI. ScalarCoefficientChange (y, one (T)))
132
166
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)
134
170
O = MOI. get (model, MOI. ObjectiveFunctionType ())
135
171
obj = MOI. ObjectiveFunction {O} ()
136
172
MOI. modify (model, obj, MOI. ScalarCoefficientChange (y, a))
@@ -141,13 +177,15 @@ end
141
177
function MOI. modify (
142
178
model:: MOI.ModelLike ,
143
179
ci:: MOI.ConstraintIndex{F,MOI.GreaterThan{T}} ,
144
- relax:: FeasibilityRelaxation {T} ,
180
+ relax:: PenaltyRelaxation {T} ,
145
181
) where {T,F<: Union{MOI.ScalarAffineFunction{T},MOI.ScalarQuadraticFunction{T}} }
146
182
# Performance optimization: we don't need the z relaxation variable.
147
183
y = MOI. add_variable (model)
148
184
MOI. add_constraint (model, y, MOI. GreaterThan (zero (T)))
149
185
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)
151
189
O = MOI. get (model, MOI. ObjectiveFunctionType ())
152
190
obj = MOI. ObjectiveFunction {O} ()
153
191
MOI. modify (model, obj, MOI. ScalarCoefficientChange (y, a))
@@ -157,13 +195,15 @@ end
157
195
function MOI. modify (
158
196
model:: MOI.ModelLike ,
159
197
ci:: MOI.ConstraintIndex{F,MOI.LessThan{T}} ,
160
- relax:: FeasibilityRelaxation {T} ,
198
+ relax:: PenaltyRelaxation {T} ,
161
199
) where {T,F<: Union{MOI.ScalarAffineFunction{T},MOI.ScalarQuadraticFunction{T}} }
162
200
# Performance optimization: we don't need the y relaxation variable.
163
201
z = MOI. add_variable (model)
164
202
MOI. add_constraint (model, z, MOI. GreaterThan (zero (T)))
165
203
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)
167
207
O = MOI. get (model, MOI. ObjectiveFunctionType ())
168
208
obj = MOI. ObjectiveFunction {O} ()
169
209
MOI. modify (model, obj, MOI. ScalarCoefficientChange (z, a))
0 commit comments