@@ -21,97 +21,96 @@ constrdict(model::LinQuadOptimizer, ::SVCI{MOI.Integer}) = cmap(model).integer
2121constrdict (model:: LinQuadOptimizer , :: SVCI{MOI.Semicontinuous{Float64}} ) = cmap (model). semicontinuous
2222constrdict (model:: LinQuadOptimizer , :: SVCI{MOI.Semiinteger{Float64}} ) = cmap (model). semiinteger
2323
24- function set_variable_bound (model:: LinQuadOptimizer , v:: SinVar , set:: LE )
24+ """
25+ change_both_variable_bounds!(model::LinQuadOptimizer, columns::Vector{Int},
26+ lower_bounds::Vector{Float64}, upper_bounds::Vector{Float64})
27+
28+ Set the lower bound of column `columns[i]` to `lower_bounds[i]` and the upper
29+ bound to `upper_bounds[i]`. Alternatively, the lower or upper bound can be left
30+ blank by passing an array of length 0 instead.
31+
32+ Examples:
33+ change_both_variable_bounds!(model, [1, 2], [-0.5, 0.0], [1.0, 2.0])
34+ change_both_variable_bounds!(model, [1, 2], [-0.5, 0.0], Float64[])
35+ change_both_variable_bounds!(model, [1, 2], Float64[], [1.0, 2.0])
36+ """
37+ function change_both_variable_bounds! (
38+ model:: LinQuadOptimizer ,
39+ columns:: Vector{Int} ,
40+ lower_bounds:: Vector{Float64} ,
41+ upper_bounds:: Vector{Float64} )
42+ if length (lower_bounds) > 0 && length (upper_bounds) > 0
43+ columns = vcat (columns, columns)
44+ end
2545 change_variable_bounds! (model,
26- [get_column (model, v)],
27- [set. upper],
28- [backend_type (model, Val {:Upperbound} ())]
46+ columns,
47+ vcat (lower_bounds, upper_bounds),
48+ vcat (
49+ fill (backend_type (model, Val {:Lowerbound} ()), length (lower_bounds)),
50+ fill (backend_type (model, Val {:Upperbound} ()), length (upper_bounds))
51+ )
2952 )
3053end
3154
55+ function set_variable_bound (model:: LinQuadOptimizer , v:: SinVar , set:: LE )
56+ change_both_variable_bounds! (
57+ model, [get_column (model, v)], Float64[], [set. upper])
58+ end
59+
3260function set_variable_bound (model:: LinQuadOptimizer , v:: SinVar , set:: GE )
33- change_variable_bounds! (model,
34- [get_column (model, v)],
35- [set. lower],
36- [backend_type (model, Val {:Lowerbound} ())]
37- )
61+ change_both_variable_bounds! (
62+ model, [get_column (model, v)], [set. lower], Float64[])
3863end
3964
4065function set_variable_bound (model:: LinQuadOptimizer , v:: SinVar , set:: EQ )
41- change_variable_bounds! (model,
42- [get_column (model, v), get_column (model, v)],
43- [set. value, set. value],
44- [backend_type (model, Val {:Upperbound} ()),
45- backend_type (model, Val {:Lowerbound} ())
46- ]
47- )
66+ change_both_variable_bounds! (
67+ model, [get_column (model, v)], [set. value], [set. value])
4868end
4969
5070function set_variable_bound (model:: LinQuadOptimizer , v:: SinVar , set:: IV )
51- change_variable_bounds! (model,
52- [get_column (model, v), get_column (model, v)],
53- [set. upper, set. lower],
54- [backend_type (model, Val {:Upperbound} ()),
55- backend_type (model, Val {:Lowerbound} ())
56- ]
57- )
71+ change_both_variable_bounds! (
72+ model, [get_column (model, v)], [set. lower], [set. upper])
5873end
5974
60- """
61- has_value(dict::Dict{K, V}, value::V) where {K, V}
62-
63- Return true if `dict` has a `key=>value` pair with `value`.
64- """
65- function has_value (dict:: Dict{K, V} , value:: V ) where {K, V}
66- return value in values (dict)
75+ function set_variable_bounds (
76+ model:: LinQuadOptimizer , vars:: Vector{SinVar} , sets:: Vector{LE} )
77+ change_both_variable_bounds! (model, get_column .(model, vars), Float64[],
78+ [set. upper for set in sets])
6779end
6880
69- """
70- __check_for_conflicting__(model::LinQuadOptimizer, variable::SinVar, set,
71- conflicting_type::Type{<:AbstractSet})
72-
73- Throw an error if `variable` is already constrained to be in a set of type
74- `conflicting_type`.
75- """
76- function __check_for_conflicting__ (model:: LinQuadOptimizer , variable:: SinVar , set,
77- conflict_type:: Type{<:MOI.AbstractSet} )
78- if has_value (constrdict (model, SVCI {conflict_type} (0 )), variable. variable)
79- error (" Cannot add constraint $(variable) -in-$(set) as it is already " *
80- " constrained by a set of type $(conflict_type) ." )
81- end
81+ function set_variable_bounds (
82+ model:: LinQuadOptimizer , vars:: Vector{SinVar} , sets:: Vector{GE} )
83+ change_both_variable_bounds! (model, get_column .(model, vars),
84+ [set. lower for set in sets], Float64[])
8285end
8386
84- function __check_for_conflicting__ (model:: LinQuadOptimizer , variable:: SinVar , set,
85- conflict_type:: Type{MOI.ZeroOne} )
86- for (index, lower, upper) in values (constrdict (model, SVCI {conflict_type} (0 )))
87- if index == variable. variable
88- error (" Cannot add constraint $(variable) -in-$(set) as it is already " *
89- " constrained by a set of type $(conflict_type) ." )
90- end
91- end
87+ function set_variable_bounds (
88+ model:: LinQuadOptimizer , vars:: Vector{SinVar} , sets:: Vector{EQ} )
89+ values = [set. value for set in sets]
90+ change_both_variable_bounds! (model, get_column .(model, vars), values, values)
9291end
9392
93+ function set_variable_bounds (
94+ model:: LinQuadOptimizer , vars:: Vector{SinVar} , sets:: Vector{IV} )
95+ change_both_variable_bounds! (model, get_column .(model, vars),
96+ [set. lower for set in sets], [set. upper for set in sets])
97+ end
9498
9599"""
96- __check_for_conflicting__(model::LinQuadOptimizer, variable::SinVar, set,
97- conflicting_types::AbstractSet...)
100+ has_value(dict::Dict{K, V}, value::V) where {K, V}
98101
99- Throw an error if `variable` is constrained to be in a set whose type is one of
100- `conflicting_types`.
102+ Return true if `dict` has a `key=>value` pair with `value`.
101103"""
102- function __check_for_conflicting__ (model:: LinQuadOptimizer , variable:: SinVar , set,
103- conflicting_types... )
104- for conflict_type in conflicting_types
105- __check_for_conflicting__ (model, variable, set, conflict_type)
106- end
104+ function has_value (dict:: Dict{K, V} , value:: V ) where {K, V}
105+ return value in values (dict)
107106end
108107
109108function MOI. add_constraint (model:: LinQuadOptimizer , variable:: SinVar , set:: S ) where S <: LinSets
110109 __assert_supported_constraint__ (model, SinVar, S)
111- # Since the following " variable type" sets also define bounds (implicitly or explicitly),
112- # they may conflict with other bound constraints.
113- __check_for_conflicting__ (model, variable, set,
114- S, MOI . Semicontinuous{Float64}, MOI . Semiinteger{Float64}, MOI . ZeroOne)
110+ variable_type = model . variable_type[ variable. variable]
111+ if ! (variable_type == Continuous || variable_type == Integer)
112+ error ( " Cannot set bounds because variable is of type: $(variable_type) . " )
113+ end
115114 set_variable_bound (model, variable, set)
116115 model. last_constraint_reference += 1
117116 index = SVCI {S} (model. last_constraint_reference)
@@ -120,13 +119,36 @@ function MOI.add_constraint(model::LinQuadOptimizer, variable::SinVar, set::S) w
120119 return index
121120end
122121
122+ function MOI. add_constraints (model:: LinQuadOptimizer , variables:: Vector{SinVar} ,
123+ sets:: Vector{S} ) where S <: LinSets
124+ __assert_supported_constraint__ (model, SinVar, S)
125+ for variable in variables
126+ variable_type = model. variable_type[variable. variable]
127+ if ! (variable_type == Continuous || variable_type == Integer)
128+ error (" Cannot set bounds because variable is of type: $(variable_type) ." )
129+ end
130+ end
131+ set_variable_bounds (model, variables, sets)
132+ indices = SVCI{S}[]
133+ for variable in variables
134+ model. last_constraint_reference += 1
135+ index = SVCI {S} (model. last_constraint_reference)
136+ dict = constrdict (model, index)
137+ dict[index] = variable. variable
138+ push! (indices, index)
139+ end
140+ return indices
141+ end
142+
123143function MOI. delete (model:: LinQuadOptimizer , index:: SVCI{S} ) where S <: LinSets
124144 __assert_valid__ (model, index)
125145 delete_constraint_name (model, index)
126146 dict = constrdict (model, index)
127- variable_index = dict[index]
128- set_variable_bound (model, SinVar (variable_index), IV (- Inf , Inf ))
147+ variable = dict[index]
148+ model. variable_type[variable] = Continuous
149+ set_variable_bound (model, SinVar (variable), IV (- Inf , Inf ))
129150 delete! (dict, index)
151+ return
130152end
131153
132154# constraint set
@@ -174,8 +196,11 @@ user does.
174196=#
175197function MOI. add_constraint (model:: LinQuadOptimizer , variable:: SinVar , set:: MOI.ZeroOne )
176198 __assert_supported_constraint__ (model, SinVar, MOI. ZeroOne)
177- __check_for_conflicting__ (model, variable, set, MOI. ZeroOne, MOI. Integer,
178- MOI. Semicontinuous{Float64}, MOI. Semiinteger{Float64})
199+ variable_type = model. variable_type[variable. variable]
200+ if variable_type != Continuous
201+ error (" Cannot make variable binary because it is $(variable_type) ." )
202+ end
203+ model. variable_type[variable. variable] = Binary
179204 model. last_constraint_reference += 1
180205 index = SVCI {MOI.ZeroOne} (model. last_constraint_reference)
181206 column = get_column (model, variable)
@@ -198,6 +223,7 @@ function MOI.delete(model::LinQuadOptimizer, index::SVCI{MOI.ZeroOne})
198223 delete_constraint_name (model, index)
199224 dict = constrdict (model, index)
200225 (variable, lower, upper) = dict[index]
226+ model. variable_type[variable] = Continuous
201227 column = get_column (model, variable)
202228 change_variable_types! (
203229 model, [column], [backend_type (model, Val {:Continuous} ())])
227253
228254function MOI. add_constraint (model:: LinQuadOptimizer , variable:: SinVar , set:: MOI.Integer )
229255 __assert_supported_constraint__ (model, SinVar, MOI. Integer)
230- __check_for_conflicting__ (model, variable, set, MOI. ZeroOne,
231- MOI. Semicontinuous{Float64}, MOI. Semiinteger{Float64})
256+ variable_type = model. variable_type[variable. variable]
257+ if variable_type != Continuous
258+ error (" Cannot make variable integer because it is $(variable_type) ." )
259+ end
260+ model. variable_type[variable. variable] = Integer
232261 change_variable_types! (model, [get_column (model, variable)],
233262 [backend_type (model, set)])
234263 model. last_constraint_reference += 1
@@ -244,6 +273,7 @@ function MOI.delete(model::LinQuadOptimizer, index::SVCI{MOI.Integer})
244273 delete_constraint_name (model, index)
245274 dict = constrdict (model, index)
246275 variable = dict[index]
276+ model. variable_type[variable] = Continuous
247277 change_variable_types! (model, [get_column (model, variable)],
248278 [backend_type (model, Val {:Continuous} ())])
249279 delete! (dict, index)
@@ -265,14 +295,15 @@ end
265295 Semicontinuous / Semiinteger constraints
266296=#
267297const SEMI_TYPES = Union{MOI. Semicontinuous{Float64}, MOI. Semiinteger{Float64}}
298+ variable_type_ (:: Type{<:MOI.Semicontinuous} ) = Semicontinuous
299+ variable_type_ (:: Type{<:MOI.Semiinteger} ) = Semiinteger
268300function MOI. add_constraint (model:: LinQuadOptimizer , variable:: SinVar , set:: S ) where S <: SEMI_TYPES
269301 __assert_supported_constraint__ (model, SinVar, S)
270- __check_for_conflicting__ (model, variable, set, S, MOI. ZeroOne, MOI. Integer)
271- if S == MOI. Semicontinuous{Float64}
272- __check_for_conflicting__ (model, variable, set, MOI. Semiinteger{Float64})
273- else
274- __check_for_conflicting__ (model, variable, set, MOI. Semicontinuous{Float64})
302+ variable_type = model. variable_type[variable. variable]
303+ if variable_type != Continuous
304+ error (" Cannot make variable $(S) because it is $(variable_type) ." )
275305 end
306+ model. variable_type[variable. variable] = variable_type_ (S)
276307 column = get_column (model, variable)
277308 change_variable_types! (model, [column], [backend_type (model, set)])
278309 change_variable_bounds! (model,
@@ -293,7 +324,9 @@ function MOI.delete(model::LinQuadOptimizer, index::SVCI{<:SEMI_TYPES})
293324 __assert_valid__ (model, index)
294325 delete_constraint_name (model, index)
295326 dict = constrdict (model, index)
296- column = get_column (model, dict[index])
327+ variable = dict[index]
328+ column = get_column (model, variable)
329+ model. variable_type[variable] = Continuous
297330 change_variable_types! (model, [column], [backend_type (model, Val {:Continuous} ())])
298331 change_variable_bounds! (model,
299332 [column, column],
0 commit comments