Skip to content

Add Bridges.Constraint.ComplexNormInfinityToSecondOrderConeBridge #2451

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 8 commits into from
Apr 11, 2024
Merged
Show file tree
Hide file tree
Changes from 7 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
1 change: 1 addition & 0 deletions docs/src/submodules/Bridges/list_of_bridges.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ Bridges.Constraint.QuadtoSOCBridge
Bridges.Constraint.SOCtoPSDBridge
Bridges.Constraint.RSOCtoPSDBridge
Bridges.Constraint.NormInfinityBridge
Bridges.Constraint.ComplexNormInfinityToSecondOrderConeBridge
Bridges.Constraint.NormOneBridge
Bridges.Constraint.NormToPowerBridge
Bridges.Constraint.NormOneConeToNormConeBridge
Expand Down
5 changes: 5 additions & 0 deletions src/Bridges/Constraint/Constraint.jl
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ include("bridges/all_different.jl")
include("bridges/all_different_reif.jl")
include("bridges/bin_packing.jl")
include("bridges/circuit.jl")
include("bridges/complex_norm_infinity.jl")
include("bridges/count_at_least.jl")
include("bridges/count_belongs.jl")
include("bridges/count_distinct.jl")
Expand Down Expand Up @@ -107,6 +108,10 @@ function add_all_bridges(bridged_model, ::Type{T}) where {T}
MOI.Bridges.add_bridge(bridged_model, NormOneConeToNormConeBridge{T})
MOI.Bridges.add_bridge(bridged_model, SecondOrderConeToNormConeBridge{T})
MOI.Bridges.add_bridge(bridged_model, NormInfinityConeToNormConeBridge{T})
MOI.Bridges.add_bridge(
bridged_model,
ComplexNormInfinityToSecondOrderConeBridge{T},
)
MOI.Bridges.add_bridge(bridged_model, RelativeEntropyBridge{T})
MOI.Bridges.add_bridge(bridged_model, NormSpectralBridge{T})
MOI.Bridges.add_bridge(bridged_model, NormNuclearBridge{T})
Expand Down
152 changes: 152 additions & 0 deletions src/Bridges/Constraint/bridges/complex_norm_infinity.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,152 @@
# Copyright (c) 2017: Miles Lubin and contributors
# Copyright (c) 2017: Google Inc.
#
# Use of this source code is governed by an MIT-style license that can be found
# in the LICENSE.md file or at https://opensource.org/licenses/MIT.

"""
ComplexNormInfinityToSecondOrderConeBridge{T} <: Bridges.Constraint.AbstractBridge

`ComplexNormInfinityToSecondOrderConeBridge` implements the following
reformulation:

* ``(t, x) \\in NormInfinity(1+d)`` into ``(t, real(x_i), imag(x_i)) \\in SecondOrderCone()``
for all ``i``.

## Source node

`ComplexNormInfinityToSecondOrderConeBridge` supports:

* [`MOI.VectorAffineFunction{Complex{T}}`](@ref) in [`MOI.NormInfinityCone`](@ref)

## Target nodes

`ComplexNormInfinityToSecondOrderConeBridge` creates:

* [`MOI.VectorAffineFunction{T}`](@ref) in [`MOI.SecondOrderCone`](@ref)
"""
struct ComplexNormInfinityToSecondOrderConeBridge{T} <: AbstractBridge
ci::Vector{
MOI.ConstraintIndex{MOI.VectorAffineFunction{T},MOI.SecondOrderCone},
}
end

const ComplexNormInfinityToSecondOrderCone{T,OT<:MOI.ModelLike} =
SingleBridgeOptimizer{ComplexNormInfinityToSecondOrderConeBridge{T},OT}

function bridge_constraint(
::Type{ComplexNormInfinityToSecondOrderConeBridge{T}},
model::MOI.ModelLike,
f::MOI.VectorAffineFunction{Complex{T}},
s::MOI.NormInfinityCone,
) where {T}
fi_s = MOI.Utilities.scalarize(f)
if !iszero(imag(fi_s[1]))
error(
"The epigraph variable `t` in `[t; x] in NormInfinityCone()` " *
"must be real. It is: $(fi_s[1])",
)
end
t = real(fi_s[1])
cis = MOI.ConstraintIndex{MOI.VectorAffineFunction{T},MOI.SecondOrderCone}[]
for fi in fi_s[2:end]
ci = MOI.add_constraint(
model,
MOI.Utilities.operate(vcat, T, t, real(fi), imag(fi)),
MOI.SecondOrderCone(3),
)
push!(cis, ci)
end
return ComplexNormInfinityToSecondOrderConeBridge{T}(cis)
end

function MOI.supports_constraint(
::Type{<:ComplexNormInfinityToSecondOrderConeBridge{T}},
::Type{MOI.VectorAffineFunction{Complex{T}}},
::Type{MOI.NormInfinityCone},
) where {T}
return true
end

function MOI.Bridges.added_constrained_variable_types(
::Type{<:ComplexNormInfinityToSecondOrderConeBridge},
)
return Tuple{Type}[]
end

function MOI.Bridges.added_constraint_types(
::Type{<:ComplexNormInfinityToSecondOrderConeBridge{T}},
) where {T}
return Tuple{Type,Type}[(MOI.VectorAffineFunction{T}, MOI.SecondOrderCone)]
end

function concrete_bridge_type(
::Type{<:ComplexNormInfinityToSecondOrderConeBridge{T}},
::Type{MOI.VectorAffineFunction{Complex{T}}},
::Type{MOI.NormInfinityCone},
) where {T}
return ComplexNormInfinityToSecondOrderConeBridge{T}
end

function MOI.get(
::ComplexNormInfinityToSecondOrderConeBridge,
::MOI.NumberOfVariables,
)::Int64
return 0
end

function MOI.get(
bridge::ComplexNormInfinityToSecondOrderConeBridge{T},
::MOI.NumberOfConstraints{MOI.VectorAffineFunction{T},MOI.SecondOrderCone},
)::Int64 where {T}
return length(bridge.ci)
end

function MOI.get(
bridge::ComplexNormInfinityToSecondOrderConeBridge{T},
::MOI.ListOfConstraintIndices{
MOI.VectorAffineFunction{T},
MOI.SecondOrderCone,
},
) where {T}
return copy(bridge.ci)
end

function MOI.delete(
model::MOI.ModelLike,
bridge::ComplexNormInfinityToSecondOrderConeBridge,
)
MOI.delete(model, bridge.ci)
return
end

function MOI.get(
model::MOI.ModelLike,
::MOI.ConstraintFunction,
bridge::ComplexNormInfinityToSecondOrderConeBridge{T},
) where {T}
elements = MOI.ScalarAffineFunction{Complex{T}}[]
for ci in bridge.ci
f = MOI.get(model, MOI.ConstraintFunction(), ci)
fi_s = MOI.Utilities.scalarize(f)
if isempty(elements)
push!(elements, fi_s[1])
end
fi = MOI.Utilities.operate(
+,
Complex{T},
(one(T) + zero(T) * im) * fi_s[2],
(zero(T) + one(T) * im) * fi_s[3],
)
push!(elements, fi)
end
return MOI.Utilities.operate(vcat, Complex{T}, elements...)
end

function MOI.get(
::MOI.ModelLike,
::MOI.ConstraintSet,
bridge::ComplexNormInfinityToSecondOrderConeBridge,
)
return MOI.NormInfinityCone(1 + length(bridge.ci))
end
72 changes: 72 additions & 0 deletions test/Bridges/Constraint/complex_norm_infinity.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
# Copyright (c) 2017: Miles Lubin and contributors
# Copyright (c) 2017: Google Inc.
#
# Use of this source code is governed by an MIT-style license that can be found
# in the LICENSE.md file or at https://opensource.org/licenses/MIT.

module TestConstraintComplexNormInfinityToSecondOrderCone

using Test

import MathOptInterface as MOI

function runtests()
for name in names(@__MODULE__; all = true)
if startswith("$(name)", "test_")
@testset "$(name)" begin
getfield(@__MODULE__, name)()
end
end
end
return
end

function test_runtests()
MOI.Bridges.runtests(
MOI.Bridges.Constraint.ComplexNormInfinityToSecondOrderConeBridge,
"""
variables: t, x
::Complex{Float64}: [t, (1 + 2im) * x + (3 + 4im)] in NormInfinityCone(2)
""",
"""
variables: t, x
::Float64: [t, 1 * x + 3, 2 * x + 4] in SecondOrderCone(3)
""",
)
MOI.Bridges.runtests(
MOI.Bridges.Constraint.ComplexNormInfinityToSecondOrderConeBridge,
"""
variables: t, x, y
::Complex{Float64}: [2.0 * t + 3.0, x + im * y] in NormInfinityCone(2)
""",
"""
variables: t, x, y
::Float64: [2.0 * t + 3.0, 1.0 * x, 1.0 * y] in SecondOrderCone(3)
""",
)
return
end

function test_imag_t()
inner = MOI.Utilities.UniversalFallback(MOI.Utilities.Model{Float64}())
model =
MOI.Bridges.Constraint.ComplexNormInfinityToSecondOrderCone{Float64}(
inner,
)
x = MOI.add_variables(model, 2)
f_t = (1.0 + 2.0im) * x[1]
f_x = (1.0 + 2.0im) * x[2] + (3.0 + 4.0im)
f = MOI.Utilities.operate(vcat, Complex{Float64}, f_t, f_x)
@test_throws(
ErrorException(
"The epigraph variable `t` in `[t; x] in NormInfinityCone()` " *
"must be real. It is: $f_t",
),
MOI.add_constraint(model, f, MOI.NormInfinityCone(2))
)
return
end

end # module

TestConstraintComplexNormInfinityToSecondOrderCone.runtests()
16 changes: 0 additions & 16 deletions test/Bridges/lazy_bridge_optimizer.jl
Original file line number Diff line number Diff line change
Expand Up @@ -2131,22 +2131,6 @@ function test_delete_index_in_vector(T::Type = Float64)
return
end

function test_bridge_complex_norminfinitycone()
model = MOI.instantiate(
MOI.Utilities.Model{Float64};
with_bridge_type = Float64,
)
x = MOI.add_variable(model)
t = MOI.add_variable(model)
f = (1.0 + 0.0im) * x + 2.0 * im
g = MOI.Utilities.operate(vcat, Complex{Float64}, t, f)
@test_throws(
MOI.UnsupportedConstraint,
MOI.add_constraint(model, g, MOI.NormInfinityCone(2)),
)
return
end

function test_bridge_complex_normonecone()
model = MOI.instantiate(
MOI.Utilities.Model{Float64};
Expand Down