Skip to content
This repository was archived by the owner on Jun 14, 2020. It is now read-only.

Commit 30cbccc

Browse files
committed
Replace check for conflicting constraints with an O(1) cache
1 parent dce0136 commit 30cbccc

File tree

3 files changed

+37
-57
lines changed

3 files changed

+37
-57
lines changed

src/LinQuadOptInterface.jl

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -199,6 +199,8 @@ end
199199
# Abstract + macro
200200
abstract type LinQuadOptimizer <: MOI.AbstractOptimizer end
201201

202+
@enum(VariableType, Continuous, Binary, Integer, Semiinteger, Semicontinuous)
203+
202204
macro LinQuadOptimizerBase(inner_model_type=Any)
203205
esc(quote
204206
inner::$inner_model_type
@@ -214,6 +216,7 @@ macro LinQuadOptimizerBase(inner_model_type=Any)
214216
variable_names::Dict{MOI.VariableIndex, String}
215217
variable_names_rev::Dict{String, MOI.VariableIndex}
216218
variable_references::Vector{MOI.VariableIndex}
219+
variable_type::Dict{MOI.VariableIndex, LinQuadOptInterface.VariableType}
217220

218221
variable_primal_solution::Vector{Float64}
219222
variable_dual_solution::Vector{Float64}
@@ -256,6 +259,7 @@ function MOI.is_empty(m::LinQuadOptimizer)
256259
ret = ret && isempty(m.variable_names)
257260
ret = ret && isempty(m.variable_names_rev)
258261
ret = ret && isempty(m.variable_references)
262+
ret = ret && isempty(m.variable_type)
259263
ret = ret && isempty(m.variable_primal_solution)
260264
ret = ret && isempty(m.variable_dual_solution)
261265
ret = ret && m.last_constraint_reference == 0
@@ -291,7 +295,7 @@ function MOI.empty!(m::M, env = nothing) where M<:LinQuadOptimizer
291295
m.variable_names = Dict{MathOptInterface.VariableIndex, String}()
292296
m.variable_names_rev = Dict{String, MathOptInterface.VariableIndex}()
293297
m.variable_references = MathOptInterface.VariableIndex[]
294-
298+
m.variable_type = Dict{MathOptInterface.VariableIndex, VariableType}()
295299
m.variable_primal_solution = Float64[]
296300
m.variable_dual_solution = Float64[]
297301

src/constraints/singlevariable.jl

Lines changed: 29 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -66,52 +66,12 @@ function has_value(dict::Dict{K, V}, value::V) where {K, V}
6666
return value in values(dict)
6767
end
6868

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
82-
end
83-
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
92-
end
93-
94-
95-
"""
96-
__check_for_conflicting__(model::LinQuadOptimizer, variable::SinVar, set,
97-
conflicting_types::AbstractSet...)
98-
99-
Throw an error if `variable` is constrained to be in a set whose type is one of
100-
`conflicting_types`.
101-
"""
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
107-
end
108-
10969
function MOI.add_constraint(model::LinQuadOptimizer, variable::SinVar, set::S) where S <: LinSets
11070
__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)
71+
variable_type = model.variable_type[variable.variable]
72+
if !(variable_type == Continuous || variable_type == Integer)
73+
error("Cannot set bounds because variable is of type: $(variable_type).")
74+
end
11575
set_variable_bound(model, variable, set)
11676
model.last_constraint_reference += 1
11777
index = SVCI{S}(model.last_constraint_reference)
@@ -124,9 +84,11 @@ function MOI.delete(model::LinQuadOptimizer, index::SVCI{S}) where S <: LinSets
12484
__assert_valid__(model, index)
12585
delete_constraint_name(model, index)
12686
dict = constrdict(model, index)
127-
variable_index = dict[index]
128-
set_variable_bound(model, SinVar(variable_index), IV(-Inf, Inf))
87+
variable = dict[index]
88+
model.variable_type[variable] = Continuous
89+
set_variable_bound(model, SinVar(variable), IV(-Inf, Inf))
12990
delete!(dict, index)
91+
return
13092
end
13193

13294
# constraint set
@@ -174,8 +136,11 @@ user does.
174136
=#
175137
function MOI.add_constraint(model::LinQuadOptimizer, variable::SinVar, set::MOI.ZeroOne)
176138
__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})
139+
variable_type = model.variable_type[variable.variable]
140+
if variable_type != Continuous
141+
error("Cannot make variable binary because it is $(variable_type).")
142+
end
143+
model.variable_type[variable.variable] = Binary
179144
model.last_constraint_reference += 1
180145
index = SVCI{MOI.ZeroOne}(model.last_constraint_reference)
181146
column = get_column(model, variable)
@@ -198,6 +163,7 @@ function MOI.delete(model::LinQuadOptimizer, index::SVCI{MOI.ZeroOne})
198163
delete_constraint_name(model, index)
199164
dict = constrdict(model, index)
200165
(variable, lower, upper) = dict[index]
166+
model.variable_type[variable] = Continuous
201167
column = get_column(model, variable)
202168
change_variable_types!(
203169
model, [column], [backend_type(model, Val{:Continuous}())])
@@ -227,8 +193,11 @@ end
227193

228194
function MOI.add_constraint(model::LinQuadOptimizer, variable::SinVar, set::MOI.Integer)
229195
__assert_supported_constraint__(model, SinVar, MOI.Integer)
230-
__check_for_conflicting__(model, variable, set, MOI.ZeroOne,
231-
MOI.Semicontinuous{Float64}, MOI.Semiinteger{Float64})
196+
variable_type = model.variable_type[variable.variable]
197+
if variable_type != Continuous
198+
error("Cannot make variable integer because it is $(variable_type).")
199+
end
200+
model.variable_type[variable.variable] = Integer
232201
change_variable_types!(model, [get_column(model, variable)],
233202
[backend_type(model, set)])
234203
model.last_constraint_reference += 1
@@ -244,6 +213,7 @@ function MOI.delete(model::LinQuadOptimizer, index::SVCI{MOI.Integer})
244213
delete_constraint_name(model, index)
245214
dict = constrdict(model, index)
246215
variable = dict[index]
216+
model.variable_type[variable] = Continuous
247217
change_variable_types!(model, [get_column(model, variable)],
248218
[backend_type(model, Val{:Continuous}())])
249219
delete!(dict, index)
@@ -265,14 +235,15 @@ end
265235
Semicontinuous / Semiinteger constraints
266236
=#
267237
const SEMI_TYPES = Union{MOI.Semicontinuous{Float64}, MOI.Semiinteger{Float64}}
238+
variable_type_(::Type{<:MOI.Semicontinuous}) = Semicontinuous
239+
variable_type_(::Type{<:MOI.Semiinteger}) = Semiinteger
268240
function MOI.add_constraint(model::LinQuadOptimizer, variable::SinVar, set::S) where S <: SEMI_TYPES
269241
__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})
242+
variable_type = model.variable_type[variable.variable]
243+
if variable_type != Continuous
244+
error("Cannot make variable $(S) because it is $(variable_type).")
275245
end
246+
model.variable_type[variable.variable] = variable_type_(S)
276247
column = get_column(model, variable)
277248
change_variable_types!(model, [column], [backend_type(model, set)])
278249
change_variable_bounds!(model,
@@ -293,7 +264,9 @@ function MOI.delete(model::LinQuadOptimizer, index::SVCI{<:SEMI_TYPES})
293264
__assert_valid__(model, index)
294265
delete_constraint_name(model, index)
295266
dict = constrdict(model, index)
296-
column = get_column(model, dict[index])
267+
variable = dict[index]
268+
column = get_column(model, variable)
269+
model.variable_type[variable] = Continuous
297270
change_variable_types!(model, [column], [backend_type(model, Val{:Continuous}())])
298271
change_variable_bounds!(model,
299272
[column, column],

src/variables.jl

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,7 @@ function MOI.add_variable(model::LinQuadOptimizer)
9292
push!(model.variable_references, index)
9393
push!(model.variable_primal_solution, NaN)
9494
push!(model.variable_dual_solution, NaN)
95+
model.variable_type[index] = Continuous
9596
return index
9697
end
9798

@@ -115,6 +116,7 @@ function MOI.add_variables(model::LinQuadOptimizer, number_to_add::Int)
115116
push!(model.variable_references, index)
116117
push!(model.variable_primal_solution, NaN)
117118
push!(model.variable_dual_solution, NaN)
119+
model.variable_type[index] = Continuous
118120
end
119121
return variable_indices
120122
end
@@ -143,6 +145,7 @@ function MOI.delete(model::LinQuadOptimizer, index::VarInd)
143145
delete_variables!(model, column, column)
144146
# delete from problem
145147
deleteat!(model.variable_references, column)
148+
delete!(model.variable_type, index)
146149
deleteat!(model.variable_primal_solution, column)
147150
deleteat!(model.variable_dual_solution, column)
148151
deleteref!(model.variable_mapping, column, index)

0 commit comments

Comments
 (0)