Skip to content

Define operate and refactor moivcat #455

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 12 commits into from
Aug 16, 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
4 changes: 0 additions & 4 deletions src/Bridges/Bridges.jl
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,6 @@ const VQF{T} = MOI.VectorQuadraticFunction{T}
const VI = MOI.VariableIndex
const CI = MOI.ConstraintIndex

# TODO move to MOIU ?
mapcoefficient(coefmap, t::MOI.ScalarAffineTerm) = MOI.ScalarAffineTerm(coefmap(t.coefficient), t.variable_index)
mapcoefficient(coefmap, f::MOI.ScalarAffineFunction) = MOI.ScalarAffineFunction(mapcoefficient.(coefmap, f.terms), coefmap(f.constant))

include("bridge.jl")
include("bridgeoptimizer.jl")
include("singlebridgeoptimizer.jl")
Expand Down
15 changes: 13 additions & 2 deletions src/Bridges/bridge.jl
Original file line number Diff line number Diff line change
Expand Up @@ -40,9 +40,20 @@ MOI.supportsconstraint(::Type{<:AbstractBridge}, ::Type{<:MOI.AbstractFunction},
"""
addedconstrainttypes(BT::Type{<:AbstractBridge}, F::Type{<:MOI.AbstractFunction}, S::Type{<:MOI.AbstractSet})::Bool

Return a list of the types of constraints that bridges of type `BT` add for bridging an `F`-in-`S` constraints.
Return a list of the types of constraints that bridges of type `BT` add for
bridging an `F`-in-`S` constraints.

addedconstrainttypes(BT::Type{<:AbstractBridge})::Bool

Return a list of the types of constraints that bridges of concrete type `BT` add
for `F`-in-`S` constraints.
"""
function addedconstrainttypes end
function addedconstrainttypes(BT::Type{<:AbstractBridge},
F::Type{<:MOI.AbstractFunction},
S::Type{<:MOI.AbstractSet})
addedconstrainttypes(concrete_bridge_type(BT, F, S))
end


"""
concrete_bridge_type(BT::Type{<:AbstractBridge},
Expand Down
15 changes: 10 additions & 5 deletions src/Bridges/detbridge.jl
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,8 @@ function extract_eigenvalues(model, f::MOI.VectorAffineFunction{T}, d::Int) wher

Δ = MOI.addvariables!(model, n)

X = MOIU.eachscalar(f)[2:(n+1)]
f_scalars = MOIU.eachscalar(f)
X = f_scalars[2:(n+1)]
m = length(X.terms)
M = m + n + d

Expand All @@ -41,7 +42,7 @@ function extract_eigenvalues(model, f::MOI.VectorAffineFunction{T}, d::Int) wher
Y = MOI.VectorAffineFunction(terms, constant)
sdindex = MOI.addconstraint!(model, Y, MOI.PositiveSemidefiniteConeTriangle(2d))

t = MOIU.eachscalar(f)[1]
t = f_scalars[1]
D = Δ[trimap.(1:d, 1:d)]
t, D, Δ, sdindex
end
Expand Down Expand Up @@ -94,7 +95,9 @@ addedconstrainttypes(::Type{LogDetBridge{T}}, ::Type{<:Union{MOI.VectorOfVariabl
Constrains ``x \\le \\log(z)`` and return the constraint index.
"""
function sublog(model, x::MOI.VariableIndex, z::MOI.VariableIndex, ::Type{T}) where T
MOI.addconstraint!(model, MOI.VectorAffineFunction([MOI.VectorAffineTerm(1, MOI.ScalarAffineTerm(one(T), x)), MOI.VectorAffineTerm(3, MOI.ScalarAffineTerm(one(T), z))], [zero(T), one(T), zero(T)]), MOI.ExponentialCone())
MOI.addconstraint!(model, MOIU.operate(vcat, T, MOI.SingleVariable(x),
one(T), MOI.SingleVariable(z)),
MOI.ExponentialCone())
end

"""
Expand All @@ -104,7 +107,8 @@ Constrains ``t \\le l_1 + \\cdots + l_n`` where `n` is the length of `l` and ret
"""
function subsum(model, t::MOI.ScalarAffineFunction, l::Vector{MOI.VariableIndex}, ::Type{T}) where T
n = length(l)
MOI.addconstraint!(model, MOI.ScalarAffineFunction([t.terms; MOI.ScalarAffineTerm.(-one(T), l)], zero(T)), MOI.LessThan(-t.constant))
f = MOIU.operate!(-, T, t, MOIU.operate(sum, T, l))
return MOIU.add_scalar_constraint(model, f, MOI.LessThan(zero(T)))
end

# Attributes, Bridge acting as an model
Expand Down Expand Up @@ -173,7 +177,8 @@ function RootDetBridge{T}(model, f::MOI.VectorAffineFunction{T}, s::MOI.RootDetC
d = s.side_dimension
t, D, Δ, sdindex = extract_eigenvalues(model, f, d)
DF = MOI.VectorAffineFunction{T}(MOI.VectorOfVariables(D))
gmindex = MOI.addconstraint!(model, MOIU.moivcat(t, DF), MOI.GeometricMeanCone(d+1))
gmindex = MOI.addconstraint!(model, MOIU.operate(vcat, T, t, DF),
MOI.GeometricMeanCone(d+1))

RootDetBridge(Δ, sdindex, gmindex)
end
Expand Down
85 changes: 58 additions & 27 deletions src/Bridges/geomeanbridge.jl
Original file line number Diff line number Diff line change
Expand Up @@ -38,40 +38,41 @@ Now, this is equivalent to

[1] Ben-Tal, Aharon, and Arkadi Nemirovski. *Lectures on modern convex optimization: analysis, algorithms, and engineering applications*. Society for Industrial and Applied Mathematics, 2001.
"""
struct GeoMeanBridge{T} <: AbstractBridge
struct GeoMeanBridge{T, F, G} <: AbstractBridge
# Initially, (t, x) is of dimension d so x is dimension (d-1)
# We create n new variables so that there is 2^l = d-1+n variables x_i
# We then need to create 2^l-1 new variables (1+2+...+2^{l-1})
d::Int
xij::Vector{VI}
tubc::CI{MOI.ScalarAffineFunction{T}, MOI.LessThan{T}}
socrc::Vector{CI{MOI.VectorAffineFunction{T}, MOI.RotatedSecondOrderCone}}
tubc::CI{F, MOI.LessThan{T}}
socrc::Vector{CI{G, MOI.RotatedSecondOrderCone}}
end
function GeoMeanBridge{T}(model, f::MOI.VectorOfVariables, s::MOI.GeometricMeanCone) where T
GeoMeanBridge{T}(model, MOI.VectorAffineFunction{T}(f), s)
end
function GeoMeanBridge{T}(model, f::MOI.VectorAffineFunction{T}, s::MOI.GeometricMeanCone) where T
function GeoMeanBridge{T, F, G}(model, f::MOI.AbstractVectorFunction,
s::MOI.GeometricMeanCone) where {T, F, G}
d = s.dimension
n = d-1
l = ilog2(n)
N = 1 << l
xij = MOI.addvariables!(model, N-1)
f_scalars = MOIU.eachscalar(f)

xl1 = xij[1]
sN = one(T) / sqrt(N)
xl1 = MOI.SingleVariable(xij[1])
sN = one(T) / √N
function _getx(i)
if i > n
MOI.ScalarAffineFunction{T}([MOI.ScalarAffineTerm(sN, xl1)], zero(T))
return sN * xl1
else
MOIU.eachscalar(f)[1+i]
return f_scalars[1+i]
end
end

t = MOIU.eachscalar(f)[1]
t = f_scalars[1]
# With sqrt(2)^l*t - xl1, we should scale both the ConstraintPrimal and ConstraintDual
tubc = MOI.addconstraint!(model, MOI.ScalarAffineFunction([t.terms; MOI.ScalarAffineTerm(-sN, xl1)], t.constant), MOI.LessThan(zero(T)))
tubc = MOIU.add_scalar_constraint(model,
MOIU.operate!(+, T, t, -sN * xl1),
MOI.LessThan(zero(T)))

socrc = Vector{CI{MOI.VectorAffineFunction{T}, MOI.RotatedSecondOrderCone}}(undef, N-1)
socrc = Vector{CI{G, MOI.RotatedSecondOrderCone}}(undef, N-1)
offset = offsetnext = 0
for i in 1:l
offsetnext = offset + i
Expand All @@ -80,26 +81,55 @@ function GeoMeanBridge{T}(model, f::MOI.VectorAffineFunction{T}, s::MOI.Geometri
a = _getx(2j-1)
b = _getx(2j)
else
a = MOI.ScalarAffineFunction{T}(MOI.SingleVariable(xij[offsetnext+2j-1]))
b = MOI.ScalarAffineFunction{T}(MOI.SingleVariable(xij[offsetnext+2j]))
a = one(T) * MOI.SingleVariable(xij[offsetnext+2j-1])
b = one(T) * MOI.SingleVariable(xij[offsetnext+2j])
end
c = MOI.ScalarAffineFunction{T}(MOI.SingleVariable(xij[offset+j]))
socrc[offset + j] = MOI.addconstraint!(model, MOIU.moivcat(a, b, c), MOI.RotatedSecondOrderCone(3))
c = MOI.SingleVariable(xij[offset+j])
socrc[offset + j] = MOI.addconstraint!(model,
MOIU.operate(vcat, T, a, b, c),
MOI.RotatedSecondOrderCone(3))
end
offset = offsetnext
end
GeoMeanBridge(d, xij, tubc, socrc)
end

MOI.supportsconstraint(::Type{GeoMeanBridge{T}}, ::Type{<:Union{MOI.VectorOfVariables, MOI.VectorAffineFunction{T}}}, ::Type{MOI.GeometricMeanCone}) where T = true
addedconstrainttypes(::Type{GeoMeanBridge{T}}, ::Type{<:Union{MOI.VectorOfVariables, MOI.VectorAffineFunction{T}}}, ::Type{MOI.GeometricMeanCone}) where T = [(MOI.ScalarAffineFunction{T}, MOI.LessThan{T}), (MOI.VectorAffineFunction{T}, MOI.RotatedSecondOrderCone)]
function MOI.supportsconstraint(::Type{GeoMeanBridge{T}},
::Type{<:MOI.AbstractVectorFunction},
::Type{MOI.GeometricMeanCone}) where T
return true
end
function addedconstrainttypes(::Type{GeoMeanBridge{T, F, G}}) where {T, F, G}
return [(F, MOI.LessThan{T}), (G, MOI.RotatedSecondOrderCone)]
end
function concrete_bridge_type(::Type{<:GeoMeanBridge{T}},
H::Type{<:MOI.AbstractVectorFunction},
::Type{MOI.GeometricMeanCone}) where T
S = MOIU.scalar_type(H)
A = MOIU.promote_operation(*, T, T, MOI.SingleVariable)
F = MOIU.promote_operation(+, T, S, A)
G = MOIU.promote_operation(vcat, T, A, A, MOI.SingleVariable)
return GeoMeanBridge{T, F, G}
end

# Attributes, Bridge acting as an model
MOI.get(b::GeoMeanBridge, ::MOI.NumberOfVariables) = length(b.xij)
MOI.get(b::GeoMeanBridge{T}, ::MOI.NumberOfConstraints{MOI.ScalarAffineFunction{T}, MOI.LessThan{T}}) where T = 1 # t ≤ x_{l1}/sqrt(N)
MOI.get(b::GeoMeanBridge{T}, ::MOI.NumberOfConstraints{MOI.VectorAffineFunction{T}, MOI.RotatedSecondOrderCone}) where T = length(b.socrc)
MOI.get(b::GeoMeanBridge{T}, ::MOI.ListOfConstraintIndices{MOI.ScalarAffineFunction{T}, MOI.LessThan{T}}) where T = [b.tubc]
MOI.get(b::GeoMeanBridge{T}, ::MOI.ListOfConstraintIndices{MOI.VectorAffineFunction{T}, MOI.RotatedSecondOrderCone}) where T = b.socrc
function MOI.get(b::GeoMeanBridge{T, F},
::MOI.NumberOfConstraints{F, MOI.LessThan{T}}) where {T, F}
return 1 # t ≤ x_{l1}/sqrt(N)
end
function MOI.get(b::GeoMeanBridge{T, F, G},
::MOI.NumberOfConstraints{G, MOI.RotatedSecondOrderCone}) where {T, F, G}
return length(b.socrc)
end
function MOI.get(b::GeoMeanBridge{T, F},
::MOI.ListOfConstraintIndices{F, MOI.LessThan{T}}) where {T, F}
return [b.tubc]
end
function MOI.get(b::GeoMeanBridge{T, F, G},
::MOI.ListOfConstraintIndices{G, MOI.RotatedSecondOrderCone}) where {T, F, G}
return b.socrc
end

# References
function MOI.delete!(model::MOI.ModelLike, c::GeoMeanBridge)
Expand All @@ -109,9 +139,10 @@ function MOI.delete!(model::MOI.ModelLike, c::GeoMeanBridge)
end

# Attributes, Bridge acting as a constraint
function MOI.canget(model::MOI.ModelLike, a::MOI.ConstraintPrimal, ::Type{GeoMeanBridge{T}}) where T
MOI.canget(model, a, CI{MOI.ScalarAffineFunction{T}, MOI.LessThan{T}}) &&
MOI.canget(model, a, CI{MOI.VectorAffineFunction{T}, MOI.RotatedSecondOrderCone})
function MOI.canget(model::MOI.ModelLike, a::MOI.ConstraintPrimal,
::Type{GeoMeanBridge{T, F, G}}) where {T, F, G}
MOI.canget(model, a, CI{F, MOI.LessThan{T}}) &&
MOI.canget(model, a, CI{G, MOI.RotatedSecondOrderCone})
end
function _getconstrattr(model, a, c::GeoMeanBridge{T}) where T
output = Vector{T}(undef, c.d)
Expand Down
12 changes: 9 additions & 3 deletions src/Bridges/intervalbridge.jl
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,18 @@ end
function SplitIntervalBridge{T, F}(model, f::F, s::MOI.Interval{T}) where {T, F}
lower = MOI.addconstraint!(model, f, MOI.GreaterThan(s.lower))
upper = MOI.addconstraint!(model, f, MOI.LessThan(s.upper))
return SplitIntervalBridge(lower, upper)
return SplitIntervalBridge{T, F}(lower, upper)
end

MOI.supportsconstraint(::Type{SplitIntervalBridge{T}}, ::Type{<:MOI.AbstractScalarFunction}, ::Type{MOI.Interval{T}}) where T = true
addedconstrainttypes(::Type{SplitIntervalBridge{T}}, F::Type{<:MOI.AbstractScalarFunction}, ::Type{MOI.Interval{T}}) where T = [(F, MOI.GreaterThan{T}), (F, MOI.LessThan{T})]
concrete_bridge_type(::Type{<:SplitIntervalBridge}, F::Type{<:MOI.AbstractScalarFunction}, ::Type{MOI.Interval{T}}) where T = SplitIntervalBridge{T, F}
function addedconstrainttypes(::Type{SplitIntervalBridge{T, F}}) where {T, F}
return [(F, MOI.GreaterThan{T}), (F, MOI.LessThan{T})]
end
function concrete_bridge_type(::Type{<:SplitIntervalBridge},
F::Type{<:MOI.AbstractScalarFunction},
::Type{MOI.Interval{T}}) where T
return SplitIntervalBridge{T, F}
end

# Attributes, Bridge acting as an model
MOI.get(b::SplitIntervalBridge{T, F}, ::MOI.NumberOfConstraints{F, MOI.LessThan{T}}) where {T, F} = 1
Expand Down
67 changes: 46 additions & 21 deletions src/Bridges/rsocbridge.jl
Original file line number Diff line number Diff line change
Expand Up @@ -16,31 +16,54 @@ That means in particular that the norm is of constraint primal and duals are pre

[1] Ben-Tal, Aharon, and Arkadi Nemirovski. *Lectures on modern convex optimization: analysis, algorithms, and engineering applications*. Society for Industrial and Applied Mathematics, 2001.
"""
struct RSOCBridge{T} <: AbstractBridge
soc::CI{MOI.VectorAffineFunction{T}, MOI.SecondOrderCone}
struct RSOCBridge{T, F} <: AbstractBridge
soc::CI{F, MOI.SecondOrderCone}
end
function RSOCBridge{T}(model, f::MOI.VectorOfVariables, s::MOI.RotatedSecondOrderCone) where T
RSOCBridge{T}(model, MOI.VectorAffineFunction{T}(f), s)
end
function RSOCBridge{T}(model, f::MOI.VectorAffineFunction{T}, s::MOI.RotatedSecondOrderCone) where T
function RSOCBridge{T, F}(model, f::MOI.AbstractVectorFunction, s::MOI.RotatedSecondOrderCone) where {T, F}
d = s.dimension
t = MOIU.eachscalar(f)[1]
u = MOIU.eachscalar(f)[2]
x = MOIU.eachscalar(f)[3:d]
f_scalars = MOIU.eachscalar(f)
t = f_scalars[1]
u = f_scalars[2]
x = f_scalars[3:d]
s2 = √2
y = MOI.ScalarAffineFunction([mapcoefficient.(c -> c/s2, t.terms); mapcoefficient.(c -> -c/s2, u.terms)], t.constant/s2 - u.constant/s2)
z = MOI.ScalarAffineFunction([mapcoefficient.(c -> c/s2, t.terms); mapcoefficient.(c -> c/s2, u.terms)], t.constant/s2 + u.constant/s2)
g = MOIU.moivcat(z, y, x)
ts = MOIU.operate!(/, T, t, s2)
us = MOIU.operate!(/, T, u, s2)
# Cannot use `operate!` here since `ts` and `us` are needed for the next
# line
y = ts - us
z = MOIU.operate!(+, T, ts, us)
g = MOIU.operate(vcat, T, z, y, x)
soc = MOI.addconstraint!(model, g, MOI.SecondOrderCone(d))
RSOCBridge{T}(soc)
RSOCBridge{T, F}(soc)
end

MOI.supportsconstraint(::Type{RSOCBridge{T}}, ::Type{<:Union{MOI.VectorOfVariables, MOI.VectorAffineFunction{T}}}, ::Type{MOI.RotatedSecondOrderCone}) where T = true
addedconstrainttypes(::Type{RSOCBridge{T}}, ::Type{<:Union{MOI.VectorOfVariables, MOI.VectorAffineFunction{T}}}, ::Type{MOI.RotatedSecondOrderCone}) where T = [(MOI.VectorAffineFunction{T}, MOI.SecondOrderCone)]
function MOI.supportsconstraint(::Type{RSOCBridge{T}},
::Type{<:MOI.AbstractVectorFunction},
::Type{MOI.RotatedSecondOrderCone}) where T
return true
end
function addedconstrainttypes(::Type{RSOCBridge{T, F}}) where {T, F}
return [(F, MOI.SecondOrderCone)]
end
function concrete_bridge_type(::Type{<:RSOCBridge{T}},
G::Type{<:MOI.AbstractVectorFunction},
::Type{MOI.RotatedSecondOrderCone}) where T
S = MOIU.promote_operation(/, T, MOIU.scalar_type(G), T)
Y = MOIU.promote_operation(-, T, S, S)
Z = MOIU.promote_operation(+, T, S, S)
F = MOIU.promote_operation(vcat, T, Z, Y, G)
RSOCBridge{T, F}
end

# Attributes, Bridge acting as an model
MOI.get(b::RSOCBridge{T}, ::MOI.NumberOfConstraints{MOI.VectorAffineFunction{T}, MOI.SecondOrderCone}) where T = 1
MOI.get(b::RSOCBridge{T}, ::MOI.ListOfConstraintIndices{MOI.VectorAffineFunction{T}, MOI.SecondOrderCone}) where T = [b.soc]
function MOI.get(b::RSOCBridge{T, F},
::MOI.NumberOfConstraints{F, MOI.SecondOrderCone}) where {T, F}
return 1
end
function MOI.get(b::RSOCBridge{T, F},
::MOI.ListOfConstraintIndices{F, MOI.SecondOrderCone}) where {T, F}
return [b.soc]
end

# References
function MOI.delete!(model::MOI.ModelLike, c::RSOCBridge)
Expand All @@ -56,12 +79,14 @@ function _get(model, attr::Union{MOI.ConstraintPrimal, MOI.ConstraintDual}, c::R
[x[1]/s2+x[2]/s2; x[1]/s2-x[2]/s2; x[3:end]]
end
# Need to define both `get` methods and redirect to `_get` to avoid ambiguity in dispatch
function MOI.canget(model::MOI.ModelLike, a::MOI.ConstraintPrimal, ::Type{RSOCBridge{T}}) where T
MOI.canget(model, a, CI{MOI.VectorAffineFunction{T}, MOI.SecondOrderCone})
function MOI.canget(model::MOI.ModelLike, a::MOI.ConstraintPrimal,
::Type{RSOCBridge{T, F}}) where {T, F}
MOI.canget(model, a, CI{F, MOI.SecondOrderCone})
end
MOI.get(model::MOI.ModelLike, attr::MOI.ConstraintPrimal, c::RSOCBridge) = _get(model, attr, c)
function MOI.canget(model::MOI.ModelLike, a::MOI.ConstraintDual, ::Type{RSOCBridge{T}}) where T
MOI.canget(model, a, CI{MOI.VectorAffineFunction{T}, MOI.SecondOrderCone})
function MOI.canget(model::MOI.ModelLike, a::MOI.ConstraintDual,
::Type{RSOCBridge{T, F}}) where {T, F}
MOI.canget(model, a, CI{F, MOI.SecondOrderCone})
end
MOI.get(model::MOI.ModelLike, attr::MOI.ConstraintDual, c::RSOCBridge) = _get(model, attr, c)

Expand Down
7 changes: 4 additions & 3 deletions src/Bridges/soctopsdbridge.jl
Original file line number Diff line number Diff line change
Expand Up @@ -127,10 +127,11 @@ function RSOCtoPSDCBridge{T}(instance, f, s::MOI.RotatedSecondOrderCone) where T
end

_RSOCtoPSDCaff(f::MOI.VectorOfVariables, ::Type{T}) where T = _RSOCtoPSDCaff(MOI.VectorAffineFunction{T}(f), T)
function _RSOCtoPSDCaff(f::MOI.VectorAffineFunction, ::Type)
function _RSOCtoPSDCaff(f::MOI.VectorAffineFunction, ::Type{T}) where T
n = MOI.output_dimension(f)
g = mapcoefficient(c -> 2c, MOIU.eachscalar(f)[2])
_SOCtoPSDCaff(MOIU.eachscalar(f)[[1; 3:n]], g)
f_scalars = MOIU.eachscalar(f)
g = MOIU.operate!(*, T, f_scalars[2], convert(T, 2))
_SOCtoPSDCaff(f_scalars[[1; 3:n]], g)
end

function MOI.canget(instance::MOI.AbstractOptimizer, a::Union{MOI.ConstraintPrimal, MOI.ConstraintDual}, ::Type{RSOCtoPSDCBridge{T}}) where T
Expand Down
1 change: 1 addition & 0 deletions src/Utilities/Utilities.jl
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ const CI{F,S} = MOI.ConstraintIndex{F,S}

include("functions.jl")
include("sets.jl")
include("constraints.jl")
include("copy.jl")

include("model.jl")
Expand Down
8 changes: 8 additions & 0 deletions src/Utilities/constraints.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
function add_scalar_constraint(model::MOI.ModelLike,
func::Union{MOI.ScalarAffineFunction{T},
MOI.ScalarQuadraticFunction{T}},
set::MOI.AbstractScalarSet) where T
set = shift_constant(set, -func.constant)
func.constant = zero(T)
return MOI.addconstraint!(model, func, set)
end
Loading