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

Commit 0666b30

Browse files
authored
WIP: fix issues identified by MOI #354 (#10)
* Fix get(ConstraintFunction) for SingleVariable * Add todo for constraintset of ranged constraint * Add support for deleting affine and vector affine constraints. * Updates including deleting q constraints * Semicontinuous and Semiinteger variables * Fix bug in deleting vector constraints
1 parent 3a938d1 commit 0666b30

File tree

8 files changed

+204
-23
lines changed

8 files changed

+204
-23
lines changed

src/LinQuadOptInterface.jl

Lines changed: 64 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,9 @@ struct ConstraintMapping
7777
binary::Dict{SVCI{MOI.ZeroOne}, Tuple{VarInd, Float64, Float64}}
7878
sos1::Dict{VVCI{SOS1}, Int}
7979
sos2::Dict{VVCI{SOS2}, Int}
80+
semicontinuous::Dict{SVCI{MOI.Semicontinuous{Float64}}, VarInd}
81+
semiinteger::Dict{SVCI{MOI.Semiinteger{Float64}}, VarInd}
82+
8083
end
8184
ConstraintMapping() = ConstraintMapping(
8285
Dict{LCI{LE}, Int}(),
@@ -99,8 +102,66 @@ ConstraintMapping() = ConstraintMapping(
99102
Dict{SVCI{MOI.Integer}, VarInd}(),
100103
Dict{SVCI{MOI.ZeroOne}, Tuple{VarInd, Float64, Float64}}(),
101104
Dict{VVCI{SOS1}, Int}(),
102-
Dict{VVCI{SOS2}, Int}()
105+
Dict{VVCI{SOS2}, Int}(),
106+
Dict{SVCI{MOI.Semicontinuous{Float64}}, VarInd}(),
107+
Dict{SVCI{MOI.Semiinteger{Float64}}, VarInd}()
103108
)
109+
110+
"""
111+
shift_references_after_delete_affine!(m, row)
112+
113+
This function updates all of the references in `m`
114+
after we have deleted row `row` in the affine constraint matrix.
115+
"""
116+
function shift_references_after_delete_affine!(m, row)
117+
for scalar_affine in [
118+
cmap(m).less_than,
119+
cmap(m).greater_than,
120+
cmap(m).equal_to,
121+
cmap(m).interval
122+
]
123+
for (key, val) in scalar_affine
124+
if val > row
125+
scalar_affine[key] -= 1
126+
end
127+
end
128+
end
129+
130+
for vector_affine in [
131+
cmap(m).vv_nonnegatives,
132+
cmap(m).vv_nonpositives,
133+
cmap(m).vv_zeros
134+
]
135+
for (key, vals) in vector_affine
136+
for (i, val) in enumerate(vals)
137+
if val > row
138+
vector_affine[key][i] -= 1
139+
end
140+
end
141+
end
142+
end
143+
end
144+
145+
"""
146+
shift_references_after_delete_quadratic!(m, row)
147+
148+
This function updates all of the references in `m`
149+
after we have deleted row `row` in the quadratic constraint matrix.
150+
"""
151+
function shift_references_after_delete_quadratic!(m, row)
152+
for scalar_quadratic in [
153+
cmap(m).q_less_than,
154+
cmap(m).q_greater_than,
155+
cmap(m).q_equal_to
156+
]
157+
for (key, val) in scalar_quadratic
158+
if val > row
159+
scalar_quadratic[key] -= 1
160+
end
161+
end
162+
end
163+
end
164+
104165
function Base.isempty(map::ConstraintMapping)
105166

106167
ret = true
@@ -125,6 +186,8 @@ function Base.isempty(map::ConstraintMapping)
125186
ret = ret && isempty(map.binary)
126187
ret = ret && isempty(map.sos1)
127188
ret = ret && isempty(map.sos2)
189+
ret = ret && isempty(map.semiinteger)
190+
ret = ret && isempty(map.semicontinuous)
128191

129192
return ret
130193
end

src/constraints.jl

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,10 +26,18 @@ end
2626
hasinteger(m::LinQuadOptimizer)::Bool
2727
2828
A helper function to determine if the solver instance `m` has any integer
29-
components (i.e. binary, integer, special ordered sets, etc).
29+
components (i.e. binary, integer, special ordered sets, semicontinuous, or
30+
semi-integer variables).
3031
"""
3132
function hasinteger(m::LinQuadOptimizer)
32-
length(cmap(m).integer) + length(cmap(m).binary) + length(cmap(m).sos1) + length(cmap(m).sos2) > 0
33+
(
34+
length(cmap(m).integer) +
35+
length(cmap(m).binary) +
36+
length(cmap(m).sos1) +
37+
length(cmap(m).sos2) +
38+
length(cmap(m).semicontinuous) +
39+
length(cmap(m).semiinteger)
40+
) > 0
3341
end
3442

3543
#=

src/constraints/scalaraffine.jl

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ function addlinearconstraints!(m::LinQuadOptimizer, func::Vector{Linear}, set::V
8484
coefficients = Vector{Float64}(nnz) # corresponding non-zeros
8585
i = 1
8686
for (fi, f) in enumerate(func)
87-
row_starts[fi] = cnt
87+
row_starts[fi] = i
8888
for (var, coef) in zip(f.variables, f.coefficients)
8989
column_indices[i] = getcol(m, var)
9090
coefficients[i] = coef
@@ -129,6 +129,13 @@ function MOI.get(m::LinQuadOptimizer, ::MOI.ConstraintSet, c::LCI{S}) where S <:
129129
S(rhs+m.constraint_constant[m[c]])
130130
end
131131

132+
MOI.canget(m::LinQuadOptimizer, ::MOI.ConstraintSet, ::Type{LCI{IV}}) = false
133+
# TODO(odow): get constraint sets for ranged constraints.
134+
# function MOI.get(m::LinQuadOptimizer, ::MOI.ConstraintSet, c::LCI{IV})
135+
# ???
136+
# IV(lowerbound+m.constraint_constant[m[c]], upperbound + m.constraint_constant[m[c]])
137+
# end
138+
132139
#=
133140
Constraint function of Linear function
134141
=#
@@ -169,7 +176,7 @@ end
169176
Delete a linear constraint
170177
=#
171178

172-
MOI.candelete(m::LinQuadOptimizer, c::LCI{<: LinSets}) = true
179+
MOI.candelete(m::LinQuadOptimizer, c::LCI{<: LinSets}) = MOI.isvalid(m, c)
173180
function MOI.delete!(m::LinQuadOptimizer, c::LCI{<: LinSets})
174181
deleteconstraintname!(m, c)
175182
dict = constrdict(m, c)
@@ -178,13 +185,9 @@ function MOI.delete!(m::LinQuadOptimizer, c::LCI{<: LinSets})
178185
deleteat!(m.constraint_primal_solution, row)
179186
deleteat!(m.constraint_dual_solution, row)
180187
deleteat!(m.constraint_constant, row)
181-
deleteref!(m, row, c)
182-
end
183-
function deleteref!(m::LinQuadOptimizer, row::Int, ref::LCI{<: LinSets})
184-
deleteref!(cmap(m).less_than, row, ref)
185-
deleteref!(cmap(m).greater_than, row, ref)
186-
deleteref!(cmap(m).equal_to, row, ref)
187-
deleteref!(cmap(m).interval, row, ref)
188+
# shift all the other references
189+
shift_references_after_delete_affine!(m, row)
190+
delete!(dict, c)
188191
end
189192

190193
#=

src/constraints/scalarquadratic.jl

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,3 +66,17 @@ function reduceduplicates(rowi::Vector{T}, coli::Vector{T}, vals::Vector{S}) whe
6666
end
6767
ri, ci, vi
6868
end
69+
70+
71+
MOI.candelete(m::LinQuadOptimizer, c::QCI{<: LinSets}) = MOI.isvalid(m, c)
72+
function MOI.delete!(m::LinQuadOptimizer, c::QCI{<: LinSets})
73+
deleteconstraintname!(m, c)
74+
dict = constrdict(m, c)
75+
row = dict[c]
76+
delete_quadratic_constraints!(m, row, row)
77+
deleteat!(m.qconstraint_primal_solution, row)
78+
deleteat!(m.qconstraint_dual_solution, row)
79+
# shift all the other references
80+
shift_references_after_delete_quadratic!(m, row)
81+
delete!(dict, c)
82+
end

src/constraints/singlevariable.jl

Lines changed: 53 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,10 @@
55
SingleVariable -in- EqualTo
66
SingleVariable -in- Interval
77
8-
TODO
9-
10-
Binary
118
SingleVariable -in- ZeroOne
129
SingleVariable -in- Integer
10+
SingleVariable -in- Semiinteger
11+
SingleVariable -in- Semicontinuous
1312
=#
1413
constrdict(m::LinQuadOptimizer, ::SVCI{LE}) = cmap(m).upper_bound
1514
constrdict(m::LinQuadOptimizer, ::SVCI{GE}) = cmap(m).lower_bound
@@ -19,6 +18,9 @@ constrdict(m::LinQuadOptimizer, ::SVCI{IV}) = cmap(m).interval_bound
1918
constrdict(m::LinQuadOptimizer, ::SVCI{MOI.ZeroOne}) = cmap(m).binary
2019
constrdict(m::LinQuadOptimizer, ::SVCI{MOI.Integer}) = cmap(m).integer
2120

21+
constrdict(m::LinQuadOptimizer, ::SVCI{MOI.Semicontinuous{Float64}}) = cmap(m).semicontinuous
22+
constrdict(m::LinQuadOptimizer, ::SVCI{MOI.Semiinteger{Float64}}) = cmap(m).semiinteger
23+
2224
function setvariablebound!(m::LinQuadOptimizer, col::Int, bound::Float64, sense::Cchar)
2325
change_variable_bounds!(m, [col], [bound], [sense])
2426
end
@@ -49,7 +51,7 @@ function MOI.addconstraint!(m::LinQuadOptimizer, v::SinVar, set::S) where S <: L
4951
end
5052

5153
# delete constraint
52-
MOI.candelete(m::LinQuadOptimizer, c::SVCI{S}) where S <: LinSets = true
54+
MOI.candelete(m::LinQuadOptimizer, c::SVCI{S}) where S <: LinSets = MOI.isvalid(m, c)
5355
function MOI.delete!(m::LinQuadOptimizer, c::SVCI{S}) where S <: LinSets
5456
deleteconstraintname!(m, c)
5557
dict = constrdict(m, c)
@@ -116,7 +118,7 @@ function MOI.addconstraint!(m::LinQuadOptimizer, v::SinVar, set::MOI.ZeroOne)
116118
ref
117119
end
118120

119-
MOI.candelete(m::LinQuadOptimizer, c::SVCI{MOI.ZeroOne}) = true
121+
MOI.candelete(m::LinQuadOptimizer, c::SVCI{MOI.ZeroOne}) = MOI.isvalid(m, c)
120122
function MOI.delete!(m::LinQuadOptimizer, c::SVCI{MOI.ZeroOne})
121123
deleteconstraintname!(m, c)
122124
dict = constrdict(m, c)
@@ -134,7 +136,7 @@ MOI.canget(m::LinQuadOptimizer, ::MOI.ConstraintSet, ::Type{SVCI{MOI.ZeroOne}})
134136
MOI.get(m::LinQuadOptimizer, ::MOI.ConstraintSet, c::SVCI{MOI.ZeroOne}) = MOI.ZeroOne()
135137

136138
MOI.canget(m::LinQuadOptimizer, ::MOI.ConstraintFunction, ::Type{SVCI{MOI.ZeroOne}}) = true
137-
MOI.get(m::LinQuadOptimizer, ::MOI.ConstraintFunction, c::SVCI{MOI.ZeroOne}) = m[c]
139+
MOI.get(m::LinQuadOptimizer, ::MOI.ConstraintFunction, c::SVCI{MOI.ZeroOne}) = SinVar(m[c][1])
138140

139141
#=
140142
Integer constraints
@@ -150,6 +152,7 @@ function MOI.addconstraint!(m::LinQuadOptimizer, v::SinVar, set::MOI.Integer)
150152
ref
151153
end
152154

155+
MOI.candelete(m::LinQuadOptimizer, c::SVCI{MOI.Integer}) = MOI.isvalid(m, c)
153156
function MOI.delete!(m::LinQuadOptimizer, c::SVCI{MOI.Integer})
154157
deleteconstraintname!(m, c)
155158
dict = constrdict(m, c)
@@ -160,10 +163,52 @@ function MOI.delete!(m::LinQuadOptimizer, c::SVCI{MOI.Integer})
160163
make_problem_type_continuous(m)
161164
end
162165
end
163-
MOI.candelete(m::LinQuadOptimizer, c::SVCI{MOI.Integer}) = true
164166

165167
MOI.canget(m::LinQuadOptimizer, ::MOI.ConstraintSet, ::Type{SVCI{MOI.Integer}}) = true
166168
MOI.get(m::LinQuadOptimizer, ::MOI.ConstraintSet, c::SVCI{MOI.Integer}) = MOI.Integer()
167169

168-
MOI.get(m::LinQuadOptimizer, ::MOI.ConstraintFunction, c::SVCI{MOI.Integer}) = m[c]
169170
MOI.canget(m::LinQuadOptimizer, ::MOI.ConstraintFunction, ::Type{SVCI{MOI.Integer}}) = true
171+
MOI.get(m::LinQuadOptimizer, ::MOI.ConstraintFunction, c::SVCI{MOI.Integer}) = SinVar(m[c])
172+
173+
#=
174+
Semicontinuous / Semiinteger constraints
175+
=#
176+
const SEMI_TYPES = Union{MOI.Semicontinuous{Float64}, MOI.Semiinteger{Float64}}
177+
function MOI.addconstraint!(m::LinQuadOptimizer, v::SinVar, set::SEMI_TYPES)
178+
change_variable_types!(m, [getcol(m, v)], [backend_type(m, set)])
179+
setvariablebound!(m, getcol(m, v), set.upper, backend_type(m, Val{:Upperbound}()))
180+
setvariablebound!(m, getcol(m, v), set.lower, backend_type(m, Val{:Lowerbound}()))
181+
182+
m.last_constraint_reference += 1
183+
ref = SVCI{typeof(set)}(m.last_constraint_reference)
184+
dict = constrdict(m, ref)
185+
dict[ref] = v.variable
186+
make_problem_type_integer(m)
187+
ref
188+
end
189+
190+
MOI.candelete(m::LinQuadOptimizer, c::SVCI{<:SEMI_TYPES}) = MOI.isvalid(m, c)
191+
function MOI.delete!(m::LinQuadOptimizer, c::SVCI{<:SEMI_TYPES})
192+
deleteconstraintname!(m, c)
193+
dict = constrdict(m, c)
194+
v = dict[c]
195+
change_variable_types!(m, [getcol(m, v)], [backend_type(m, Val{:Continuous}())])
196+
setvariablebound!(m, getcol(m, v), Inf, backend_type(m, Val{:Upperbound}()))
197+
setvariablebound!(m, getcol(m, v), -Inf, backend_type(m, Val{:Lowerbound}()))
198+
delete!(dict, c)
199+
if !hasinteger(m)
200+
make_problem_type_continuous(m)
201+
end
202+
end
203+
204+
MOI.canget(m::LinQuadOptimizer, ::MOI.ConstraintSet, ::Type{SVCI{S}}) where S <:SEMI_TYPES = true
205+
function MOI.get(m::LinQuadOptimizer, ::MOI.ConstraintSet, c::SVCI{S}) where S <: SEMI_TYPES
206+
dict = constrdict(m, c)
207+
v = dict[c]
208+
lb = get_variable_lowerbound(m, getcol(m, v))
209+
ub = get_variable_upperbound(m, getcol(m, v))
210+
return S(lb, ub)
211+
end
212+
213+
MOI.canget(m::LinQuadOptimizer, ::MOI.ConstraintFunction, ::Type{SVCI{S}}) where S <:SEMI_TYPES = true
214+
MOI.get(m::LinQuadOptimizer, ::MOI.ConstraintFunction, c::SVCI{<:SEMI_TYPES}) = SinVar(m[c])

src/constraints/vectoraffine.jl

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,25 @@ function MOI.modifyconstraint!(m::LinQuadOptimizer, ref::VLCI{<: VecLinSets}, ch
5656
end
5757
end
5858

59+
MOI.candelete(m::LinQuadOptimizer, c::VLCI{<:VecLinSets}) = MOI.isvalid(m, c)
60+
function MOI.delete!(m::LinQuadOptimizer, c::VLCI{<:VecLinSets})
61+
deleteconstraintname!(m, c)
62+
dict = constrdict(m, c)
63+
# we delete rows from largest to smallest here so that we don't have
64+
# to worry about updating references in a greater numbered row, only to
65+
# modify it later.
66+
for row in sort(dict[c], rev=true)
67+
delete_linear_constraints!(m, row, row)
68+
deleteat!(m.constraint_primal_solution, row)
69+
deleteat!(m.constraint_dual_solution, row)
70+
deleteat!(m.constraint_constant, row)
71+
# shift all the other references
72+
shift_references_after_delete_affine!(m, row)
73+
end
74+
delete!(dict, c)
75+
end
76+
77+
5978
#=
6079
Constraint set of Linear function
6180
=#

src/constraints/vectorofvariables.jl

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,23 @@ function MOI.addconstraint!(m::LinQuadOptimizer, func::VecVar, set::S) where S <
3030
return ref
3131
end
3232

33+
MOI.candelete(m::LinQuadOptimizer, c::VVCI{S}) where S <: VecLinSets = MOI.isvalid(m, c)
34+
function MOI.delete!(m::LinQuadOptimizer, c::VVCI{S}) where S <: VecLinSets
35+
deleteconstraintname!(m, c)
36+
dict = constrdict(m, c)
37+
# we delete rows from largest to smallest here so that we don't have
38+
# to worry about updating references in a greater numbered row, only to
39+
# modify it later.
40+
for row in sort(dict[c], rev=true)
41+
delete_linear_constraints!(m, row, row)
42+
deleteat!(m.constraint_primal_solution, row)
43+
deleteat!(m.constraint_dual_solution, row)
44+
deleteat!(m.constraint_constant, row)
45+
# shift all the other references
46+
shift_references_after_delete_affine!(m, row)
47+
end
48+
delete!(dict, c)
49+
end
3350

3451
#=
3552
Get constraint set of vector variable bound
@@ -73,7 +90,7 @@ function MOI.addconstraint!(m::LinQuadOptimizer, v::VecVar, sos::S) where S <: U
7390
ref
7491
end
7592

76-
MOI.candelete(m::LinQuadOptimizer, c::VVCI{<:Union{SOS1, SOS2}}) = true
93+
MOI.candelete(m::LinQuadOptimizer, c::VVCI{<:Union{SOS1, SOS2}}) = MOI.isvalid(m, c)
7794
function MOI.delete!(m::LinQuadOptimizer, c::VVCI{<:Union{SOS1, SOS2}})
7895
deleteconstraintname!(m, c)
7996
dict = constrdict(m, c)

src/solver_interface.jl

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,8 +40,10 @@ Three are special cases:
4040
MOI.Nonpositives - 'L'
4141
MOI.Nonnegatives - 'G'
4242
43-
MOI.ZeroOne - 'B'
44-
MOI.Integer - 'I'
43+
MOI.ZeroOne - 'B'
44+
MOI.Integer - 'I'
45+
MOI.Semicontinuous - 'S'
46+
MOI.Semiinteger - 'N'
4547
4648
MOI.SOS1 - :SOS1 # '1'
4749
MOI.SOS2 - :SOS2 # '2'
@@ -66,6 +68,8 @@ backend_type(m::LinQuadOptimizer, ::MOI.Integer) = Cchar('I')
6668
backend_type(m::LinQuadOptimizer, ::MOI.SOS1{T}) where T = :SOS1 # Cchar('1')
6769
backend_type(m::LinQuadOptimizer, ::MOI.SOS2{T}) where T = :SOS2 # Cchar('2')
6870

71+
backend_type(m::LinQuadOptimizer, ::MOI.Semicontinuous{T}) where T = Cchar('S')
72+
backend_type(m::LinQuadOptimizer, ::MOI.Semiinteger{T}) where T = Cchar('N')
6973

7074
backend_type(m::LinQuadOptimizer, ::Val{:Continuous}) = Cchar('C')
7175
backend_type(m::LinQuadOptimizer, ::Val{:Upperbound}) = Cchar('U')
@@ -218,6 +222,14 @@ the model `m`.
218222
function delete_linear_constraints! end
219223
@deprecate lqs_delrows! delete_linear_constraints!
220224

225+
"""
226+
delete_quadratic_constraints!(m, start_row::Int, end_row::Int)::Void
227+
228+
Delete the quadratic constraints `start_row`, `start_row+1`, ..., `end_row` from
229+
the model `m`.
230+
"""
231+
function delete_quadratic_constraints! end
232+
221233
"""
222234
lqs_chgctype(m, cols::Vector{Int}, types):Void
223235

0 commit comments

Comments
 (0)