Skip to content

Commit

Permalink
Merge pull request #10 from joaquimg/jg/updates
Browse files Browse the repository at this point in the history
Updates
  • Loading branch information
joaquimg authored Aug 8, 2020
2 parents 88b7106 + f229335 commit 7f49070
Show file tree
Hide file tree
Showing 6 changed files with 230 additions and 68 deletions.
7 changes: 1 addition & 6 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,8 @@ os:
- linux
julia:
- 1.0
- 1.3
- nightly
- 1.4
codecov: true
notifications:
email: false

jobs:
allow_failures:
- julia: nightly

2 changes: 1 addition & 1 deletion Project.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ MathOptInterface = "b8f27783-ece8-5eb3-8dc8-9495eed66fee"
DataStructures = "864edb3b-99cc-5e75-8d2d-829cb0a9cfe8"

[compat]
MathOptInterface = "~0.9.12"
MathOptInterface = "0.9.12"
DataStructures = "0.17.10"
julia = "1"

Expand Down
6 changes: 6 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,12 @@ MOI.set(model, QuadraticToBinary.VariablePrecision(), vi, val)
The precision for each varible will be `val * (UB - LB)`. Where `UB` and `LB` are,
respectively, the upper and lower bound of the variable.

For the sake of simplicity, the following two attributes are made available:
`QuadraticToBinary.FallbackUpperBound` and `QuadraticToBinary.FallbackLowerBound`.
As usual, these can be get and set with the `MOI.get` and `MOI.set` methods.
These allow setting bounds used in variables that have no explicit upper bounds
and need to be expanded.


## Reference

Expand Down
214 changes: 153 additions & 61 deletions src/moi.jl
Original file line number Diff line number Diff line change
Expand Up @@ -10,43 +10,6 @@ const EQ{T} = MOI.EqualTo{T}
const LT{T} = MOI.LessThan{T}
const GT{T} = MOI.GreaterThan{T}

# same as MOI except for quad stuff
MOIU.@model(NonQuadraticModel,
(MOI.ZeroOne, MOI.Integer),
(MOI.EqualTo, MOI.GreaterThan, MOI.LessThan, MOI.Interval,
MOI.Semicontinuous, MOI.Semiinteger),
(MOI.Reals, MOI.Zeros, MOI.Nonnegatives, MOI.Nonpositives,
MOI.Complements, MOI.NormInfinityCone, MOI.NormOneCone,
MOI.SecondOrderCone, MOI.RotatedSecondOrderCone,
MOI.GeometricMeanCone, MOI.ExponentialCone, MOI.DualExponentialCone,
MOI.RelativeEntropyCone, MOI.NormSpectralCone, MOI.NormNuclearCone,
MOI.PositiveSemidefiniteConeTriangle, MOI.PositiveSemidefiniteConeSquare,
MOI.RootDetConeTriangle, MOI.RootDetConeSquare, MOI.LogDetConeTriangle,
MOI.LogDetConeSquare),
(MOI.PowerCone, MOI.DualPowerCone, MOI.SOS1, MOI.SOS2),
(),
(MOI.ScalarAffineFunction,),
(MOI.VectorOfVariables,),
(MOI.VectorAffineFunction,))

MOIU.@model(PureQuadraticModel,
(MOI.ZeroOne, MOI.Integer),
(MOI.EqualTo, MOI.GreaterThan, MOI.LessThan, MOI.Interval,
MOI.Semicontinuous, MOI.Semiinteger),
(MOI.Reals, MOI.Zeros, MOI.Nonnegatives, MOI.Nonpositives,
MOI.Complements, MOI.NormInfinityCone, MOI.NormOneCone,
MOI.SecondOrderCone, MOI.RotatedSecondOrderCone,
MOI.GeometricMeanCone, MOI.ExponentialCone, MOI.DualExponentialCone,
MOI.RelativeEntropyCone, MOI.NormSpectralCone, MOI.NormNuclearCone,
MOI.PositiveSemidefiniteConeTriangle, MOI.PositiveSemidefiniteConeSquare,
MOI.RootDetConeTriangle, MOI.RootDetConeSquare, MOI.LogDetConeTriangle,
MOI.LogDetConeSquare),
(MOI.PowerCone, MOI.DualPowerCone, MOI.SOS1, MOI.SOS2,),
(),
(MOI.ScalarQuadraticFunction,),
(),
(MOI.VectorQuadraticFunction,))

const SCALAR_SETS = Union{
MOI.GreaterThan{Float64},
MOI.LessThan{Float64},
Expand Down Expand Up @@ -164,19 +127,25 @@ mutable struct Optimizer{T, OT <: MOI.ModelLike} <: MOI.AbstractOptimizer

has_quad_change::Bool

function Optimizer{T}(optimizer::OT) where {T, OT <: MOI.ModelLike}
fallback_lb::Float64
fallback_ub::Float64

function Optimizer{T}(optimizer::OT; lb = -Inf, ub = +Inf, global_precision = 1e-4
) where {T, OT <: MOI.ModelLike}
# TODO optimizer must support binary, and affine in less and greater
return new{T, OT}(
optimizer,
1e-4,
global_precision,
nothing,
Dict{CI, MOI.ScalarQuadraticFunction{T}}(),
Dict{CI, MOI.VectorQuadraticFunction{T}}(),
Dict{VI, VariableInfo}(),
Dict{CI, VI}(),
Dict{Tuple{VI,VI}, VI}(),
nothing,
false
false,
lb,
ub,
)
end
end
Expand Down Expand Up @@ -522,16 +491,38 @@ function MOI.set(model::Optimizer, attr::MOI.ConstraintFunction,
error("Operation not allowed. Quadratic functions cant be modified.")
end

function MOI.add_constrained_variable(model::Optimizer, s::S
) where {S<:MOI.AbstractScalarSet}
v, c = MOI.add_constrained_variable(model.optimizer, s)
model.original_variables[v] = VariableInfo()
return v, c
end
function MOI.add_constrained_variables(model::Optimizer, s::Vector{S}
) where {S<:MOI.AbstractScalarSet}
vs, cs = MOI.add_constrained_variables(model.optimizer, s)
for v in vs
model.original_variables[v] = VariableInfo()
end
return vs, cs
end
function MOI.add_constrained_variables(model::Optimizer, s::S
) where {S<:MOI.AbstractVectorSet}
vs, cs = MOI.add_constrained_variables(model.optimizer, s)
for v in vs
model.original_variables[v] = VariableInfo()
end
return vs, cs
end

function MOI.add_constraint(model::Optimizer, f::F, s::S
) where {F<:MOI.AbstractFunction, S<:MOI.AbstractSet}
ci = MOI.add_constraint(model.optimizer, f, s)
return ci
return MOI.add_constraint(model.optimizer, f, s)
end
function MOI.add_constraints(model::Optimizer, f::Vector{F}, s::Vector{S}
) where {F, S}
cis = MOI.add_constraints(model.optimizer, f, s)
return cis
return MOI.add_constraints(model.optimizer, f, s)
end

function MOI.add_constraint(model::Optimizer, f::F, s::S
) where {F<:QuadraticFunction{T}, S<:MOI.AbstractSet} where T
fc = MOIU.canonical(f)
Expand Down Expand Up @@ -718,6 +709,35 @@ function cache_bounds(
return
end

function MOI.add_constrained_variables(
model::Optimizer, s::Vector{S}
) where {S <: SCALAR_SETS}
vs, c = MOI.add_constrained_variables(model.optimizer, s)
# from add var
for v in vs
model.original_variables[v] = VariableInfo()
end
# from add con
f = MOI.SingleVariable.(vs)
for i in eachindex(f)
cache_bounds(model, f[i], s[i])
model.ci_to_var[c[i]] = f[i].variable
end
return vs, c
end
function MOI.add_constrained_variable(
model::Optimizer, s::S
) where {S <: SCALAR_SETS}
v, ci = MOI.add_constrained_variable(model.optimizer, s)
# from add var
model.original_variables[v] = VariableInfo()
# from add con
f = MOI.SingleVariable(v)
cache_bounds(model, f, s)
model.ci_to_var[ci] = f.variable
return v, ci
end

function MOI.add_constraints(
model::Optimizer, f::Vector{MOI.SingleVariable}, s::Vector{S}
) where {S <: SCALAR_SETS}
Expand Down Expand Up @@ -822,6 +842,40 @@ end

scalar_type(S::Type{MOI.ZeroOne}) = BINARY
scalar_type(S::Type{MOI.Integer}) = INTEGER

function MOI.add_constrained_variables(
model::Optimizer, s::Vector{S}
) where {S <: SCALAR_TYPES}
vs, c = MOI.add_constrained_variables(model.optimizer, s)
# from add var
for v in vs
model.original_variables[v] = VariableInfo()
end
# from add con
f = MOI.SingleVariable.(vs)
for i in eachindex(f)
info = model.original_variables[f[i].variable]
info.type = scalar_type(S)
end
for i in eachindex(c)
model.ci_to_var[c[i]] = f[i].variable
end
return vs, c
end
function MOI.add_constrained_variable(
model::Optimizer, s::S
) where {S <: SCALAR_TYPES}
v, ci = MOI.add_constrained_variable(model.optimizer, s)
# from add var
model.original_variables[v] = VariableInfo()
# from add con
f = MOI.SingleVariable(v)
info = model.original_variables[f.variable]
info.type = scalar_type(S)
model.ci_to_var[ci] = f.variable
return v, ci
end

function MOI.add_constraints(
model::Optimizer, f::Vector{MOI.SingleVariable}, s::Vector{S}
) where {S <: SCALAR_TYPES}
Expand Down Expand Up @@ -929,9 +983,22 @@ function delete_additional_constraints(model)
end
end


lower(info) = info.type == BINARY ? zero(typeof(info.lower)) : info.lower
upper(info) = info.type == BINARY ? one(typeof(info.lower)) : info.upper
function lower(model, info)
if info.type == BINARY
return zero(typeof(info.lower))
elseif info.lower > -Inf
return info.lower
end
return model.fallback_lb
end
function upper(model, info)
if info.type == BINARY
return one(typeof(info.lower))
elseif info.upper < Inf
return info.upper
end
return model.fallback_ub
end
function get_precision(model::Optimizer{T}, x) where T
info = model.original_variables[x]
a = model.global_initial_precision
Expand Down Expand Up @@ -1006,10 +1073,10 @@ function build_approximation!(model::Optimizer)
for pair in QT
for x in pair
info = model.original_variables[x]
if !(upper(info) < Inf)
if !(upper(model, info) < Inf)
error("Variable $x has no upper bound.")
end
if !(lower(info) > -Inf)
if !(lower(model, info) > -Inf)
error("Variable $x has no lower bound.")
end
end
Expand Down Expand Up @@ -1054,8 +1121,8 @@ function build_approximation!(model::Optimizer)
s28 = EQ{T}[]
for xj in DS
info = model.original_variables[xj]
Xu = upper(info)
Xl = lower(info)
Xu = upper(model, info)
Xl = lower(model, info)
Δxj = Δx[xj]
zj = z[xj]
terms = [
Expand All @@ -1081,8 +1148,8 @@ function build_approximation!(model::Optimizer)
xj = xa
end
info = model.original_variables[xj]
Xu = upper(info)
Xl = lower(info)
Xu = upper(model, info)
Xl = lower(model, info)
#order is important in the pairs
Δwij = Δw[(xa,xb)]
wij = w[(xa,xb)]
Expand Down Expand Up @@ -1132,8 +1199,8 @@ function build_approximation!(model::Optimizer)
xj = xa
end
info_i = model.original_variables[xi]
Xu_i = upper(info_i)
Xl_i = lower(info_i)
Xu_i = upper(model, info_i)
Xl_i = lower(model, info_i)
Δwij = Δw[(xa,xb)]
Δxj = Δx[xj]
p = get_precision(model, xj)
Expand Down Expand Up @@ -1190,8 +1257,8 @@ function build_approximation!(model::Optimizer)
xj = xa
end
info_i = model.original_variables[xi]
Xu_i = upper(info_i)
Xl_i = lower(info_i)
Xu_i = upper(model, info_i)
Xl_i = lower(model, info_i)
zj = z[xj]
xhij = xh[(xa,xb)]
# 33
Expand Down Expand Up @@ -1362,6 +1429,8 @@ end

struct VariablePrecision end
struct GlobalVariablePrecision end
struct FallbackUpperBound end
struct FallbackLowerBound end

function MOI.set(
model::Optimizer,
Expand All @@ -1382,7 +1451,7 @@ end

function MOI.set(
model::Optimizer,
attr::GlobalVariablePrecision,
::GlobalVariablePrecision,
value::Union{Nothing, Float64}
)
val = value === nothing ? NaN : value
Expand All @@ -1391,18 +1460,41 @@ function MOI.set(
return
end
function MOI.get(
model::Optimizer, attr::GlobalVariablePrecision, x::MOI.VariableIndex
model::Optimizer, ::GlobalVariablePrecision, x::MOI.VariableIndex
)
return model.global_initial_precision
end

function MOI.get(model::Optimizer, attr::MOI.NumberOfConstraints{F, S}) where {F, S}
function MOI.set(model::Optimizer, ::FallbackLowerBound, val)
model.fallback_lb = val
return nothing
end
function MOI.set(model::Optimizer, ::FallbackLowerBound, ::Nothing)
model.fallback_lb = -Inf
return nothing
end
function MOI.get(model::Optimizer, ::FallbackLowerBound)
return model.fallback_lb
end
function MOI.set(model::Optimizer, ::FallbackUpperBound, val)
model.fallback_ub = val
return nothing
end
function MOI.set(model::Optimizer, ::FallbackUpperBound, ::Nothing)
model.fallback_ub = Inf
return nothing
end
function MOI.get(model::Optimizer, ::FallbackUpperBound)
return model.fallback_ub
end

function MOI.get(model::Optimizer, ::MOI.NumberOfConstraints{F, S}) where {F, S}
# TODO: this could be more efficient.
return length(MOI.get(model, MOI.ListOfConstraintIndices{F,S}()))
end


function MOI.get(model::Optimizer, ::MOI.ListOfConstraints)
function MOI.get(::Optimizer, ::MOI.ListOfConstraints)
constraints = Set{Tuple{DataType, DataType}}()
error("TODO")
end
Expand Down
Loading

0 comments on commit 7f49070

Please sign in to comment.