@@ -71,162 +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
8483function _add_penalty_to_objective (
8584 model:: MOI.ModelLike ,
8685 :: Type{F} ,
87- penalty:: T ,
88- x:: Vector{MOI.VariableIndex} ,
89- ) where {T,F<: MOI.VariableIndex }
90- g = MOI. ScalarAffineFunction (MOI. ScalarAffineTerm .(penalty, x), zero (T))
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+ }
9196 f = MOI. get (model, MOI. ObjectiveFunction {F} ())
92- push! (g. terms, MOI. ScalarAffineTerm (one (T), f))
93- MOI. set (model, MOI. ObjectiveFunction {typeof(g)} (), g)
94- return MOI. ScalarAffineFunction (MOI. ScalarAffineTerm .(one (T), x), zero (T))
95- end
96-
97- function _add_penalty_to_objective (
98- model:: MOI.ModelLike ,
99- :: Type{F} ,
100- penalty:: T ,
101- x:: Vector{MOI.VariableIndex} ,
102- ) where {T,F<: Union{MOI.ScalarAffineFunction{T},MOI.ScalarQuadraticFunction{T}} }
103- obj = MOI. ObjectiveFunction {F} ()
104- for xi in x
105- MOI. modify (model, obj, MOI. ScalarCoefficientChange (xi, penalty))
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)
106101 end
107- return MOI. ScalarAffineFunction (MOI. ScalarAffineTerm .(one (T), x), zero (T))
108- end
109-
110- function _add_penalty_to_objective (
111- model:: MOI.ModelLike ,
112- :: Type{F} ,
113- penalty:: T ,
114- x:: Vector{MOI.VariableIndex} ,
115- ) where {T,F<: MOI.ScalarNonlinearFunction }
116- attr = MOI. ObjectiveFunction {F} ()
117- f = MOI. get (model, attr)
118- g = Any[MOI. ScalarNonlinearFunction (:* , Any[penalty, xi]) for xi in x]
119- MOI. set (model, attr, MOI. ScalarNonlinearFunction (:+ , vcat (f, g)))
120- return MOI. ScalarAffineFunction (MOI. ScalarAffineTerm .(one (T), x), zero (T))
102+ MOI. set (model, MOI. ObjectiveFunction {typeof(g)} (), g)
103+ return
121104end
122105
123106function _add_penalty_to_objective (
124107 :: MOI.ModelLike ,
125108 :: Type{F} ,
126- :: T ,
127- :: Vector{MOI.VariableIndex} ,
128- ) where {T,F}
109+ :: MOI.ScalarAffineFunction ,
110+ ) where {F}
129111 return error (
130112 " Cannot perform `ScalarPenaltyRelaxation` with an objective function of type `$F `" ,
131113 )
132114end
133115
134- function MOI. modify (
116+ function _relax_constraint (
117+ :: Type{T} ,
135118 model:: MOI.ModelLike ,
136119 ci:: MOI.ConstraintIndex{F,<:MOI.AbstractScalarSet} ,
137- relax:: ScalarPenaltyRelaxation{T} ,
138120) where {T,F<: Union{MOI.ScalarAffineFunction{T},MOI.ScalarQuadraticFunction{T}} }
139- sense = _change_sense_to_min_if_necessary (T, model)
140- y = MOI. add_variable (model)
141- z = MOI. add_variable (model)
142- MOI. add_constraint (model, y, MOI. GreaterThan (zero (T)))
143- MOI. add_constraint (model, z, MOI. GreaterThan (zero (T)))
144- MOI. modify (model, ci, MOI. ScalarCoefficientChange (y, one (T)))
145- MOI. modify (model, ci, MOI. ScalarCoefficientChange (z, - one (T)))
146- penalty = sense == MOI. MIN_SENSE ? relax. penalty : - relax. penalty
147- O = MOI. get (model, MOI. ObjectiveFunctionType ())
148- return _add_penalty_to_objective (model, O, penalty, [y, 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
149126end
150127
151- function MOI. modify (
128+ function _relax_constraint (
129+ :: Type{T} ,
152130 model:: MOI.ModelLike ,
153131 ci:: MOI.ConstraintIndex{F,MOI.GreaterThan{T}} ,
154- relax:: ScalarPenaltyRelaxation{T} ,
155132) where {T,F<: Union{MOI.ScalarAffineFunction{T},MOI.ScalarQuadraticFunction{T}} }
156- sense = _change_sense_to_min_if_necessary (T, model)
157- # Performance optimization: we don't need the z relaxation variable.
158- y = MOI. add_variable (model)
159- MOI. add_constraint (model, y, MOI. GreaterThan (zero (T)))
160- MOI. modify (model, ci, MOI. ScalarCoefficientChange (y, one (T)))
161- penalty = sense == MOI. MIN_SENSE ? relax. penalty : - relax. penalty
162- O = MOI. get (model, MOI. ObjectiveFunctionType ())
163- return _add_penalty_to_objective (model, O, penalty, [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]
164137end
165138
166- function MOI. modify (
139+ function _relax_constraint (
140+ :: Type{T} ,
167141 model:: MOI.ModelLike ,
168142 ci:: MOI.ConstraintIndex{F,MOI.LessThan{T}} ,
169- relax:: ScalarPenaltyRelaxation{T} ,
170143) where {T,F<: Union{MOI.ScalarAffineFunction{T},MOI.ScalarQuadraticFunction{T}} }
171- sense = _change_sense_to_min_if_necessary (T, model)
172- # Performance optimization: we don't need the y relaxation variable.
173- z = MOI. add_variable (model)
174- MOI. add_constraint (model, z, MOI. GreaterThan (zero (T)))
175- MOI. modify (model, ci, MOI. ScalarCoefficientChange (z, - one (T)))
176- penalty = sense == MOI. MIN_SENSE ? relax. penalty : - relax. penalty
177- O = MOI. get (model, MOI. ObjectiveFunctionType ())
178- return _add_penalty_to_objective (model, O, penalty, [z])
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]
179148end
180149
181- function MOI. modify (
150+ function _relax_constraint (
151+ :: Type{T} ,
182152 model:: MOI.ModelLike ,
183153 ci:: MOI.ConstraintIndex{MOI.ScalarNonlinearFunction,S} ,
184- relax:: ScalarPenaltyRelaxation{T} ,
185154) where {T,S<: MOI.AbstractScalarSet }
186- sense = _change_sense_to_min_if_necessary (T, model )
155+ x, _ = MOI . add_constrained_variable (model, MOI . GreaterThan ( zero (T)) )
187156 y, _ = MOI. add_constrained_variable (model, MOI. GreaterThan (zero (T)))
188- z, _ = MOI. add_constrained_variable (model, MOI. GreaterThan (zero (T)))
189157 f = MOI. get (model, MOI. ConstraintFunction (), ci)
190- f = MOI. ScalarNonlinearFunction (
158+ g = MOI. ScalarNonlinearFunction (
191159 :+ ,
192- Any[f, y , MOI. ScalarNonlinearFunction (:- , Any[z ])],
160+ Any[f, x , MOI. ScalarNonlinearFunction (:- , Any[y ])],
193161 )
194- MOI. set (model, MOI. ConstraintFunction (), ci, f)
195- penalty = sense == MOI. MIN_SENSE ? relax. penalty : - relax. penalty
196- O = MOI. get (model, MOI. ObjectiveFunctionType ())
197- return _add_penalty_to_objective (model, O, penalty, [y, z])
162+ MOI. set (model, MOI. ConstraintFunction (), ci, g)
163+ return [x, y]
198164end
199165
200- function MOI. modify (
166+ function _relax_constraint (
167+ :: Type{T} ,
201168 model:: MOI.ModelLike ,
202169 ci:: MOI.ConstraintIndex{MOI.ScalarNonlinearFunction,MOI.GreaterThan{T}} ,
203- relax:: ScalarPenaltyRelaxation{T} ,
204170) where {T}
205- sense = _change_sense_to_min_if_necessary (T, model)
206- y = MOI. add_variable (model)
207- MOI. add_constraint (model, y, MOI. GreaterThan (zero (T)))
208- func = MOI. get (model, MOI. ConstraintFunction (), ci)
209- newfunc = MOI. ScalarNonlinearFunction (:+ , [func, y])
210- MOI. set (model, MOI. ConstraintFunction (), ci, newfunc)
211- penalty = sense == MOI. MIN_SENSE ? relax. penalty : - relax. penalty
212- O = MOI. get (model, MOI. ObjectiveFunctionType ())
213- return _add_penalty_to_objective (model, O, penalty, [y])
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]
214176end
215177
216- function MOI. modify (
178+ function _relax_constraint (
179+ :: Type{T} ,
217180 model:: MOI.ModelLike ,
218181 ci:: MOI.ConstraintIndex{MOI.ScalarNonlinearFunction,MOI.LessThan{T}} ,
219- relax:: ScalarPenaltyRelaxation{T} ,
220182) where {T}
221- sense = _change_sense_to_min_if_necessary (T, model)
222- z = MOI. add_variable (model)
223- MOI. add_constraint (model, z, MOI. GreaterThan (zero (T)))
224- func = MOI. get (model, MOI. ConstraintFunction (), ci)
225- newfunc = MOI. ScalarNonlinearFunction (:- , [func, z])
226- MOI. set (model, MOI. ConstraintFunction (), ci, newfunc)
227- penalty = sense == MOI. MIN_SENSE ? relax. penalty : - relax. penalty
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)
228208 O = MOI. get (model, MOI. ObjectiveFunctionType ())
229- return _add_penalty_to_objective (model, O, penalty, [z])
209+ _add_penalty_to_objective (model, O, p)
210+ return MOI. ScalarAffineFunction (MOI. ScalarAffineTerm .(one (T), x), zero (T))
230211end
231212
232213"""
@@ -361,13 +342,20 @@ end
361342
362343function MOI. modify (model:: MOI.ModelLike , relax:: PenaltyRelaxation{T} ) where {T}
363344 map = Dict {MOI.ConstraintIndex,MOI.ScalarAffineFunction{T}} ()
345+ penalty_expr = zero (MOI. ScalarAffineFunction{T})
364346 for (F, S) in MOI. get (model, MOI. ListOfConstraintTypesPresent ())
365- _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)
366353 end
367354 return map
368355end
369356
370357function _modify_penalty_relaxation (
358+ penalty_expr:: MOI.ScalarAffineFunction{T} ,
371359 map:: Dict{MOI.ConstraintIndex,MOI.ScalarAffineFunction{T}} ,
372360 model:: MOI.ModelLike ,
373361 relax:: PenaltyRelaxation ,
@@ -380,9 +368,14 @@ function _modify_penalty_relaxation(
380368 continue
381369 end
382370 try
383- 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))
384377 catch err
385- if err isa MethodError && err. f == MOI . modify
378+ if err isa MethodError && err. f == _relax_constraint
386379 if relax. warn
387380 @warn (
388381 " Skipping PenaltyRelaxation for ConstraintIndex{$F ,$S }"
0 commit comments