Skip to content

Commit 9de6dac

Browse files
authored
Fix automatic adding complex bridge (#313)
* Fix automatic adding complex bridge * Fix format * Fix doc ref
1 parent ffb0c61 commit 9de6dac

File tree

5 files changed

+34
-43
lines changed

5 files changed

+34
-43
lines changed

docs/src/constraints.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -206,7 +206,7 @@ So `p(x)` is constrained to be equal to
206206
`s(x) = s_0(x) + s_1(x) * q_1(x) + s_2(x) * q_2(x) + ...`
207207
where the `s_i(x)` polynomials are Sum-of-Squares.
208208
The dual of the equality constraint between `p(x)` and `s(x)` is given
209-
by [`SumOfSquares.PolyJuMP.moments`](@ref).
209+
by [`SumOfSquares.MultivariateMoments.moments`](@ref).
210210
```julia
211211
μ = moments(cref)
212212
```

docs/src/tutorials/Noncommutative and Hermitian/sums_of_hermitian_squares.jl

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,12 +10,10 @@ using SumOfSquares
1010

1111
using DynamicPolynomials
1212
@ncpolyvar x y
13-
p = (x + 1.0im * y) * (x - im * y)
13+
p = (x + im * y) * (x - im * y)
1414

1515
import CSDP
1616
model = Model(CSDP.Optimizer)
17-
MOI.Bridges.add_bridge(backend(model).optimizer, PolyJuMP.Bridges.Constraint.ZeroPolynomialBridge{Complex{Float64}})
18-
MOI.Bridges.add_bridge(backend(model).optimizer, SumOfSquares.Bridges.Constraint.SOSPolynomialBridge{Complex{Float64}})
1917
cone = NonnegPolyInnerCone{MOI.HermitianPositiveSemidefiniteConeTriangle}()
2018
con_ref = @constraint(model, p in cone)
2119
optimize!(model)

docs/src/tutorials/Symmetry/cyclic.jl

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -140,14 +140,11 @@ b = √3/2
140140
import CSDP
141141
solver = CSDP.Optimizer
142142
model = Model(solver)
143-
MOI.Bridges.add_bridge(backend(model).optimizer, PolyJuMP.Bridges.Constraint.ZeroPolynomialBridge{Complex{Float64}})
144-
MOI.Bridges.add_bridge(backend(model).optimizer, SumOfSquares.Bridges.Constraint.SOSPolynomialBridge{Complex{Float64}})
145143
@variable(model, t)
146144
@objective(model, Max, t)
147145
pattern = Symmetry.Pattern(G, action)
148146
cone = SumOfSquares.NonnegPolyInnerCone{MOI.HermitianPositiveSemidefiniteConeTriangle}()
149-
pp = (1.0 + 0.0im) * poly - (1.0 + 0.0im) * t
150-
con_ref = @constraint(model, pp in cone, symmetry = pattern)
147+
con_ref = @constraint(model, poly - t in cone, symmetry = pattern)
151148
optimize!(model)
152149
@test termination_status(model) == MOI.OPTIMAL #src
153150
@test objective_value(model) 0.0 atol=1e-4 #src

src/constraint.jl

Lines changed: 28 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -290,42 +290,54 @@ function PolyJuMP.bridges(
290290
::Type{<:MOI.AbstractVectorFunction},
291291
::Type{EmptyCone},
292292
)
293-
return [Bridges.Constraint.EmptyBridge]
293+
return [(Bridges.Constraint.EmptyBridge, Float64)]
294294
end
295295

296296
function PolyJuMP.bridges(
297297
::Type{<:MOI.AbstractVectorFunction},
298298
::Type{PositiveSemidefinite2x2ConeTriangle},
299299
)
300-
return [Bridges.Constraint.PositiveSemidefinite2x2Bridge]
300+
return [(Bridges.Constraint.PositiveSemidefinite2x2Bridge, Float64)]
301301
end
302302

303303
function PolyJuMP.bridges(
304304
::Type{<:MOI.AbstractVectorFunction},
305305
::Type{<:DiagonallyDominantConeTriangle},
306306
)
307-
return [Bridges.Constraint.DiagonallyDominantBridge]
307+
return [(Bridges.Constraint.DiagonallyDominantBridge, Float64)]
308308
end
309309

310310
function PolyJuMP.bridges(
311311
::Type{<:MOI.AbstractVectorFunction},
312312
::Type{<:ScaledDiagonallyDominantConeTriangle},
313313
)
314-
return [Bridges.Constraint.ScaledDiagonallyDominantBridge]
314+
return [(Bridges.Constraint.ScaledDiagonallyDominantBridge, Float64)]
315+
end
316+
317+
function _bridge_coefficient_type(
318+
::Type{SOSPolynomialSet{S,M,MV,C}},
319+
) where {S,M,MV,C}
320+
return _complex(Float64, matrix_cone_type(C))
315321
end
316322

317323
function PolyJuMP.bridges(
318324
::Type{<:MOI.AbstractVectorFunction},
319-
::Type{<:SOSPolynomialSet{<:AbstractAlgebraicSet}},
325+
S::Type{<:SOSPolynomialSet{<:AbstractAlgebraicSet}},
320326
)
321-
return [Bridges.Constraint.SOSPolynomialBridge]
327+
return [(
328+
Bridges.Constraint.SOSPolynomialBridge,
329+
_bridge_coefficient_type(S),
330+
)]
322331
end
323332

324333
function PolyJuMP.bridges(
325334
::Type{<:MOI.AbstractVectorFunction},
326-
::Type{<:SOSPolynomialSet{<:BasicSemialgebraicSet}},
335+
S::Type{<:SOSPolynomialSet{<:BasicSemialgebraicSet}},
327336
)
328-
return [Bridges.Constraint.SOSPolynomialInSemialgebraicSetBridge]
337+
return [(
338+
Bridges.Constraint.SOSPolynomialInSemialgebraicSetBridge,
339+
_bridge_coefficient_type(S),
340+
)]
329341
end
330342

331343
# Syntax: `@constraint(model, a >= b, SOSCone())`
@@ -339,10 +351,17 @@ function JuMP.build_constraint(
339351
return build_constraint(_error, f, extra; kws...)
340352
end
341353

354+
_promote_coef_type(::Type{V}, ::Type) where {V<:JuMP.AbstractVariableRef} = V
355+
_promote_coef_type(::Type{F}, ::Type{T}) where {F,T} = promote_type(F, T)
356+
342357
function JuMP.build_constraint(_error::Function, p, cone::SOSLikeCone; kws...)
343-
coefs = PolyJuMP.non_constant_coefficients(p)
344358
monos = MP.monomials(p)
345359
set = JuMP.moi_set(cone, monos; kws...)
360+
_coefs = PolyJuMP.non_constant_coefficients(p)
361+
# If a polynomial with real coefficients is used with the Hermitian SOS
362+
# cone, we want to promote the coefficients to complex
363+
T = _bridge_coefficient_type(typeof(set))
364+
coefs = convert(Vector{_promote_coef_type(eltype(_coefs), T)}, _coefs)
346365
shape = PolyJuMP.PolynomialShape(monos)
347366
return PolyJuMP.bridgeable(
348367
JuMP.VectorConstraint(coefs, set, shape),
@@ -351,29 +370,6 @@ function JuMP.build_constraint(_error::Function, p, cone::SOSLikeCone; kws...)
351370
)
352371
end
353372

354-
_non_constant(a::Vector{T}) where {T} = convert.(MOI.ScalarAffineFunction{T}, a)
355-
_non_constant(a::Vector{<:JuMP.AbstractJuMPScalar}) = moi_function.(a)
356-
_non_constant(a::Vector{<:MOI.AbstractFunction}) = a
357-
358-
# Add constraint with `p` having coefficients being MOI functions.
359-
# This is needed as a workaround as JuMP does not support complex numbers yet.
360-
# We can remove it when https://github.com/jump-dev/JuMP.jl/pull/2391 is done
361-
# We overload `JuMP.add_constraint` to avoid clash with the name.
362-
function JuMP.add_constraint(model::MOI.ModelLike, p, cone::SOSLikeCone; kws...)
363-
coefs = MOI.Utilities.vectorize(_non_constant(MP.coefficients(p)))
364-
monos = MP.monomials(p)
365-
set = JuMP.moi_set(cone, monos; kws...)
366-
return MOI.add_constraint(model, coefs, set)
367-
end
368-
function JuMP.add_constraint(model::JuMP.Model, p, cone::SOSLikeCone; kws...)
369-
ci = JuMP.add_constraint(JuMP.backend(model), p, cone; kws...)
370-
return JuMP.ConstraintRef(
371-
model,
372-
ci,
373-
PolyJuMP.PolynomialShape(MP.monomials(p)),
374-
)
375-
end
376-
377373
struct ValueNotSupported <: Exception end
378374
function Base.showerror(io::IO, ::ValueNotSupported)
379375
return print(

src/variable.jl

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
export DSOSPoly, SDSOSPoly, SOSPoly
22

33
function PolyJuMP.bridges(::Type{<:PositiveSemidefinite2x2ConeTriangle})
4-
return [Bridges.Variable.PositiveSemidefinite2x2Bridge]
4+
return [(Bridges.Variable.PositiveSemidefinite2x2Bridge, Float64)]
55
end
66
function PolyJuMP.bridges(::Type{<:ScaledDiagonallyDominantConeTriangle})
7-
return [Bridges.Variable.ScaledDiagonallyDominantBridge]
7+
return [(Bridges.Variable.ScaledDiagonallyDominantBridge, Float64)]
88
end
99
function PolyJuMP.bridges(::Type{<:CopositiveInnerCone})
10-
return [Bridges.Variable.CopositiveInnerBridge]
10+
return [(Bridges.Variable.CopositiveInnerBridge, Float64)]
1111
end
1212

1313
function JuMP.value(p::GramMatrix{<:JuMP.AbstractJuMPScalar})

0 commit comments

Comments
 (0)