Skip to content

Commit d7bac30

Browse files
authored
Add support for complex variable (#14)
* Add support for complex variable * Fix format
1 parent c9045bf commit d7bac30

File tree

3 files changed

+63
-11
lines changed

3 files changed

+63
-11
lines changed

README.md

+3-2
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,9 @@ const COI = ComplexOptInterface
1919

2020
model = Model()
2121
COI.add_all_bridges(model)
22-
@variable(model, x[1:2, 1:2] in COI.HermitianPSDCone())
23-
@constraint(model, x[1, 1] + x[2, 2] * im == 1 + 2im)
22+
@variable(model, x in COI.ComplexPlane(), start = 5 + 6im, lower_bound = 1 + 2im, upper_bound = 3 + 4im)
23+
@variable(model, Q[1:2, 1:2] in COI.HermitianPSDCone())
24+
@constraint(model, (1 + 2im) * x + Q[1, 1] + Q[2, 2] * im == 1 + 2im)
2425
```
2526

2627
## Design considerations

src/jump.jl

+29-2
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,33 @@ function add_all_bridges(model::JuMP.Model)
77
return JuMP.add_bridge(model, Bridges.Constraint.SplitZeroBridge)
88
end
99

10+
struct ComplexPlane end
11+
12+
struct ComplexVariable{S,T,U,V} <: JuMP.AbstractVariable
13+
info::JuMP.VariableInfo{S,T,U,V}
14+
end
15+
16+
function JuMP.build_variable(::Function, v::JuMP.ScalarVariable, ::ComplexPlane)
17+
return ComplexVariable(v.info)
18+
end
19+
20+
function JuMP.add_variable(
21+
model::JuMP.Model,
22+
v::ComplexVariable,
23+
name::String = "",
24+
)
25+
model.is_model_dirty = true
26+
var = JuMP.ScalarVariable(v.info)
27+
real_part = JuMP.add_variable(model, _real(var), _real(name))
28+
imag_part = JuMP.add_variable(model, _imag(var), _imag(name))
29+
# Efficiently build `real_part + imag_part * im`
30+
return JuMP.GenericAffExpr{ComplexF64,JuMP.VariableRef}(
31+
zero(ComplexF64),
32+
real_part => one(ComplexF64),
33+
imag_part => convert(ComplexF64, im),
34+
)
35+
end
36+
1037
struct HermitianPSDCone end
1138

1239
struct HermitianMatrixShape <: JuMP.AbstractShape
@@ -64,8 +91,8 @@ function _mapinfo(f::Function, v::JuMP.ScalarVariable)
6491
)
6592
end
6693

67-
_real(s::String) = s
68-
_imag(s::String) = s
94+
_real(s::String) = string("real(", s, ")")
95+
_imag(s::String) = string("imag(", s, ")")
6996

7097
_real(v::JuMP.ScalarVariable) = _mapinfo(real, v)
7198
_imag(v::JuMP.ScalarVariable) = _mapinfo(imag, v)

test/jump.jl

+31-7
Original file line numberDiff line numberDiff line change
@@ -9,15 +9,39 @@ using Test
99
function test_readme_example()
1010
model = Model()
1111
COI.add_all_bridges(model)
12-
@variable(model, x[1:2, 1:2] in COI.HermitianPSDCone())
13-
@test num_variables(model) == 4
12+
@variable(
13+
model,
14+
x in COI.ComplexPlane(),
15+
start = 5 + 6im,
16+
lower_bound = 1 + 2im,
17+
upper_bound = 3 + 4im
18+
)
19+
xr = first(x.terms).first
20+
xi = collect(x.terms)[2].first
21+
@test lower_bound(xr) == 1
22+
@test upper_bound(xr) == 3
23+
@test start_value(xr) == 5
24+
@test lower_bound(xi) == 2
25+
@test upper_bound(xi) == 4
26+
@test start_value(xi) == 6
27+
@variable(model, Q[1:2, 1:2] in COI.HermitianPSDCone())
28+
@test num_variables(model) == 6
1429
v = all_variables(model)
15-
@test x[1, 1] == 1v[1]
16-
@test x[1, 2] == v[2] + v[4] * im
17-
@test x[2, 2] == 1v[3]
30+
@test xr == v[1]
31+
@test name(v[1]) == "real(x)"
32+
@test xi == v[2]
33+
@test name(v[2]) == "imag(x)"
34+
@test x == v[1] + v[2] * im
35+
@test name(v[3]) == "real(Q[1,1])"
36+
@test Q[1, 1] == 1v[3]
37+
@test name(v[4]) == "real(Q[1,2])"
38+
@test name(v[6]) == "imag(Q[1,2])"
39+
@test Q[1, 2] == v[4] + v[6] * im
40+
@test name(v[5]) == "real(Q[2,2])"
41+
@test Q[2, 2] == 1v[5]
1842
# FIXME needs https://github.com/jump-dev/JuMP.jl/pull/2899
19-
#@test x[2, 1] == conj(x[1, 2])
20-
@constraint(model, x[1, 1] + x[2, 2] * im == 1 + 2im)
43+
#@test Q[2, 1] == conj(x[1, 2])
44+
@constraint(model, Q[1, 1] + Q[2, 2] * im == 1 + 2im)
2145
end
2246

2347
function test_simple_equality()

0 commit comments

Comments
 (0)