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

Commit

Permalink
WIP: fix issues identified by MOI #354 (#10)
Browse files Browse the repository at this point in the history
* 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
  • Loading branch information
odow authored May 17, 2018
1 parent 3a938d1 commit 0666b30
Show file tree
Hide file tree
Showing 8 changed files with 204 additions and 23 deletions.
65 changes: 64 additions & 1 deletion src/LinQuadOptInterface.jl
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,9 @@ struct ConstraintMapping
binary::Dict{SVCI{MOI.ZeroOne}, Tuple{VarInd, Float64, Float64}}
sos1::Dict{VVCI{SOS1}, Int}
sos2::Dict{VVCI{SOS2}, Int}
semicontinuous::Dict{SVCI{MOI.Semicontinuous{Float64}}, VarInd}
semiinteger::Dict{SVCI{MOI.Semiinteger{Float64}}, VarInd}

end
ConstraintMapping() = ConstraintMapping(
Dict{LCI{LE}, Int}(),
Expand All @@ -99,8 +102,66 @@ ConstraintMapping() = ConstraintMapping(
Dict{SVCI{MOI.Integer}, VarInd}(),
Dict{SVCI{MOI.ZeroOne}, Tuple{VarInd, Float64, Float64}}(),
Dict{VVCI{SOS1}, Int}(),
Dict{VVCI{SOS2}, Int}()
Dict{VVCI{SOS2}, Int}(),
Dict{SVCI{MOI.Semicontinuous{Float64}}, VarInd}(),
Dict{SVCI{MOI.Semiinteger{Float64}}, VarInd}()
)

"""
shift_references_after_delete_affine!(m, row)
This function updates all of the references in `m`
after we have deleted row `row` in the affine constraint matrix.
"""
function shift_references_after_delete_affine!(m, row)
for scalar_affine in [
cmap(m).less_than,
cmap(m).greater_than,
cmap(m).equal_to,
cmap(m).interval
]
for (key, val) in scalar_affine
if val > row
scalar_affine[key] -= 1
end
end
end

for vector_affine in [
cmap(m).vv_nonnegatives,
cmap(m).vv_nonpositives,
cmap(m).vv_zeros
]
for (key, vals) in vector_affine
for (i, val) in enumerate(vals)
if val > row
vector_affine[key][i] -= 1
end
end
end
end
end

"""
shift_references_after_delete_quadratic!(m, row)
This function updates all of the references in `m`
after we have deleted row `row` in the quadratic constraint matrix.
"""
function shift_references_after_delete_quadratic!(m, row)
for scalar_quadratic in [
cmap(m).q_less_than,
cmap(m).q_greater_than,
cmap(m).q_equal_to
]
for (key, val) in scalar_quadratic
if val > row
scalar_quadratic[key] -= 1
end
end
end
end

function Base.isempty(map::ConstraintMapping)

ret = true
Expand All @@ -125,6 +186,8 @@ function Base.isempty(map::ConstraintMapping)
ret = ret && isempty(map.binary)
ret = ret && isempty(map.sos1)
ret = ret && isempty(map.sos2)
ret = ret && isempty(map.semiinteger)
ret = ret && isempty(map.semicontinuous)

return ret
end
Expand Down
12 changes: 10 additions & 2 deletions src/constraints.jl
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,18 @@ end
hasinteger(m::LinQuadOptimizer)::Bool
A helper function to determine if the solver instance `m` has any integer
components (i.e. binary, integer, special ordered sets, etc).
components (i.e. binary, integer, special ordered sets, semicontinuous, or
semi-integer variables).
"""
function hasinteger(m::LinQuadOptimizer)
length(cmap(m).integer) + length(cmap(m).binary) + length(cmap(m).sos1) + length(cmap(m).sos2) > 0
(
length(cmap(m).integer) +
length(cmap(m).binary) +
length(cmap(m).sos1) +
length(cmap(m).sos2) +
length(cmap(m).semicontinuous) +
length(cmap(m).semiinteger)
) > 0
end

#=
Expand Down
21 changes: 12 additions & 9 deletions src/constraints/scalaraffine.jl
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ function addlinearconstraints!(m::LinQuadOptimizer, func::Vector{Linear}, set::V
coefficients = Vector{Float64}(nnz) # corresponding non-zeros
i = 1
for (fi, f) in enumerate(func)
row_starts[fi] = cnt
row_starts[fi] = i
for (var, coef) in zip(f.variables, f.coefficients)
column_indices[i] = getcol(m, var)
coefficients[i] = coef
Expand Down Expand Up @@ -129,6 +129,13 @@ function MOI.get(m::LinQuadOptimizer, ::MOI.ConstraintSet, c::LCI{S}) where S <:
S(rhs+m.constraint_constant[m[c]])
end

MOI.canget(m::LinQuadOptimizer, ::MOI.ConstraintSet, ::Type{LCI{IV}}) = false
# TODO(odow): get constraint sets for ranged constraints.
# function MOI.get(m::LinQuadOptimizer, ::MOI.ConstraintSet, c::LCI{IV})
# ???
# IV(lowerbound+m.constraint_constant[m[c]], upperbound + m.constraint_constant[m[c]])
# end

#=
Constraint function of Linear function
=#
Expand Down Expand Up @@ -169,7 +176,7 @@ end
Delete a linear constraint
=#

MOI.candelete(m::LinQuadOptimizer, c::LCI{<: LinSets}) = true
MOI.candelete(m::LinQuadOptimizer, c::LCI{<: LinSets}) = MOI.isvalid(m, c)
function MOI.delete!(m::LinQuadOptimizer, c::LCI{<: LinSets})
deleteconstraintname!(m, c)
dict = constrdict(m, c)
Expand All @@ -178,13 +185,9 @@ function MOI.delete!(m::LinQuadOptimizer, c::LCI{<: LinSets})
deleteat!(m.constraint_primal_solution, row)
deleteat!(m.constraint_dual_solution, row)
deleteat!(m.constraint_constant, row)
deleteref!(m, row, c)
end
function deleteref!(m::LinQuadOptimizer, row::Int, ref::LCI{<: LinSets})
deleteref!(cmap(m).less_than, row, ref)
deleteref!(cmap(m).greater_than, row, ref)
deleteref!(cmap(m).equal_to, row, ref)
deleteref!(cmap(m).interval, row, ref)
# shift all the other references
shift_references_after_delete_affine!(m, row)
delete!(dict, c)
end

#=
Expand Down
14 changes: 14 additions & 0 deletions src/constraints/scalarquadratic.jl
Original file line number Diff line number Diff line change
Expand Up @@ -66,3 +66,17 @@ function reduceduplicates(rowi::Vector{T}, coli::Vector{T}, vals::Vector{S}) whe
end
ri, ci, vi
end


MOI.candelete(m::LinQuadOptimizer, c::QCI{<: LinSets}) = MOI.isvalid(m, c)
function MOI.delete!(m::LinQuadOptimizer, c::QCI{<: LinSets})
deleteconstraintname!(m, c)
dict = constrdict(m, c)
row = dict[c]
delete_quadratic_constraints!(m, row, row)
deleteat!(m.qconstraint_primal_solution, row)
deleteat!(m.qconstraint_dual_solution, row)
# shift all the other references
shift_references_after_delete_quadratic!(m, row)
delete!(dict, c)
end
61 changes: 53 additions & 8 deletions src/constraints/singlevariable.jl
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,10 @@
SingleVariable -in- EqualTo
SingleVariable -in- Interval
TODO
Binary
SingleVariable -in- ZeroOne
SingleVariable -in- Integer
SingleVariable -in- Semiinteger
SingleVariable -in- Semicontinuous
=#
constrdict(m::LinQuadOptimizer, ::SVCI{LE}) = cmap(m).upper_bound
constrdict(m::LinQuadOptimizer, ::SVCI{GE}) = cmap(m).lower_bound
Expand All @@ -19,6 +18,9 @@ constrdict(m::LinQuadOptimizer, ::SVCI{IV}) = cmap(m).interval_bound
constrdict(m::LinQuadOptimizer, ::SVCI{MOI.ZeroOne}) = cmap(m).binary
constrdict(m::LinQuadOptimizer, ::SVCI{MOI.Integer}) = cmap(m).integer

constrdict(m::LinQuadOptimizer, ::SVCI{MOI.Semicontinuous{Float64}}) = cmap(m).semicontinuous
constrdict(m::LinQuadOptimizer, ::SVCI{MOI.Semiinteger{Float64}}) = cmap(m).semiinteger

function setvariablebound!(m::LinQuadOptimizer, col::Int, bound::Float64, sense::Cchar)
change_variable_bounds!(m, [col], [bound], [sense])
end
Expand Down Expand Up @@ -49,7 +51,7 @@ function MOI.addconstraint!(m::LinQuadOptimizer, v::SinVar, set::S) where S <: L
end

# delete constraint
MOI.candelete(m::LinQuadOptimizer, c::SVCI{S}) where S <: LinSets = true
MOI.candelete(m::LinQuadOptimizer, c::SVCI{S}) where S <: LinSets = MOI.isvalid(m, c)
function MOI.delete!(m::LinQuadOptimizer, c::SVCI{S}) where S <: LinSets
deleteconstraintname!(m, c)
dict = constrdict(m, c)
Expand Down Expand Up @@ -116,7 +118,7 @@ function MOI.addconstraint!(m::LinQuadOptimizer, v::SinVar, set::MOI.ZeroOne)
ref
end

MOI.candelete(m::LinQuadOptimizer, c::SVCI{MOI.ZeroOne}) = true
MOI.candelete(m::LinQuadOptimizer, c::SVCI{MOI.ZeroOne}) = MOI.isvalid(m, c)
function MOI.delete!(m::LinQuadOptimizer, c::SVCI{MOI.ZeroOne})
deleteconstraintname!(m, c)
dict = constrdict(m, c)
Expand All @@ -134,7 +136,7 @@ MOI.canget(m::LinQuadOptimizer, ::MOI.ConstraintSet, ::Type{SVCI{MOI.ZeroOne}})
MOI.get(m::LinQuadOptimizer, ::MOI.ConstraintSet, c::SVCI{MOI.ZeroOne}) = MOI.ZeroOne()

MOI.canget(m::LinQuadOptimizer, ::MOI.ConstraintFunction, ::Type{SVCI{MOI.ZeroOne}}) = true
MOI.get(m::LinQuadOptimizer, ::MOI.ConstraintFunction, c::SVCI{MOI.ZeroOne}) = m[c]
MOI.get(m::LinQuadOptimizer, ::MOI.ConstraintFunction, c::SVCI{MOI.ZeroOne}) = SinVar(m[c][1])

#=
Integer constraints
Expand All @@ -150,6 +152,7 @@ function MOI.addconstraint!(m::LinQuadOptimizer, v::SinVar, set::MOI.Integer)
ref
end

MOI.candelete(m::LinQuadOptimizer, c::SVCI{MOI.Integer}) = MOI.isvalid(m, c)
function MOI.delete!(m::LinQuadOptimizer, c::SVCI{MOI.Integer})
deleteconstraintname!(m, c)
dict = constrdict(m, c)
Expand All @@ -160,10 +163,52 @@ function MOI.delete!(m::LinQuadOptimizer, c::SVCI{MOI.Integer})
make_problem_type_continuous(m)
end
end
MOI.candelete(m::LinQuadOptimizer, c::SVCI{MOI.Integer}) = true

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

MOI.get(m::LinQuadOptimizer, ::MOI.ConstraintFunction, c::SVCI{MOI.Integer}) = m[c]
MOI.canget(m::LinQuadOptimizer, ::MOI.ConstraintFunction, ::Type{SVCI{MOI.Integer}}) = true
MOI.get(m::LinQuadOptimizer, ::MOI.ConstraintFunction, c::SVCI{MOI.Integer}) = SinVar(m[c])

#=
Semicontinuous / Semiinteger constraints
=#
const SEMI_TYPES = Union{MOI.Semicontinuous{Float64}, MOI.Semiinteger{Float64}}
function MOI.addconstraint!(m::LinQuadOptimizer, v::SinVar, set::SEMI_TYPES)
change_variable_types!(m, [getcol(m, v)], [backend_type(m, set)])
setvariablebound!(m, getcol(m, v), set.upper, backend_type(m, Val{:Upperbound}()))
setvariablebound!(m, getcol(m, v), set.lower, backend_type(m, Val{:Lowerbound}()))

m.last_constraint_reference += 1
ref = SVCI{typeof(set)}(m.last_constraint_reference)
dict = constrdict(m, ref)
dict[ref] = v.variable
make_problem_type_integer(m)
ref
end

MOI.candelete(m::LinQuadOptimizer, c::SVCI{<:SEMI_TYPES}) = MOI.isvalid(m, c)
function MOI.delete!(m::LinQuadOptimizer, c::SVCI{<:SEMI_TYPES})
deleteconstraintname!(m, c)
dict = constrdict(m, c)
v = dict[c]
change_variable_types!(m, [getcol(m, v)], [backend_type(m, Val{:Continuous}())])
setvariablebound!(m, getcol(m, v), Inf, backend_type(m, Val{:Upperbound}()))
setvariablebound!(m, getcol(m, v), -Inf, backend_type(m, Val{:Lowerbound}()))
delete!(dict, c)
if !hasinteger(m)
make_problem_type_continuous(m)
end
end

MOI.canget(m::LinQuadOptimizer, ::MOI.ConstraintSet, ::Type{SVCI{S}}) where S <:SEMI_TYPES = true
function MOI.get(m::LinQuadOptimizer, ::MOI.ConstraintSet, c::SVCI{S}) where S <: SEMI_TYPES
dict = constrdict(m, c)
v = dict[c]
lb = get_variable_lowerbound(m, getcol(m, v))
ub = get_variable_upperbound(m, getcol(m, v))
return S(lb, ub)
end

MOI.canget(m::LinQuadOptimizer, ::MOI.ConstraintFunction, ::Type{SVCI{S}}) where S <:SEMI_TYPES = true
MOI.get(m::LinQuadOptimizer, ::MOI.ConstraintFunction, c::SVCI{<:SEMI_TYPES}) = SinVar(m[c])
19 changes: 19 additions & 0 deletions src/constraints/vectoraffine.jl
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,25 @@ function MOI.modifyconstraint!(m::LinQuadOptimizer, ref::VLCI{<: VecLinSets}, ch
end
end

MOI.candelete(m::LinQuadOptimizer, c::VLCI{<:VecLinSets}) = MOI.isvalid(m, c)
function MOI.delete!(m::LinQuadOptimizer, c::VLCI{<:VecLinSets})
deleteconstraintname!(m, c)
dict = constrdict(m, c)
# we delete rows from largest to smallest here so that we don't have
# to worry about updating references in a greater numbered row, only to
# modify it later.
for row in sort(dict[c], rev=true)
delete_linear_constraints!(m, row, row)
deleteat!(m.constraint_primal_solution, row)
deleteat!(m.constraint_dual_solution, row)
deleteat!(m.constraint_constant, row)
# shift all the other references
shift_references_after_delete_affine!(m, row)
end
delete!(dict, c)
end


#=
Constraint set of Linear function
=#
Expand Down
19 changes: 18 additions & 1 deletion src/constraints/vectorofvariables.jl
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,23 @@ function MOI.addconstraint!(m::LinQuadOptimizer, func::VecVar, set::S) where S <
return ref
end

MOI.candelete(m::LinQuadOptimizer, c::VVCI{S}) where S <: VecLinSets = MOI.isvalid(m, c)
function MOI.delete!(m::LinQuadOptimizer, c::VVCI{S}) where S <: VecLinSets
deleteconstraintname!(m, c)
dict = constrdict(m, c)
# we delete rows from largest to smallest here so that we don't have
# to worry about updating references in a greater numbered row, only to
# modify it later.
for row in sort(dict[c], rev=true)
delete_linear_constraints!(m, row, row)
deleteat!(m.constraint_primal_solution, row)
deleteat!(m.constraint_dual_solution, row)
deleteat!(m.constraint_constant, row)
# shift all the other references
shift_references_after_delete_affine!(m, row)
end
delete!(dict, c)
end

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

MOI.candelete(m::LinQuadOptimizer, c::VVCI{<:Union{SOS1, SOS2}}) = true
MOI.candelete(m::LinQuadOptimizer, c::VVCI{<:Union{SOS1, SOS2}}) = MOI.isvalid(m, c)
function MOI.delete!(m::LinQuadOptimizer, c::VVCI{<:Union{SOS1, SOS2}})
deleteconstraintname!(m, c)
dict = constrdict(m, c)
Expand Down
16 changes: 14 additions & 2 deletions src/solver_interface.jl
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,10 @@ Three are special cases:
MOI.Nonpositives - 'L'
MOI.Nonnegatives - 'G'
MOI.ZeroOne - 'B'
MOI.Integer - 'I'
MOI.ZeroOne - 'B'
MOI.Integer - 'I'
MOI.Semicontinuous - 'S'
MOI.Semiinteger - 'N'
MOI.SOS1 - :SOS1 # '1'
MOI.SOS2 - :SOS2 # '2'
Expand All @@ -66,6 +68,8 @@ backend_type(m::LinQuadOptimizer, ::MOI.Integer) = Cchar('I')
backend_type(m::LinQuadOptimizer, ::MOI.SOS1{T}) where T = :SOS1 # Cchar('1')
backend_type(m::LinQuadOptimizer, ::MOI.SOS2{T}) where T = :SOS2 # Cchar('2')

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

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

"""
delete_quadratic_constraints!(m, start_row::Int, end_row::Int)::Void
Delete the quadratic constraints `start_row`, `start_row+1`, ..., `end_row` from
the model `m`.
"""
function delete_quadratic_constraints! end

"""
lqs_chgctype(m, cols::Vector{Int}, types):Void
Expand Down

0 comments on commit 0666b30

Please sign in to comment.