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

RFC: refactor the solver-facing API #7

Merged
merged 10 commits into from
May 8, 2018
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
2 changes: 1 addition & 1 deletion REQUIRE
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
julia 0.6
MathOptInterface
MathOptInterface 0.2 0.3
20 changes: 10 additions & 10 deletions src/LinQuadOptInterface.jl
Original file line number Diff line number Diff line change
Expand Up @@ -149,10 +149,10 @@ abstract type LinQuadOptimizer <: MOI.AbstractOptimizer end
obj_sense::MOI.OptimizationSense

last_variable_reference::UInt64
variable_mapping::Dict{MathOptInterface.VariableIndex, Int}
variable_names::Dict{MathOptInterface.VariableIndex, String}
variable_names_rev::Dict{String, MathOptInterface.VariableIndex}
variable_references::Vector{MathOptInterface.VariableIndex}
variable_mapping::Dict{MOI.VariableIndex, Int}
variable_names::Dict{MOI.VariableIndex, String}
variable_names_rev::Dict{String, MOI.VariableIndex}
variable_references::Vector{MOI.VariableIndex}

variable_primal_solution::Vector{Float64}
variable_dual_solution::Vector{Float64}
Expand All @@ -173,9 +173,9 @@ abstract type LinQuadOptimizer <: MOI.AbstractOptimizer end

objective_constant::Float64

termination_status::MathOptInterface.TerminationStatusCode
primal_status::MathOptInterface.ResultStatusCode
dual_status::MathOptInterface.ResultStatusCode
termination_status::MOI.TerminationStatusCode
primal_status::MOI.ResultStatusCode
dual_status::MOI.ResultStatusCode
primal_result_count::Int
dual_result_count::Int

Expand Down Expand Up @@ -216,7 +216,7 @@ function MOI.isempty(m::LinQuadOptimizer)
end
function MOI.empty!(m::M, env = nothing) where M<:LinQuadOptimizer
m.name = ""
m.inner = LinQuadModel(M,env)
m.inner = LinearQuadraticModel(M,env)

m.obj_is_quad = false
# we assume the default is minimization
Expand Down Expand Up @@ -267,10 +267,10 @@ end
MOI.canset(m::LinQuadOptimizer, ::MOI.Name) = true

function MOI.supportsconstraint(m::LinQuadOptimizer, ft::Type{F}, st::Type{S}) where F <: MOI.AbstractFunction where S <: MOI.AbstractSet
(ft,st) in lqs_supported_constraints(m)
(ft,st) in supported_constraints(m)
end
function MOI.supports(m::LinQuadOptimizer, ::MOI.ObjectiveFunction{F}) where F <: MOI.AbstractFunction
F in lqs_supported_objectives(m)
F in supported_objectives(m)
end

# a useful helper function
Expand Down
8 changes: 4 additions & 4 deletions src/constraints.jl
Original file line number Diff line number Diff line change
Expand Up @@ -52,15 +52,15 @@ end
=#

function MOI.canaddconstraint(m::LinQuadOptimizer, f::Type{F}, s::Type{S}) where {F<:MOI.AbstractFunction, S<:MOI.AbstractSet}
return (f,s) in lqs_supported_constraints(m)
return (f,s) in supported_constraints(m)
end

#=
Get number of constraints
=#

function MOI.canget(m::LinQuadOptimizer, ::MOI.NumberOfConstraints{F, S}) where F where S
return (F,S) in lqs_supported_constraints(m)
return (F,S) in supported_constraints(m)
end
function MOI.get(m::LinQuadOptimizer, ::MOI.NumberOfConstraints{F, S}) where F where S
length(constrdict(m, CI{F,S}(UInt(0))))
Expand All @@ -71,7 +71,7 @@ end
=#

function MOI.canget(m::LinQuadOptimizer, ::MOI.ListOfConstraintIndices{F, S}) where F where S
return (F,S) in lqs_supported_constraints(m)
return (F,S) in supported_constraints(m)
end
function MOI.get(m::LinQuadOptimizer, ::MOI.ListOfConstraintIndices{F, S}) where F where S
sort(collect(keys(constrdict(m, CI{F,S}(UInt(0))))), by=x->x.value)
Expand All @@ -84,7 +84,7 @@ end
MOI.canget(m::LinQuadOptimizer, ::MOI.ListOfConstraints) = true
function MOI.get(m::LinQuadOptimizer, ::MOI.ListOfConstraints)
ret = []
for (F,S) in lqs_supported_constraints(m)
for (F,S) in supported_constraints(m)
if MOI.get(m, MOI.NumberOfConstraints{F,S}()) > 0
push!(ret, (F,S))
end
Expand Down
63 changes: 39 additions & 24 deletions src/constraints/scalaraffine.jl
Original file line number Diff line number Diff line change
Expand Up @@ -15,27 +15,26 @@ function MOI.addconstraint!(m::LinQuadOptimizer, func::Linear, set::T) where T <
m.last_constraint_reference += 1
ref = LCI{T}(m.last_constraint_reference)
dict = constrdict(m, ref)
dict[ref] = lqs_getnumrows(m)
dict[ref] = get_number_linear_constraints(m)
push!(m.constraint_primal_solution, NaN)
push!(m.constraint_dual_solution, NaN)
push!(m.constraint_constant, func.constant)
return ref
end

function addlinearconstraint!(m::LinQuadOptimizer, func::Linear, set::S) where S <: Union{LE, GE, EQ}
addlinearconstraint!(m, func, lqs_char(m,set), _getrhs(set))
addlinearconstraint!(m, func, backend_type(m,set), _getrhs(set))
end

function addlinearconstraint!(m::LinQuadOptimizer, func::Linear, set::IV)
addlinearconstraint!(m, func, lqs_char(m,set), set.lower)
lqs_chgrngval!(m, [lqs_getnumrows(m)], [set.upper - set.lower])
add_ranged_constraints!(m, [1], getcol.(m, func.variables), func.coefficients, [set.lower], [set.upper])
end

function addlinearconstraint!(m::LinQuadOptimizer, func::Linear, sense::Cchar, rhs)
if abs(func.constant) > eps(Float64)
warn("Constant in scalar function moved into set.")
end
lqs_addrows!(m, [1], getcol.(m, func.variables), func.coefficients, [sense], [rhs - func.constant])
add_linear_constraints!(m, [1], getcol.(m, func.variables), func.coefficients, [sense], [rhs - func.constant])
end

#=
Expand All @@ -47,7 +46,7 @@ function MOI.addconstraints!(m::LinQuadOptimizer, func::Vector{Linear}, set::Vec
cfunc = MOIU.canonical.(func)

@assert length(cfunc) == length(set)
numrows = lqs_getnumrows(m)
numrows = get_number_linear_constraints(m)
addlinearconstraints!(m, cfunc, set)
crefs = Vector{LCI{S}}(length(cfunc))
for i in 1:length(cfunc)
Expand All @@ -64,14 +63,35 @@ function MOI.addconstraints!(m::LinQuadOptimizer, func::Vector{Linear}, set::Vec
end

function addlinearconstraints!(m::LinQuadOptimizer, func::Vector{Linear}, set::Vector{S}) where S <: LinSets
addlinearconstraints!(m, func, lqs_char.(m,set), [_getrhs(s) for s in set])
addlinearconstraints!(m, func, backend_type.(m,set), [_getrhs(s) for s in set])
end

function addlinearconstraints!(m::LinQuadOptimizer, func::Vector{Linear}, set::Vector{IV})
numrows = lqs_getnumrows(m)
addlinearconstraints!(m, func, lqs_char.(m,set), [s.lower for s in set])
numrows2 = lqs_getnumrows(m)
lqs_chgrngval!(m, collect(numrows+1:numrows2), [s.upper - s.lower for s in set])
# loop through once to get number of non-zeros and to move rhs across
lowerbounds = [s.lower for s in set]
upperbounds = [s.upper for s in set]
nnz = 0
for (i, f) in enumerate(func)
if abs(f.constant) > eps(Float64)
warn("Constant in scalar function moved into set.")
lowerbounds[i] -= f.constant
upperbounds[i] -= f.constant
end
nnz += length(f.coefficients)
end
row_starts = Vector{Int}(length(func)) # index of start of each row
column_indices = Vector{Int}(nnz) # flattened columns for each function
coefficients = Vector{Float64}(nnz) # corresponding non-zeros
i = 1
for (fi, f) in enumerate(func)
row_starts[fi] = cnt
for (var, coef) in zip(f.variables, f.coefficients)
column_indices[i] = getcol(m, var)
coefficients[i] = coef
i += 1
end
end
add_ranged_constraints!(m, row_starts, column_indices, coefficients, lowerbounds, upperbounds)
end

function addlinearconstraints!(m::LinQuadOptimizer, func::Vector{Linear}, sense::Vector{Cchar}, rhs::Vector{Float64})
Expand All @@ -96,7 +116,7 @@ function addlinearconstraints!(m::LinQuadOptimizer, func::Vector{Linear}, sense:
cnt += 1
end
end
lqs_addrows!(m, rowbegins, column_indices, nnz_vals, sense, rhs)
add_linear_constraints!(m, rowbegins, column_indices, nnz_vals, sense, rhs)
end

#=
Expand All @@ -105,7 +125,7 @@ end

MOI.canget(m::LinQuadOptimizer, ::MOI.ConstraintSet, ::Type{LCI{S}}) where S <: Union{LE, GE, EQ} = true
function MOI.get(m::LinQuadOptimizer, ::MOI.ConstraintSet, c::LCI{S}) where S <: Union{LE, GE, EQ}
rhs = lqs_getrhs(m, m[c])
rhs = get_rhs(m, m[c])
S(rhs+m.constraint_constant[m[c]])
end

Expand All @@ -116,7 +136,7 @@ end
MOI.canget(m::LinQuadOptimizer, ::MOI.ConstraintFunction, ::Type{<:LCI{<: LinSets}}) = true
function MOI.get(m::LinQuadOptimizer, ::MOI.ConstraintFunction, c::LCI{<: LinSets})
# TODO more efficiently
colidx, coefs = lqs_getrows(m, m[c])
colidx, coefs = get_linear_constraint(m, m[c])
Linear(m.variable_references[colidx+1], coefs, -m.constraint_constant[m[c]])
end

Expand All @@ -127,7 +147,7 @@ end
MOI.canmodifyconstraint(m::LinQuadOptimizer, c::LCI{<: LinSets}, ::Type{MOI.ScalarCoefficientChange{Float64}}) = true
function MOI.modifyconstraint!(m::LinQuadOptimizer, c::LCI{<: LinSets}, chg::MOI.ScalarCoefficientChange{Float64})
col = m.variable_mapping[chg.variable]
lqs_chgcoef!(m, m[c], col, chg.new_coefficient)
change_coefficient!(m, m[c], col, chg.new_coefficient)
end

#=
Expand All @@ -137,17 +157,12 @@ end
MOI.canmodifyconstraint(m::LinQuadOptimizer, c::LCI{S}, ::Type{S}) where S <: Union{LE, GE, EQ} = true
function MOI.modifyconstraint!(m::LinQuadOptimizer, c::LCI{S}, newset::S) where S <: Union{LE, GE, EQ}
# the column 0 (or -1 in 0-index) is the rhs.
lqs_chgcoef!(m, m[c], 0, _getrhs(newset))
change_coefficient!(m, m[c], 0, _getrhs(newset))
end

MOI.canmodifyconstraint(m::LinQuadOptimizer, c::LCI{IV}, ::Type{IV}) = true
function MOI.modifyconstraint!(m::LinQuadOptimizer, c::LCI{IV}, set::IV)
# the column 0 (or -1 in 0-index) is the rhs.
# a range constraint has the RHS value of the lower limit of the range, and
# a rngval equal to upper-lower.
row = m[c]
lqs_chgcoef!(m, row, 0, set.lower)
lqs_chgrngval!(m, [row], [set.upper - set.lower])
modify_ranged_constraints!(m, [m[c]], [set.lower], [set.upper])
end

#=
Expand All @@ -159,7 +174,7 @@ function MOI.delete!(m::LinQuadOptimizer, c::LCI{<: LinSets})
deleteconstraintname!(m, c)
dict = constrdict(m, c)
row = dict[c]
lqs_delrows!(m, row, row)
delete_linear_constraints!(m, row, row)
deleteat!(m.constraint_primal_solution, row)
deleteat!(m.constraint_dual_solution, row)
deleteat!(m.constraint_constant, row)
Expand Down Expand Up @@ -189,7 +204,7 @@ end
function MOI.transformconstraint!(m::LinQuadOptimizer, ref::LCI{S1}, newset::S2) where S1 where S2 <: Union{LE, GE, EQ}
dict = constrdict(m, ref)
row = dict[ref]
lqs_chgsense!(m, [row], [lqs_char(m,newset)])
change_linear_constraint_sense!(m, [row], [backend_type(m,newset)])
m.last_constraint_reference += 1
ref2 = LCI{S2}(m.last_constraint_reference)
dict2 = constrdict(m, ref2)
Expand Down
6 changes: 3 additions & 3 deletions src/constraints/scalarquadratic.jl
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,13 @@ function MOI.addconstraint!(m::LinQuadOptimizer, func::Quad, set::S) where S <:
dict = constrdict(m, ref)
push!(m.qconstraint_primal_solution, NaN)
push!(m.qconstraint_dual_solution, NaN)
# dict[ref] = lqs_getnumqconstrs(m)
# dict[ref] = get_number_quadratic_constraints(m)
dict[ref] = length(m.qconstraint_primal_solution)
return ref
end

function addquadraticconstraint!(m::LinQuadOptimizer, func::Quad, set::S) where S<: Union{LE, GE, EQ}
addquadraticconstraint!(m, func, lqs_char(m,set), _getrhs(set))
addquadraticconstraint!(m, func, backend_type(m,set), _getrhs(set))
end

function addquadraticconstraint!(m::LinQuadOptimizer, f::Quad, sense::Cchar, rhs::Float64)
Expand All @@ -37,7 +37,7 @@ function addquadraticconstraint!(m::LinQuadOptimizer, f::Quad, sense::Cchar, rhs
getcol.(m, f.quadratic_colvariables),
f.quadratic_coefficients
)
lqs_addqconstr!(m,
add_quadratic_constraint!(m,
getcol.(m, f.affine_variables),
f.affine_coefficients,
rhs - f.constant,
Expand Down
58 changes: 32 additions & 26 deletions src/constraints/singlevariable.jl
Original file line number Diff line number Diff line change
Expand Up @@ -20,22 +20,22 @@ constrdict(m::LinQuadOptimizer, ::SVCI{MOI.ZeroOne}) = cmap(m).binary
constrdict(m::LinQuadOptimizer, ::SVCI{MOI.Integer}) = cmap(m).integer

function setvariablebound!(m::LinQuadOptimizer, col::Int, bound::Float64, sense::Cchar)
lqs_chgbds!(m, [col], [bound], [sense])
change_variable_bounds!(m, [col], [bound], [sense])
end

function setvariablebound!(m::LinQuadOptimizer, v::SinVar, set::LE)
setvariablebound!(m, getcol(m, v), set.upper, lqs_char(m, Val{:Upperbound}()))
setvariablebound!(m, getcol(m, v), set.upper, backend_type(m, Val{:Upperbound}()))
end
function setvariablebound!(m::LinQuadOptimizer, v::SinVar, set::GE)
setvariablebound!(m, getcol(m, v), set.lower, lqs_char(m, Val{:Lowerbound}()))
setvariablebound!(m, getcol(m, v), set.lower, backend_type(m, Val{:Lowerbound}()))
end
function setvariablebound!(m::LinQuadOptimizer, v::SinVar, set::EQ)
setvariablebound!(m, getcol(m, v), set.value, lqs_char(m, Val{:Upperbound}()))
setvariablebound!(m, getcol(m, v), set.value, lqs_char(m, Val{:Lowerbound}()))
setvariablebound!(m, getcol(m, v), set.value, backend_type(m, Val{:Upperbound}()))
setvariablebound!(m, getcol(m, v), set.value, backend_type(m, Val{:Lowerbound}()))
end
function setvariablebound!(m::LinQuadOptimizer, v::SinVar, set::IV)
setvariablebound!(m, getcol(m, v), set.upper, lqs_char(m, Val{:Upperbound}()))
setvariablebound!(m, getcol(m, v), set.lower, lqs_char(m, Val{:Lowerbound}()))
setvariablebound!(m, getcol(m, v), set.upper, backend_type(m, Val{:Upperbound}()))
setvariablebound!(m, getcol(m, v), set.lower, backend_type(m, Val{:Lowerbound}()))
end

# add constraint
Expand All @@ -61,17 +61,23 @@ end
# constraint set
MOI.canget(m::LinQuadOptimizer, ::MOI.ConstraintSet, ::Type{SVCI{S}}) where S <: LinSets = true
function MOI.get(m::LinQuadOptimizer, ::MOI.ConstraintSet, c::SVCI{LE})
MOI.LessThan{Float64}(lqs_getub(m, getcol(m, m[c])))
MOI.LessThan{Float64}(
get_variable_upperbound(m, getcol(m, m[c]))
)
end
function MOI.get(m::LinQuadOptimizer, ::MOI.ConstraintSet, c::SVCI{GE})
MOI.GreaterThan{Float64}(lqs_getlb(m, getcol(m, m[c])))
MOI.GreaterThan{Float64}(
get_variable_lowerbound(m, getcol(m, m[c]))
)
end
function MOI.get(m::LinQuadOptimizer, ::MOI.ConstraintSet, c::SVCI{EQ})
MOI.EqualTo{Float64}(lqs_getlb(m, getcol(m, m[c])))
MOI.EqualTo{Float64}(
get_variable_lowerbound(m, getcol(m, m[c]))
)
end
function MOI.get(m::LinQuadOptimizer, ::MOI.ConstraintSet, c::SVCI{IV})
lb = lqs_getlb(m, getcol(m, m[c]))
ub = lqs_getub(m, getcol(m, m[c]))
lb = get_variable_lowerbound(m, getcol(m, m[c]))
ub = get_variable_upperbound(m, getcol(m, m[c]))
return MOI.Interval{Float64}(lb, ub)
end

Expand Down Expand Up @@ -100,13 +106,13 @@ function MOI.addconstraint!(m::LinQuadOptimizer, v::SinVar, set::MOI.ZeroOne)
m.last_constraint_reference += 1
ref = SVCI{MOI.ZeroOne}(m.last_constraint_reference)
dict = constrdict(m, ref)
ub = lqs_getub(m, getcol(m, v))
lb = lqs_getlb(m, getcol(m, v))
ub = get_variable_upperbound(m, getcol(m, v))
lb = get_variable_lowerbound(m, getcol(m, v))
dict[ref] = (v.variable, lb, ub)
lqs_chgctype!(m, [getcol(m, v)], [lqs_char(m, set)])
setvariablebound!(m, getcol(m, v), 1.0, lqs_char(m, Val{:Upperbound}()))
setvariablebound!(m, getcol(m, v), 0.0, lqs_char(m, Val{:Lowerbound}()))
lqs_make_problem_type_integer(m)
change_variable_types!(m, [getcol(m, v)], [backend_type(m, set)])
setvariablebound!(m, getcol(m, v), 1.0, backend_type(m, Val{:Upperbound}()))
setvariablebound!(m, getcol(m, v), 0.0, backend_type(m, Val{:Lowerbound}()))
make_problem_type_integer(m)
ref
end

Expand All @@ -115,12 +121,12 @@ function MOI.delete!(m::LinQuadOptimizer, c::SVCI{MOI.ZeroOne})
deleteconstraintname!(m, c)
dict = constrdict(m, c)
(v, lb, ub) = dict[c]
lqs_chgctype!(m, [getcol(m, v)], [lqs_char(m, Val{:Continuous}())])
setvariablebound!(m, getcol(m, v), ub, lqs_char(m, Val{:Upperbound}()))
setvariablebound!(m, getcol(m, v), lb, lqs_char(m, Val{:Lowerbound}()))
change_variable_types!(m, [getcol(m, v)], [backend_type(m, Val{:Continuous}())])
setvariablebound!(m, getcol(m, v), ub, backend_type(m, Val{:Upperbound}()))
setvariablebound!(m, getcol(m, v), lb, backend_type(m, Val{:Lowerbound}()))
delete!(dict, c)
if !hasinteger(m)
lqs_make_problem_type_continuous(m)
make_problem_type_continuous(m)
end
end

Expand All @@ -135,23 +141,23 @@ MOI.get(m::LinQuadOptimizer, ::MOI.ConstraintFunction, c::SVCI{MOI.ZeroOne}) = m
=#

function MOI.addconstraint!(m::LinQuadOptimizer, v::SinVar, set::MOI.Integer)
lqs_chgctype!(m, [getcol(m, v)], [lqs_char(m, set)])
change_variable_types!(m, [getcol(m, v)], [backend_type(m, set)])
m.last_constraint_reference += 1
ref = SVCI{MOI.Integer}(m.last_constraint_reference)
dict = constrdict(m, ref)
dict[ref] = v.variable
lqs_make_problem_type_integer(m)
make_problem_type_integer(m)
ref
end

function MOI.delete!(m::LinQuadOptimizer, c::SVCI{MOI.Integer})
deleteconstraintname!(m, c)
dict = constrdict(m, c)
v = dict[c]
lqs_chgctype!(m, [getcol(m, v)], [lqs_char(m, Val{:Continuous}())])
change_variable_types!(m, [getcol(m, v)], [backend_type(m, Val{:Continuous}())])
delete!(dict, c)
if !hasinteger(m)
lqs_make_problem_type_continuous(m)
make_problem_type_continuous(m)
end
end
MOI.candelete(m::LinQuadOptimizer, c::SVCI{MOI.Integer}) = true
Expand Down
Loading