Skip to content
This repository was archived by the owner on Jun 14, 2020. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@joaquimg I added this method to the API

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice! Are there MOI tests for deleting quadratics?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.


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

Expand Down