@@ -71,71 +71,143 @@ function _change_sense_to_min_if_necessary(
7171 :: Type{T} ,
7272 model:: MOI.ModelLike ,
7373) where {T}
74- sense = MOI. get (model, MOI. ObjectiveSense ())
75- if sense != MOI. FEASIBILITY_SENSE
76- return sense
74+ if MOI. get (model, MOI. ObjectiveSense ()) != MOI. FEASIBILITY_SENSE
75+ return
7776 end
7877 MOI. set (model, MOI. ObjectiveSense (), MOI. MIN_SENSE)
7978 f = zero (MOI. ScalarAffineFunction{T})
8079 MOI. set (model, MOI. ObjectiveFunction {typeof(f)} (), f)
81- return MOI . MIN_SENSE
80+ return
8281end
8382
84- function MOI. modify (
83+ function _add_penalty_to_objective (
84+ model:: MOI.ModelLike ,
85+ :: Type{F} ,
86+ penalty:: MOI.ScalarAffineFunction{T} ,
87+ ) where {
88+ T,
89+ F<: Union {
90+ MOI. VariableIndex,
91+ MOI. ScalarAffineFunction{T},
92+ MOI. ScalarQuadraticFunction{T},
93+ MOI. ScalarNonlinearFunction,
94+ },
95+ }
96+ f = MOI. get (model, MOI. ObjectiveFunction {F} ())
97+ g = if MOI. get (model, MOI. ObjectiveSense ()) == MOI. MIN_SENSE
98+ MOI. Utilities. operate (+ , T, f, penalty)
99+ else
100+ MOI. Utilities. operate (- , T, f, penalty)
101+ end
102+ MOI. set (model, MOI. ObjectiveFunction {typeof(g)} (), g)
103+ return
104+ end
105+
106+ function _add_penalty_to_objective (
107+ :: MOI.ModelLike ,
108+ :: Type{F} ,
109+ :: MOI.ScalarAffineFunction ,
110+ ) where {F}
111+ return error (
112+ " Cannot perform `ScalarPenaltyRelaxation` with an objective function of type `$F `" ,
113+ )
114+ end
115+
116+ function _relax_constraint (
117+ :: Type{T} ,
85118 model:: MOI.ModelLike ,
86119 ci:: MOI.ConstraintIndex{F,<:MOI.AbstractScalarSet} ,
87- relax:: ScalarPenaltyRelaxation{T} ,
88120) where {T,F<: Union{MOI.ScalarAffineFunction{T},MOI.ScalarQuadraticFunction{T}} }
89- sense = _change_sense_to_min_if_necessary (T, model)
90- y = MOI. add_variable (model)
91- z = MOI. add_variable (model)
92- MOI. add_constraint (model, y, MOI. GreaterThan (zero (T)))
93- MOI. add_constraint (model, z, MOI. GreaterThan (zero (T)))
94- MOI. modify (model, ci, MOI. ScalarCoefficientChange (y, one (T)))
95- MOI. modify (model, ci, MOI. ScalarCoefficientChange (z, - one (T)))
96- scale = sense == MOI. MIN_SENSE ? one (T) : - one (T)
97- a = scale * relax. penalty
98- O = MOI. get (model, MOI. ObjectiveFunctionType ())
99- obj = MOI. ObjectiveFunction {O} ()
100- MOI. modify (model, obj, MOI. ScalarCoefficientChange (y, a))
101- MOI. modify (model, obj, MOI. ScalarCoefficientChange (z, a))
102- return one (T) * y + one (T) * z
121+ x = MOI. add_variables (model, 2 )
122+ MOI. add_constraint .(model, x, MOI. GreaterThan (zero (T)))
123+ MOI. modify (model, ci, MOI. ScalarCoefficientChange (x[1 ], one (T)))
124+ MOI. modify (model, ci, MOI. ScalarCoefficientChange (x[2 ], - one (T)))
125+ return x
103126end
104127
105- function MOI. modify (
128+ function _relax_constraint (
129+ :: Type{T} ,
106130 model:: MOI.ModelLike ,
107131 ci:: MOI.ConstraintIndex{F,MOI.GreaterThan{T}} ,
108- relax:: ScalarPenaltyRelaxation{T} ,
109132) where {T,F<: Union{MOI.ScalarAffineFunction{T},MOI.ScalarQuadraticFunction{T}} }
110- sense = _change_sense_to_min_if_necessary (T, model)
111- # Performance optimization: we don't need the z relaxation variable.
112- y = MOI. add_variable (model)
113- MOI. add_constraint (model, y, MOI. GreaterThan (zero (T)))
114- MOI. modify (model, ci, MOI. ScalarCoefficientChange (y, one (T)))
115- scale = sense == MOI. MIN_SENSE ? one (T) : - one (T)
116- a = scale * relax. penalty
117- O = MOI. get (model, MOI. ObjectiveFunctionType ())
118- obj = MOI. ObjectiveFunction {O} ()
119- MOI. modify (model, obj, MOI. ScalarCoefficientChange (y, a))
120- return one (T) * y
133+ x = MOI. add_variable (model)
134+ MOI. add_constraint (model, x, MOI. GreaterThan (zero (T)))
135+ MOI. modify (model, ci, MOI. ScalarCoefficientChange (x, one (T)))
136+ return [x]
121137end
122138
123- function MOI. modify (
139+ function _relax_constraint (
140+ :: Type{T} ,
124141 model:: MOI.ModelLike ,
125142 ci:: MOI.ConstraintIndex{F,MOI.LessThan{T}} ,
126- relax:: ScalarPenaltyRelaxation{T} ,
127143) where {T,F<: Union{MOI.ScalarAffineFunction{T},MOI.ScalarQuadraticFunction{T}} }
128- sense = _change_sense_to_min_if_necessary (T, model)
129- # Performance optimization: we don't need the y relaxation variable.
130- z = MOI. add_variable (model)
131- MOI. add_constraint (model, z, MOI. GreaterThan (zero (T)))
132- MOI. modify (model, ci, MOI. ScalarCoefficientChange (z, - one (T)))
133- scale = sense == MOI. MIN_SENSE ? one (T) : - one (T)
134- a = scale * relax. penalty
144+ x = MOI. add_variable (model)
145+ MOI. add_constraint (model, x, MOI. GreaterThan (zero (T)))
146+ MOI. modify (model, ci, MOI. ScalarCoefficientChange (x, - one (T)))
147+ return [x]
148+ end
149+
150+ function _relax_constraint (
151+ :: Type{T} ,
152+ model:: MOI.ModelLike ,
153+ ci:: MOI.ConstraintIndex{MOI.ScalarNonlinearFunction,S} ,
154+ ) where {T,S<: MOI.AbstractScalarSet }
155+ x, _ = MOI. add_constrained_variable (model, MOI. GreaterThan (zero (T)))
156+ y, _ = MOI. add_constrained_variable (model, MOI. GreaterThan (zero (T)))
157+ f = MOI. get (model, MOI. ConstraintFunction (), ci)
158+ g = MOI. ScalarNonlinearFunction (
159+ :+ ,
160+ Any[f, x, MOI. ScalarNonlinearFunction (:- , Any[y])],
161+ )
162+ MOI. set (model, MOI. ConstraintFunction (), ci, g)
163+ return [x, y]
164+ end
165+
166+ function _relax_constraint (
167+ :: Type{T} ,
168+ model:: MOI.ModelLike ,
169+ ci:: MOI.ConstraintIndex{MOI.ScalarNonlinearFunction,MOI.GreaterThan{T}} ,
170+ ) where {T}
171+ x, _ = MOI. add_constrained_variable (model, MOI. GreaterThan (zero (T)))
172+ f = MOI. get (model, MOI. ConstraintFunction (), ci)
173+ g = MOI. ScalarNonlinearFunction (:+ , [f, x])
174+ MOI. set (model, MOI. ConstraintFunction (), ci, g)
175+ return [x]
176+ end
177+
178+ function _relax_constraint (
179+ :: Type{T} ,
180+ model:: MOI.ModelLike ,
181+ ci:: MOI.ConstraintIndex{MOI.ScalarNonlinearFunction,MOI.LessThan{T}} ,
182+ ) where {T}
183+ x, _ = MOI. add_constrained_variable (model, MOI. GreaterThan (zero (T)))
184+ f = MOI. get (model, MOI. ConstraintFunction (), ci)
185+ g = MOI. ScalarNonlinearFunction (:- , [f, x])
186+ MOI. set (model, MOI. ConstraintFunction (), ci, g)
187+ return [x]
188+ end
189+
190+ function MOI. modify (
191+ model:: MOI.ModelLike ,
192+ ci:: MOI.ConstraintIndex{F,<:MOI.AbstractScalarSet} ,
193+ relax:: ScalarPenaltyRelaxation{T} ,
194+ ) where {
195+ T,
196+ F<: Union {
197+ MOI. ScalarAffineFunction{T},
198+ MOI. ScalarQuadraticFunction{T},
199+ MOI. ScalarNonlinearFunction,
200+ },
201+ }
202+ x = _relax_constraint (T, model, ci)
203+ p = MOI. ScalarAffineFunction (
204+ MOI. ScalarAffineTerm .(relax. penalty, x),
205+ zero (T),
206+ )
207+ _change_sense_to_min_if_necessary (T, model)
135208 O = MOI. get (model, MOI. ObjectiveFunctionType ())
136- obj = MOI. ObjectiveFunction {O} ()
137- MOI. modify (model, obj, MOI. ScalarCoefficientChange (z, a))
138- return one (T) * z
209+ _add_penalty_to_objective (model, O, p)
210+ return MOI. ScalarAffineFunction (MOI. ScalarAffineTerm .(one (T), x), zero (T))
139211end
140212
141213"""
@@ -270,13 +342,20 @@ end
270342
271343function MOI. modify (model:: MOI.ModelLike , relax:: PenaltyRelaxation{T} ) where {T}
272344 map = Dict {MOI.ConstraintIndex,MOI.ScalarAffineFunction{T}} ()
345+ penalty_expr = zero (MOI. ScalarAffineFunction{T})
273346 for (F, S) in MOI. get (model, MOI. ListOfConstraintTypesPresent ())
274- _modify_penalty_relaxation (map, model, relax, F, S)
347+ _modify_penalty_relaxation (penalty_expr, map, model, relax, F, S)
348+ end
349+ if ! isempty (penalty_expr. terms)
350+ _change_sense_to_min_if_necessary (T, model)
351+ O = MOI. get (model, MOI. ObjectiveFunctionType ())
352+ _add_penalty_to_objective (model, O, penalty_expr)
275353 end
276354 return map
277355end
278356
279357function _modify_penalty_relaxation (
358+ penalty_expr:: MOI.ScalarAffineFunction{T} ,
280359 map:: Dict{MOI.ConstraintIndex,MOI.ScalarAffineFunction{T}} ,
281360 model:: MOI.ModelLike ,
282361 relax:: PenaltyRelaxation ,
@@ -289,9 +368,14 @@ function _modify_penalty_relaxation(
289368 continue
290369 end
291370 try
292- map[ci] = MOI. modify (model, ci, ScalarPenaltyRelaxation (penalty))
371+ x = _relax_constraint (T, model, ci)
372+ map[ci] = MOI. ScalarAffineFunction (
373+ MOI. ScalarAffineTerm .(one (T), x),
374+ zero (T),
375+ )
376+ append! (penalty_expr. terms, MOI. ScalarAffineTerm {T} .(penalty, x))
293377 catch err
294- if err isa MethodError && err. f == MOI . modify
378+ if err isa MethodError && err. f == _relax_constraint
295379 if relax. warn
296380 @warn (
297381 " Skipping PenaltyRelaxation for ConstraintIndex{$F ,$S }"
0 commit comments