Skip to content

Commit

Permalink
Support complex case in QuadOverLinAtom (#679)
Browse files Browse the repository at this point in the history
  • Loading branch information
ericphanson authored May 20, 2024
1 parent 639cc28 commit 095c90c
Show file tree
Hide file tree
Showing 3 changed files with 33 additions and 3 deletions.
1 change: 0 additions & 1 deletion docs/src/manual/complex-domain_optimization.md
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,6 @@ operate on complex variables as well. Notable exceptions include:

> - `inverse`
> - `square`
> - `quadoverlin`
> - `sqrt`
> - `geomean`
> - `huber`
Expand Down
17 changes: 15 additions & 2 deletions src/atoms/QuadOverLinAtom.jl
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,11 @@ mutable struct QuadOverLinAtom <: AbstractExpr
"[QuadOverLinAtom] quadoverlin arguments must be a vector and a scalar",
)
end
if iscomplex(y)
error(
"[QuadOverLinAtom] the second argument to quadoverlin must be real, not complex.",
)
end
return new((x, y), (1, 1))
end
end
Expand All @@ -29,13 +34,21 @@ curvature(::QuadOverLinAtom) = ConvexVexity()

function evaluate(q::QuadOverLinAtom)
x = evaluate(q.children[1])
return x' * x / evaluate(q.children[2])
# `real` is only necessary to fix the type; `x'*x` will always be real-valued.
return real(output(x' * x)) / evaluate(q.children[2])
end

function new_conic_form!(context::Context{T}, q::QuadOverLinAtom) where {T}
t = Variable()
x, y = q.children
f = vcat(t, (1 / T(2)) * y, x)
if iscomplex(x)
# ||x||₂² = ∑ᵢ |xᵢ|^2 = ∑ᵢ [re(xᵢ)² + im(xᵢ)²]
# = ||re(x)||₂² + ||im(x)||₂²
# = || vcat(re(x), im(y)) ||₂²
f = vcat(t, (1 / T(2)) * y, vcat(real(x), imag(x)))
else
f = vcat(t, (1 / T(2)) * y, x)
end
add_constraint!(context, Constraint{MOI.RotatedSecondOrderCone}(f))
return conic_form!(context, t)
end
Expand Down
18 changes: 18 additions & 0 deletions test/test_atoms.jl
Original file line number Diff line number Diff line change
Expand Up @@ -1958,16 +1958,34 @@ function test_QuadOverLinAtom()
_test_atom(target) do context
return quadoverlin(Variable(2), Variable())
end
target = """
variables: t, y, x1, x2, x3, x4
minobjective: 1.0 * t
[t, 0.5 * y, x1, x2, x3, x4] in RotatedSecondOrderCone(6)
"""
_test_atom(target) do context
return quadoverlin(ComplexVariable(2), Variable())
end
@test_throws(
ErrorException(
"[QuadOverLinAtom] quadoverlin arguments must be a vector and a scalar",
),
quadoverlin(Variable(2), Variable(2))
)
@test_throws(
ErrorException(
"[QuadOverLinAtom] the second argument to quadoverlin must be real, not complex.",
),
quadoverlin(Variable(2), ComplexVariable())
)
x = Variable(2)
x.value = [2.0, 3.0]
atom = quadoverlin(x, constant(2.0))
@test evaluate(atom) 13 / 2
x = ComplexVariable(2)
x.value = [2.0 + im, 3.0]
atom = quadoverlin(x, constant(2.0))
@test evaluate(atom) 14 / 2
return
end

Expand Down

0 comments on commit 095c90c

Please sign in to comment.