@@ -115,8 +115,11 @@ function MOI.delete(o::Optimizer, vi::MOI.VariableIndex)
115
115
throw (MOI. InvalidIndex (vi))
116
116
end
117
117
delete! (o. binbounds, vi)
118
+ delete! (o. bound_types, vi)
118
119
delete! (o. reference, var (o, vi))
119
120
delete (o. inner, VarRef (vi. value))
121
+ # FIXME (odow): delete the associated ConstraintIndex
122
+ delete! (o. bound_types, vi)
120
123
o. name_to_variable = nothing
121
124
return nothing
122
125
end
@@ -176,22 +179,11 @@ function MOI.add_constraint(o::Optimizer, vi::MOI.VariableIndex, ::MOI.ZeroOne)
176
179
v = var (o, vi)
177
180
p_infeas = Ref {SCIP_Bool} ()
178
181
@SCIP_CALL SCIPchgVarType (o, v, SCIP_VARTYPE_BINARY, p_infeas)
179
- # Need to adjust bounds for SCIP, which fails with an error otherwise.
180
- # Check for conflicts with existing bounds first:
181
182
lb, ub = SCIPvarGetLbOriginal (v), SCIPvarGetUbOriginal (v)
182
- if lb == - SCIPinfinity (o) && ub == SCIPinfinity (o)
183
- @SCIP_CALL SCIPchgVarLb (o, v, 0.0 )
184
- @SCIP_CALL SCIPchgVarUb (o, v, 1.0 )
185
- else
186
- # Store old bounds for later recovery.
187
- o. binbounds[vi] = MOI. Interval (lb, ub)
188
- if ub > 1.0
189
- @SCIP_CALL SCIPchgVarUb (o, v, 1.0 )
190
- end
191
- if lb < 0.0
192
- @SCIP_CALL SCIPchgVarLb (o, v, 0.0 )
193
- end
194
- end
183
+ # Store old bounds for later recovery.
184
+ o. binbounds[vi] = MOI. Interval (lb, ub)
185
+ @SCIP_CALL SCIPchgVarLb (o, v, max (lb, 0.0 ))
186
+ @SCIP_CALL SCIPchgVarUb (o, v, min (ub, 1.0 ))
195
187
ci = MOI. ConstraintIndex {MOI.VariableIndex,MOI.ZeroOne} (vi. value)
196
188
return register! (o, ci)
197
189
end
@@ -207,10 +199,9 @@ function MOI.delete(
207
199
p_infeas = Ref {SCIP_Bool} ()
208
200
@SCIP_CALL SCIPchgVarType (o, v, SCIP_VARTYPE_CONTINUOUS, p_infeas)
209
201
bounds = get (o. binbounds, vi, nothing )
210
- if bounds != = nothing
211
- @SCIP_CALL SCIPchgVarLb (o, v, bounds. lower)
212
- @SCIP_CALL SCIPchgVarUb (o, v, bounds. upper)
213
- end
202
+ @SCIP_CALL SCIPchgVarLb (o, v, bounds. lower)
203
+ @SCIP_CALL SCIPchgVarUb (o, v, bounds. upper)
204
+ delete! (o. binbounds, vi)
214
205
delete! (o. constypes[MOI. VariableIndex, MOI. ZeroOne], ConsRef (ci. value))
215
206
return nothing
216
207
end
@@ -234,38 +225,89 @@ function MOI.supports_constraint(
234
225
return true
235
226
end
236
227
228
+ function _throw_if_existing_lower (x, type, new_set:: S ) where {S}
229
+ if type == _kSCIP_EQUAL_TO
230
+ throw (MOI. LowerBoundAlreadySet {MOI.EqualTo{Float64},S} (x))
231
+ elseif type == _kSCIP_GREATER_THAN
232
+ throw (MOI. LowerBoundAlreadySet {MOI.GreaterThan{Float64},S} (x))
233
+ elseif type == _kSCIP_LESS_AND_GREATER_THAN
234
+ throw (MOI. LowerBoundAlreadySet {MOI.GreaterThan{Float64},S} (x))
235
+ elseif type == _kSCIP_INTERVAL
236
+ throw (MOI. LowerBoundAlreadySet {MOI.Interval{Float64},S} (x))
237
+ end
238
+ return
239
+ end
240
+
241
+ function _throw_if_existing_upper (x, type, new_set:: S ) where {S}
242
+ if type == _kSCIP_EQUAL_TO
243
+ throw (MOI. UpperBoundAlreadySet {MOI.EqualTo{Float64},S} (x))
244
+ elseif type == _kSCIP_LESS_THAN
245
+ throw (MOI. UpperBoundAlreadySet {MOI.LessThan{Float64},S} (x))
246
+ elseif type == _kSCIP_LESS_AND_GREATER_THAN
247
+ throw (MOI. UpperBoundAlreadySet {MOI.LessThan{Float64},S} (x))
248
+ elseif type == _kSCIP_INTERVAL
249
+ throw (MOI. UpperBoundAlreadySet {MOI.Interval{Float64},S} (x))
250
+ end
251
+ return
252
+ end
253
+
254
+ function _update_bound (o:: Optimizer , x, s:: MOI.EqualTo , l, u)
255
+ type = get (o. bound_types, x, nothing )
256
+ _throw_if_existing_lower (x, type, s)
257
+ _throw_if_existing_upper (x, type, s)
258
+ o. bound_types[x] = _kSCIP_EQUAL_TO
259
+ return s. value, s. value
260
+ end
261
+
262
+ function _update_bound (o:: Optimizer , x, s:: MOI.Interval , l, u)
263
+ type = get (o. bound_types, x, nothing )
264
+ _throw_if_existing_lower (x, type, s)
265
+ _throw_if_existing_upper (x, type, s)
266
+ o. bound_types[x] = _kSCIP_INTERVAL
267
+ return s. lower, s. upper
268
+ end
269
+
270
+ function _update_bound (o:: Optimizer , x, s:: MOI.LessThan , l, u)
271
+ type = get (o. bound_types, x, nothing )
272
+ _throw_if_existing_upper (x, type, s)
273
+ if type == _kSCIP_GREATER_THAN
274
+ o. bound_types[x] = _kSCIP_LESS_AND_GREATER_THAN
275
+ else
276
+ o. bound_types[x] = _kSCIP_LESS_THAN
277
+ end
278
+ return l, s. upper
279
+ end
280
+
281
+ function _update_bound (o:: Optimizer , x, s:: MOI.GreaterThan , l, u)
282
+ type = get (o. bound_types, x, nothing )
283
+ _throw_if_existing_lower (x, type, s)
284
+ if type == _kSCIP_LESS_THAN
285
+ o. bound_types[x] = _kSCIP_LESS_AND_GREATER_THAN
286
+ else
287
+ o. bound_types[x] = _kSCIP_GREATER_THAN
288
+ end
289
+ return s. lower, u
290
+ end
291
+
237
292
function MOI. add_constraint (
238
293
o:: Optimizer ,
239
294
vi:: MOI.VariableIndex ,
240
295
set:: S ,
241
296
) where {S<: BOUNDS }
242
297
allow_modification (o)
243
298
v = var (o, vi)
244
- newlb, newub = bounds (set)
245
- inf = SCIPinfinity (o)
246
- newlb, newub = something (newlb, - inf), something (newub, inf)
247
- oldlb, oldub = SCIPvarGetLbOriginal (v), SCIPvarGetUbOriginal (v)
248
- # FIXME (odow): This section is broken for detecting existing bounds
249
- if (oldlb != - inf && newlb != - inf || oldub != inf && newub != inf)
250
- if SCIPvarGetType (v) == SCIP_VARTYPE_BINARY
251
- # Store new bounds
252
- o. binbounds[vi] = MOI. Interval (newlb, newub)
253
- if newlb < 0.0
254
- newlb = oldlb
255
- end
256
- if newub > 1.0
257
- newub = oldub
258
- end
259
- else
260
- throw (MOI. LowerBoundAlreadySet {S,S} (vi))
261
- end
262
- end
263
- if newlb != - inf
264
- @SCIP_CALL SCIPchgVarLb (o, v, newlb)
299
+ l, u = SCIPvarGetLbOriginal (v), SCIPvarGetUbOriginal (v)
300
+ if SCIPvarGetType (v) == SCIP_VARTYPE_BINARY
301
+ s = o. binbounds[vi]
302
+ l, u = s. lower, s. upper
265
303
end
266
- if newub != inf
267
- @SCIP_CALL SCIPchgVarUb (o, v, newub)
304
+ l, u = _update_bound (o, vi, set, l, u)
305
+ if SCIPvarGetType (v) == SCIP_VARTYPE_BINARY
306
+ o. binbounds[vi] = MOI. Interval (l, u)
307
+ l, u = max (0.0 , l), min (1.0 , u)
268
308
end
309
+ @SCIP_CALL SCIPchgVarLb (o, v, l)
310
+ @SCIP_CALL SCIPchgVarUb (o, v, u)
269
311
ci = MOI. ConstraintIndex {MOI.VariableIndex,S} (vi. value)
270
312
return register! (o, ci)
271
313
end
@@ -303,6 +345,14 @@ function MOI.delete(
303
345
end
304
346
# but do delete the constraint reference
305
347
delete! (o. binbounds, vi)
348
+ type = o. bound_types[vi]
349
+ if type == _kSCIP_LESS_AND_GREATER_THAN && S <: MOI.LessThan
350
+ o. bound_types[vi] = _kSCIP_GREATER_THAN
351
+ elseif type == _kSCIP_LESS_AND_GREATER_THAN && S <: MOI.GreaterThan
352
+ o. bound_types[vi] = _kSCIP_LESS_AND_GREATER_THAN
353
+ else
354
+ delete! (o. bound_types, vi)
355
+ end
306
356
delete! (o. constypes[MOI. VariableIndex, S], ConsRef (ci. value))
307
357
return nothing
308
358
end
@@ -314,25 +364,25 @@ function MOI.set(
314
364
set:: S ,
315
365
) where {S<: BOUNDS }
316
366
allow_modification (o)
317
- v = var (o, MOI. VariableIndex (ci. value) )
318
- lb, ub = bounds (set )
319
- old_interval =
320
- get (o . binbounds, MOI . VariableIndex (ci . value), MOI . Interval ( 0.0 , 1.0 ) )
321
- if lb != = nothing
367
+ vi = MOI. VariableIndex (ci. value)
368
+ v = var (o, vi )
369
+ lb, ub = bounds (o, set)
370
+ inf = SCIPinfinity (o )
371
+ if lb > - inf
322
372
if SCIPvarGetType (v) == SCIP_VARTYPE_BINARY
373
+ old_interval = o. binbounds[vi]
374
+ o. binbounds[vi] = MOI. Interval (lb, old_interval. upper)
323
375
lb = max (lb, 0.0 )
324
376
end
325
377
@SCIP_CALL SCIPchgVarLb (o, v, lb)
326
- o. binbounds[MOI. VariableIndex (ci. value)] =
327
- MOI. Interval (lb, old_interval. upper)
328
378
end
329
- if ub != = nothing
379
+ if ub < inf
330
380
if SCIPvarGetType (v) == SCIP_VARTYPE_BINARY
381
+ old_interval = o. binbounds[vi]
382
+ o. binbounds[vi] = MOI. Interval (old_interval. lower, ub)
331
383
ub = min (ub, 1.0 )
332
384
end
333
385
@SCIP_CALL SCIPchgVarUb (o, v, ub)
334
- o. binbounds[MOI. VariableIndex (ci. value)] =
335
- MOI. Interval (old_interval. lower, ub)
336
386
end
337
387
return nothing
338
388
end
0 commit comments