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

RFC: various fixes for the latest MOI #5

Merged
merged 13 commits into from
May 1, 2018
36 changes: 30 additions & 6 deletions src/LinQuadOptInterface.jl
Original file line number Diff line number Diff line change
Expand Up @@ -133,13 +133,18 @@ end
# Abstract + macro
abstract type LinQuadOptimizer <: MOI.AbstractOptimizer end
@def LinQuadOptimizerBase begin

inner#::LinQuadOptInterface.LinQuadOptimizer

name::String

obj_is_quad::Bool
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_primal_solution::Vector{Float64}
Expand All @@ -149,13 +154,16 @@ abstract type LinQuadOptimizer <: MOI.AbstractOptimizer end
constraint_mapping::LinQuadOptInterface.ConstraintMapping

constraint_constant::Vector{Float64}

constraint_primal_solution::Vector{Float64}
constraint_dual_solution::Vector{Float64}

qconstraint_primal_solution::Vector{Float64}
qconstraint_dual_solution::Vector{Float64}

# TODO(odow): temp hack for constraint names
constraint_names::Dict{Any, String}
constraint_names_rev::Dict{String, Any}

objective_constant::Float64

termination_status::MathOptInterface.TerminationStatusCode
Expand All @@ -170,11 +178,13 @@ end
function MOI.isempty(m::LinQuadOptimizer)

ret = true

ret = ret && m.name == ""
ret = ret && m.obj_is_quad == false
ret = ret && m.obj_sense == MOI.FeasibilitySense
ret = ret && m.last_variable_reference == 0
ret = ret && isempty(m.variable_mapping)
ret = ret && isempty(m.variable_names)
ret = ret && isempty(m.variable_names_rev)
ret = ret && isempty(m.variable_references)
ret = ret && isempty(m.variable_primal_solution)
ret = ret && isempty(m.variable_dual_solution)
Expand All @@ -185,6 +195,8 @@ function MOI.isempty(m::LinQuadOptimizer)
ret = ret && isempty(m.constraint_dual_solution)
ret = ret && isempty(m.qconstraint_primal_solution)
ret = ret && isempty(m.qconstraint_dual_solution)
ret = ret && isempty(m.constraint_names)
ret = ret && isempty(m.constraint_names_rev)
ret = ret && m.objective_constant == 0.0
ret = ret && m.termination_status == MOI.OtherError
ret = ret && m.primal_status == MOI.UnknownResultStatus
Expand All @@ -196,14 +208,16 @@ function MOI.isempty(m::LinQuadOptimizer)
return ret
end
function MOI.empty!(m::M, env = nothing) where M<:LinQuadOptimizer

m.name = ""
m.inner = LinQuadModel(M,env)

m.obj_is_quad = false
m.obj_sense = MOI.FeasibilitySense

m.last_variable_reference = 0
m.variable_mapping = Dict{MathOptInterface.VariableIndex, Int}()
m.variable_names = Dict{MathOptInterface.VariableIndex, String}()
m.variable_names_rev = Dict{String, MathOptInterface.VariableIndex}()
m.variable_references = MathOptInterface.VariableIndex[]

m.variable_primal_solution = Float64[]
Expand All @@ -213,13 +227,15 @@ function MOI.empty!(m::M, env = nothing) where M<:LinQuadOptimizer
m.constraint_mapping = LinQuadOptInterface.ConstraintMapping()

m.constraint_constant = Float64[]

m.constraint_primal_solution = Float64[]
m.constraint_dual_solution = Float64[]

m.qconstraint_primal_solution = Float64[]
m.qconstraint_dual_solution = Float64[]

m.constraint_names = Dict{Any, String}()
m.constraint_names_rev = Dict{String, Any}()

m.objective_constant = 0.0

m.termination_status = MathOptInterface.OtherError
Expand All @@ -233,6 +249,14 @@ function MOI.empty!(m::M, env = nothing) where M<:LinQuadOptimizer
nothing
end

function MOI.get(m::LinQuadOptimizer, ::MOI.Name)
m.name
end
MOI.canget(m::LinQuadOptimizer, ::MOI.Name) = true
function MOI.set!(m::LinQuadOptimizer, ::MOI.Name, name::String)
m.name = name
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)
Expand All @@ -257,6 +281,6 @@ include("objective.jl")
include("solve.jl")
include("copy.jl")

include("ref.jl")
include("solver_interface.jl")

end
end
62 changes: 56 additions & 6 deletions src/constraints.jl
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ end
=#

function MOI.get(m::LinQuadOptimizer, ::MOI.ListOfConstraintIndices{F, S}) where F where S
collect(keys(constrdict(m, CI{F,S}(UInt(0)))))
sort(collect(keys(constrdict(m, CI{F,S}(UInt(0))))), by=x->x.value)
end
function MOI.canget(m::LinQuadOptimizer, ::MOI.ListOfConstraintIndices{F, S}) where F where S
return (F,S) in lqs_supported_constraints(m)
Expand Down Expand Up @@ -131,6 +131,48 @@ function setvariablebound!(m::LinQuadOptimizer, v::SinVar, set::IV)
setvariablebound!(m, getcol(m, v), set.lower, _variablelb(m))
end

function MOI.get(m::LinQuadOptimizer, ::MOI.ConstraintName, c::MOI.ConstraintIndex)
if haskey(m.constraint_names, c)
m.constraint_names[c]
else
""
end
end
MOI.canget(m::LinQuadOptimizer, ::MOI.ConstraintName, ::Type{<:MOI.ConstraintIndex}) = true
function MOI.set!(m::LinQuadOptimizer, ::MOI.ConstraintName, ref::MOI.ConstraintIndex, name::String)
if haskey(m.constraint_names_rev, name)
if m.constraint_names_rev[name] != ref
error("Duplicate constraint name: $(name)")
end
elseif name != ""
if haskey(m.constraint_names, ref)
# we're renaming an existing constraint
old_name = m.constraint_names[ref]
delete!(m.constraint_names_rev, old_name)
end
m.constraint_names[ref] = name
m.constraint_names_rev[name] = ref
end
end
MOI.canset(m::LinQuadOptimizer, ::MOI.ConstraintName, ::Type{<:MOI.ConstraintIndex}) = true

function deleteconstraintname!(m::LinQuadOptimizer, ref)
if haskey(m.constraint_names, ref)
name = m.constraint_names[ref]
delete!(m.constraint_names_rev, name)
delete!(m.constraint_names, ref)
end
end

function MOI.get(m::LinQuadOptimizer, ::Type{<:MOI.ConstraintIndex}, name::String)
m.constraint_names_rev[name]
end
MOI.canget(m::LinQuadOptimizer, ::Type{MOI.ConstraintIndex}, name::String) = haskey(m.constraint_names_rev, name)

function MOI.canget(m::LinQuadOptimizer, ::Type{FS}, name::String) where FS <: MOI.ConstraintIndex
haskey(m.constraint_names_rev, name) && typeof(m.constraint_names_rev[name]) == FS
end

function MOI.addconstraint!(m::LinQuadOptimizer, v::SinVar, set::S) where S <: LinSets
setvariablebound!(m, v, set)
m.last_constraint_reference += 1
Expand Down Expand Up @@ -186,6 +228,7 @@ MOI.canmodifyconstraint(::LinQuadOptimizer, ::SVCI{S}, ::Type{S}) where S <: Lin
=#

function MOI.delete!(m::LinQuadOptimizer, c::SVCI{S}) where S <: LinSets
deleteconstraintname!(m, c)
dict = constrdict(m, c)
vref = dict[c]
setvariablebound!(m, SinVar(vref), IV(-Inf, Inf))
Expand Down Expand Up @@ -216,14 +259,14 @@ function MOI.addconstraint!(m::LinQuadOptimizer, func::VecVar, set::S) where S <

n = MOI.dimension(set)
lqs_addrows!(m, collect(1:n), getcol.(m, func.variables), ones(n), fill(_getsense(m,set),n), zeros(n))

dict = constrdict(m, ref)

dict[ref] = collect(rows+1:rows+n)

append!(m.constraint_primal_solution, fill(NaN,n))
append!(m.constraint_dual_solution, fill(NaN,n))
append!(m.constraint_constant, fill(0.0,n))
append!(m.constraint_constant, fill(0.0,n))
return ref
end

Expand Down Expand Up @@ -278,11 +321,12 @@ function unsafe_addconstraint!(m::LinQuadOptimizer, func::Linear, set::T) where
addlinearconstraint!(m, func, set)
m.last_constraint_reference += 1
ref = LCI{T}(m.last_constraint_reference)

dict = constrdict(m, ref)
dict[ref] = lqs_getnumrows(m)
push!(m.constraint_primal_solution, NaN)
push!(m.constraint_dual_solution, NaN)
push!(m.constraint_constant, func.constant)
push!(m.constraint_constant, func.constant)
return ref
end

Expand Down Expand Up @@ -429,6 +473,7 @@ function deleteref!(m::LinQuadOptimizer, row::Int, ref::LCI{<: LinSets})
deleteref!(cmap(m).interval, row, ref)
end
function MOI.delete!(m::LinQuadOptimizer, c::LCI{<: LinSets})
deleteconstraintname!(m, c)
dict = constrdict(m, c)
row = dict[c]
lqs_delrows!(m, row, row)
Expand Down Expand Up @@ -473,6 +518,7 @@ function MOI.addconstraint!(m::LinQuadOptimizer, v::SinVar, ::MOI.ZeroOne)
ref
end
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_vartype_map(m)[:CONTINUOUS]])
Expand Down Expand Up @@ -509,6 +555,7 @@ function MOI.addconstraint!(m::LinQuadOptimizer, v::SinVar, ::MOI.Integer)
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_vartype_map(m)[:CONTINUOUS]])
Expand Down Expand Up @@ -553,6 +600,7 @@ function MOI.addconstraint!(m::LinQuadOptimizer, v::VecVar, sos::SOS2)
end

function MOI.delete!(m::LinQuadOptimizer, c::VVCI{<:Union{SOS1, SOS2}})
deleteconstraintname!(m, c)
dict = constrdict(m, c)
idx = dict[c]
lqs_delsos!(m, idx, idx)
Expand Down Expand Up @@ -597,9 +645,10 @@ function MOI.addconstraint!(m::LinQuadOptimizer, func::Quad, set::S) where S <:
m.last_constraint_reference += 1
ref = QCI{S}(m.last_constraint_reference)
dict = constrdict(m, ref)
dict[ref] = lqs_getnumqconstrs(m)
push!(m.qconstraint_primal_solution, NaN)
push!(m.qconstraint_dual_solution, NaN)
# dict[ref] = lqs_getnumqconstrs(m)
dict[ref] = length(m.qconstraint_primal_solution)
return ref
end

Expand Down Expand Up @@ -752,11 +801,12 @@ function MOI.transformconstraint!(m::LinQuadOptimizer, ref::LCI{S1}, newset::S2)
dict2 = constrdict(m, ref2)
dict2[ref2] = row
delete!(dict, ref)
deleteconstraintname!(m, ref)
return ref2
end
function MOI.cantransformconstraint(m::LinQuadOptimizer, ref::LCI{S}, newset::S) where S
false
end
function MOI.cantransformconstraint(m::LinQuadOptimizer, ref::LCI{S1}, newset::S2) where S1 where S2 <: Union{LE, GE, EQ}
true
end
end
13 changes: 8 additions & 5 deletions src/copy.jl
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
MOI.copy!(dest::LinQuadOptimizer, src::MOI.ModelLike) = MOIU.defaultcopy!(dest, src)
MOI.copy!(dest::MOI.ModelLike, src::LinQuadOptimizer) = MOIU.defaultcopy!(dest, src)
MOI.copy!(dest::LinQuadOptimizer, src::LinQuadOptimizer) = MOIU.defaultcopy!(dest, src)
MOI.copy!(dest::LinQuadOptimizer, src::MOI.ModelLike; copynames=false) = MOIU.defaultcopy!(dest, src, copynames)
MOI.copy!(dest::MOI.ModelLike, src::LinQuadOptimizer; copynames=false) = MOIU.defaultcopy!(dest, src, copynames)
MOI.copy!(dest::LinQuadOptimizer, src::LinQuadOptimizer; copynames=false) = MOIU.defaultcopy!(dest, src, copynames)

MOI.canget(::LinQuadOptimizer, ::MOI.ListOfVariableAttributesSet) = true
MOI.get(::LinQuadOptimizer, ::MOI.ListOfVariableAttributesSet) = MOI.AbstractVariableAttribute[]
MOI.canget(::LinQuadOptimizer, ::MOI.ListOfModelAttributesSet) = true
MOI.get(::LinQuadOptimizer, ::MOI.ListOfModelAttributesSet) = [MOI.ObjectiveSense, MOI.ObjectiveFunction{MOI.ScalarAffineFunction{Float64}}]
MOI.get(m::LinQuadOptimizer, ::MOI.ListOfModelAttributesSet) = [
MOI.ObjectiveSense,
MOI.ObjectiveFunction{MOI.ScalarAffineFunction{Float64}},
(MOI.get(m, MOI.Name()) != "") ? MOI.Name() : nothing
]
MOI.canget(::LinQuadOptimizer, ::MOI.ListOfConstraintAttributesSet{F,S}) where F where S = true
MOI.get(::LinQuadOptimizer, ::MOI.ListOfConstraintAttributesSet{F,S}) where F where S = MOI.AbstractConstraintAttribute[]

10 changes: 5 additions & 5 deletions src/objective.jl
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ MOI.canset(m::LinQuadOptimizer, ::Type{MOI.ObjectiveFunction{F}}) where F<:MOI.A
function MOI.canset(m::LinQuadOptimizer, ::MOI.ObjectiveFunction{F}) where F<:MOI.AbstractFunction
return F in lqs_supported_objectives(m)
end
MOI.set!(m::LinQuadOptimizer, ::Type{MOI.ObjectiveFunction{F}}, objf::Linear) where F = MOI.set!(m, MOI.ObjectiveFunction{F}(), objf::Linear)
MOI.set!(m::LinQuadOptimizer, ::Type{MOI.ObjectiveFunction{F}}, objf::Linear) where F = MOI.set!(m, MOI.ObjectiveFunction{F}(), objf::Linear)
function MOI.set!(m::LinQuadOptimizer, ::MOI.ObjectiveFunction{F}, objf::Linear) where F
cobjf = MOIU.canonical(objf)
unsafe_set!(m, MOI.ObjectiveFunction{Linear}(), cobjf)
Expand All @@ -36,13 +36,13 @@ end

function _setsense!(m::LinQuadOptimizer, sense::MOI.OptimizationSense)
if sense == MOI.MinSense
lqs_chgobjsen!(m, :Min)
lqs_chgobjsen!(m, :min)
m.obj_sense = MOI.MinSense
elseif sense == MOI.MaxSense
lqs_chgobjsen!(m, :Max)
lqs_chgobjsen!(m, :max)
m.obj_sense = MOI.MaxSense
elseif sense == MOI.FeasibilitySense
lqs_chgobjsen!(m, :Min)
lqs_chgobjsen!(m, :min)
unsafe_set!(m, MOI.ObjectiveFunction{Linear}(), MOI.ScalarAffineFunction(VarInd[],Float64[],0.0))
m.obj_is_quad = false
m.obj_sense = MOI.FeasibilitySense
Expand Down Expand Up @@ -108,4 +108,4 @@ function MOI.set!(m::LinQuadOptimizer, ::MOI.ObjectiveFunction, objf::Quad)
)
m.objective_constant = objf.constant
nothing
end
end
Loading