@@ -115,8 +115,11 @@ function MOI.delete(o::Optimizer, vi::MOI.VariableIndex)
115115 throw (MOI. InvalidIndex (vi))
116116 end
117117 delete! (o. binbounds, vi)
118+ delete! (o. bound_types, vi)
118119 delete! (o. reference, var (o, vi))
119120 delete (o. inner, VarRef (vi. value))
121+ # FIXME (odow): delete the associated ConstraintIndex
122+ delete! (o. bound_types, vi)
120123 o. name_to_variable = nothing
121124 return nothing
122125end
@@ -176,22 +179,11 @@ function MOI.add_constraint(o::Optimizer, vi::MOI.VariableIndex, ::MOI.ZeroOne)
176179 v = var (o, vi)
177180 p_infeas = Ref {SCIP_Bool} ()
178181 @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:
181182 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 ))
195187 ci = MOI. ConstraintIndex {MOI.VariableIndex,MOI.ZeroOne} (vi. value)
196188 return register! (o, ci)
197189end
@@ -207,10 +199,9 @@ function MOI.delete(
207199 p_infeas = Ref {SCIP_Bool} ()
208200 @SCIP_CALL SCIPchgVarType (o, v, SCIP_VARTYPE_CONTINUOUS, p_infeas)
209201 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)
214205 delete! (o. constypes[MOI. VariableIndex, MOI. ZeroOne], ConsRef (ci. value))
215206 return nothing
216207end
@@ -234,38 +225,89 @@ function MOI.supports_constraint(
234225 return true
235226end
236227
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+
237292function MOI. add_constraint (
238293 o:: Optimizer ,
239294 vi:: MOI.VariableIndex ,
240295 set:: S ,
241296) where {S<: BOUNDS }
242297 allow_modification (o)
243298 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
265303 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)
268308 end
309+ @SCIP_CALL SCIPchgVarLb (o, v, l)
310+ @SCIP_CALL SCIPchgVarUb (o, v, u)
269311 ci = MOI. ConstraintIndex {MOI.VariableIndex,S} (vi. value)
270312 return register! (o, ci)
271313end
@@ -303,6 +345,14 @@ function MOI.delete(
303345 end
304346 # but do delete the constraint reference
305347 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
306356 delete! (o. constypes[MOI. VariableIndex, S], ConsRef (ci. value))
307357 return nothing
308358end
@@ -314,25 +364,25 @@ function MOI.set(
314364 set:: S ,
315365) where {S<: BOUNDS }
316366 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
322372 if SCIPvarGetType (v) == SCIP_VARTYPE_BINARY
373+ old_interval = o. binbounds[vi]
374+ o. binbounds[vi] = MOI. Interval (lb, old_interval. upper)
323375 lb = max (lb, 0.0 )
324376 end
325377 @SCIP_CALL SCIPchgVarLb (o, v, lb)
326- o. binbounds[MOI. VariableIndex (ci. value)] =
327- MOI. Interval (lb, old_interval. upper)
328378 end
329- if ub != = nothing
379+ if ub < inf
330380 if SCIPvarGetType (v) == SCIP_VARTYPE_BINARY
381+ old_interval = o. binbounds[vi]
382+ o. binbounds[vi] = MOI. Interval (old_interval. lower, ub)
331383 ub = min (ub, 1.0 )
332384 end
333385 @SCIP_CALL SCIPchgVarUb (o, v, ub)
334- o. binbounds[MOI. VariableIndex (ci. value)] =
335- MOI. Interval (old_interval. lower, ub)
336386 end
337387 return nothing
338388end
0 commit comments