Skip to content

Commit b2963ae

Browse files
authored
Integrate with JuMP (#12)
* Integrate with JuMP * Format
1 parent f9136f8 commit b2963ae

File tree

10 files changed

+349
-67
lines changed

10 files changed

+349
-67
lines changed

Diff for: .JuliaFormatter.toml

+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
# Configuration file for JuliaFormatter.jl
2+
# For more information, see: https://domluna.github.io/JuliaFormatter.jl/stable/config/
3+
4+
always_for_in = true
5+
always_use_return = true
6+
margin = 80
7+
remove_extra_newlines = true
8+
short_to_long_function_def = true

Diff for: Project.toml

+4-1
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,17 @@
11
name = "ComplexOptInterface"
22
uuid = "25c3070e-1275-41b5-afef-2f982c87090a"
3-
repo = "https://github.com/jump-dev/ComplexOptInterface.jl.git"
43
authors = ["Benoît Legat <[email protected]>"]
4+
repo = "https://github.com/jump-dev/ComplexOptInterface.jl.git"
55
version = "0.0.3"
66

77
[deps]
8+
JuMP = "4076af6c-e467-56ae-b986-b466b2749572"
9+
LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e"
810
MathOptInterface = "b8f27783-ece8-5eb3-8dc8-9495eed66fee"
911
MutableArithmetics = "d8a4904e-b15c-11e9-3269-09a3773c0cb0"
1012

1113
[compat]
14+
JuMP = "0.23"
1215
MathOptInterface = "1"
1316
MutableArithmetics = "1"
1417
julia = "1.6"

Diff for: README.md

+17
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,23 @@
88
| [![Codecov branch][codecov-img]][codecov-url] | [<img src="https://upload.wikimedia.org/wikipedia/en/a/af/Discourse_logo.png" width="64">][discourse-url] |
99

1010
An extension of MathOptInterface to complex sets.
11+
12+
## How to use
13+
14+
Add to the JuMP model the bridges of this package with `add_all_bridges` and then you can create complex equality constraints and complex hermitian matrices:
15+
```julia
16+
using JuMP
17+
import ComplexOptInterface
18+
const COI = ComplexOptInterface
19+
20+
model = Model()
21+
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)
24+
```
25+
26+
## Design considerations
27+
1128
There are two types of complex sets:
1229
1) Some sets have complex entries, i.e. `MOI.EqualTo{Complex{Float64}}`,
1330
2) Some sets have real entries even if they model a complex mathematical set, i.e.

Diff for: src/Bridges/Constraint/split_equalto.jl

+8-3
Original file line numberDiff line numberDiff line change
@@ -36,8 +36,12 @@ function MOI.supports_constraint(
3636
) where {T}
3737
return true
3838
end
39-
MOIB.added_constrained_variable_types(::Type{<:SplitEqualToBridge}) = Tuple{DataType}[]
40-
function MOIB.added_constraint_types(::Type{SplitEqualToBridge{T,F,G}}) where {T,F,G}
39+
function MOIB.added_constrained_variable_types(::Type{<:SplitEqualToBridge})
40+
return Tuple{DataType}[]
41+
end
42+
function MOIB.added_constraint_types(
43+
::Type{SplitEqualToBridge{T,F,G}},
44+
) where {T,F,G}
4145
return Tuple{DataType,DataType}[(F, MOI.EqualTo{T})]
4246
end
4347
function MOI.Bridges.Constraint.concrete_bridge_type(
@@ -54,7 +58,8 @@ function MOI.get(
5458
bridge::SplitEqualToBridge{T,F},
5559
::MOI.NumberOfConstraints{F,MOI.EqualTo{T}},
5660
) where {T,F}
57-
return !isnothing(bridge.real_constraint) + !isnothing(bridge.imag_constraint)
61+
return !isnothing(bridge.real_constraint) +
62+
!isnothing(bridge.imag_constraint)
5863
end
5964
function MOI.get(
6065
bridge::SplitEqualToBridge{T,F},

Diff for: src/Bridges/Constraint/split_zero.jl

+18-8
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,8 @@ struct SplitZeroBridge{
1010
end
1111
function _nonzero_indices(func::MOI.AbstractVectorFunction)
1212
return [
13-
i for (i, scalar_func) in enumerate(MOIU.scalarize(func)) if !iszero(scalar_func)
13+
i for (i, scalar_func) in enumerate(MOIU.scalarize(func)) if
14+
!iszero(scalar_func)
1415
]
1516
end
1617
function MOI.Bridges.Constraint.bridge_constraint(
@@ -50,8 +51,12 @@ function MOI.supports_constraint(
5051
) where {T}
5152
return true
5253
end
53-
MOIB.added_constrained_variable_types(::Type{<:SplitZeroBridge}) = Tuple{DataType}[]
54-
function MOIB.added_constraint_types(::Type{SplitZeroBridge{T,F,G}}) where {T,F,G}
54+
function MOIB.added_constrained_variable_types(::Type{<:SplitZeroBridge})
55+
return Tuple{DataType}[]
56+
end
57+
function MOIB.added_constraint_types(
58+
::Type{SplitZeroBridge{T,F,G}},
59+
) where {T,F,G}
5560
return Tuple{DataType,DataType}[(F, MOI.Zeros)]
5661
end
5762
function MOI.Bridges.Constraint.concrete_bridge_type(
@@ -64,7 +69,10 @@ function MOI.Bridges.Constraint.concrete_bridge_type(
6469
end
6570

6671
# Attributes, Bridge acting as a model
67-
function MOI.get(::SplitZeroBridge{T,F}, ::MOI.NumberOfConstraints{F,MOI.Zeros}) where {T,F}
72+
function MOI.get(
73+
::SplitZeroBridge{T,F},
74+
::MOI.NumberOfConstraints{F,MOI.Zeros},
75+
) where {T,F}
6876
return 1
6977
end
7078
function MOI.get(
@@ -76,7 +84,7 @@ end
7684

7785
# Indices
7886
function MOI.delete(model::MOI.ModelLike, bridge::SplitZeroBridge)
79-
MOI.delete(model, bridge.constraint)
87+
return MOI.delete(model, bridge.constraint)
8088
end
8189

8290
# Attributes, Bridge acting as a constraint
@@ -85,7 +93,6 @@ function MOI.supports(
8593
::Union{MOI.ConstraintPrimalStart,MOI.ConstraintDualStart},
8694
::Type{<:SplitZeroBridge},
8795
)
88-
8996
return true
9097
end
9198
function MOI.get(
@@ -114,12 +121,15 @@ function MOI.set(
114121
bridge::SplitZeroBridge{T},
115122
value,
116123
) where {T}
117-
input = Vector{T}(undef, length(bridge.real_indices) + length(bridge.imag_indices))
124+
input = Vector{T}(
125+
undef,
126+
length(bridge.real_indices) + length(bridge.imag_indices),
127+
)
118128
for (i, idx) in enumerate(bridge.real_indices)
119129
input[i] = real(value[idx])
120130
end
121131
for (i, idx) in enumerate(bridge.imag_indices)
122132
input[length(bridge.real_indices)+i] = imag(value[idx])
123133
end
124-
MOI.set(model, attr, bridge.constraint, input)
134+
return MOI.set(model, attr, bridge.constraint, input)
125135
end

Diff for: src/Bridges/Variable/psd.jl

+35-17
Original file line numberDiff line numberDiff line change
@@ -51,10 +51,11 @@ function MOIB.Variable.bridge_constrained_variable(
5151
model::MOI.ModelLike,
5252
set::COI.HermitianPositiveSemidefiniteConeTriangle,
5353
) where {T}
54-
5554
n = set.side_dimension
56-
variables, psd_constraint =
57-
MOI.add_constrained_variables(model, MOI.PositiveSemidefiniteConeTriangle(2n))
55+
variables, psd_constraint = MOI.add_constrained_variables(
56+
model,
57+
MOI.PositiveSemidefiniteConeTriangle(2n),
58+
)
5859

5960
k11 = 0
6061
k12 = MOI.dimension(MOI.PositiveSemidefiniteConeTriangle(n))
@@ -72,9 +73,9 @@ function MOIB.Variable.bridge_constrained_variable(
7273
con_11_22 = EQ{T}[]
7374
con12diag = EQ{T}[]
7475
con_12_21 = EQ{T}[]
75-
for j = 1:n
76+
for j in 1:n
7677
k22 += n
77-
for i = 1:j
78+
for i in 1:j
7879
k11 += 1
7980
k12 += 1
8081
k22 += 1
@@ -124,23 +125,33 @@ function MOIB.Variable.supports_constrained_variable(
124125
)
125126
return true
126127
end
127-
function MOIB.added_constrained_variable_types(::Type{<:HermitianToSymmetricPSDBridge})
128+
function MOIB.added_constrained_variable_types(
129+
::Type{<:HermitianToSymmetricPSDBridge},
130+
)
128131
return [(MOI.PositiveSemidefiniteConeTriangle,)]
129132
end
130-
function MOIB.added_constraint_types(::Type{HermitianToSymmetricPSDBridge{T}}) where {T}
133+
function MOIB.added_constraint_types(
134+
::Type{HermitianToSymmetricPSDBridge{T}},
135+
) where {T}
131136
return [(MOI.ScalarAffineFunction{T}, MOI.EqualTo{T})]
132137
end
133138

134139
# Attributes, Bridge acting as a model
135140
function MOI.get(bridge::HermitianToSymmetricPSDBridge, ::MOI.NumberOfVariables)
136141
return length(bridge.variables)
137142
end
138-
function MOI.get(bridge::HermitianToSymmetricPSDBridge, ::MOI.ListOfVariableIndices)
143+
function MOI.get(
144+
bridge::HermitianToSymmetricPSDBridge,
145+
::MOI.ListOfVariableIndices,
146+
)
139147
return bridge.variables
140148
end
141149
function MOI.get(
142150
bridge::HermitianToSymmetricPSDBridge,
143-
::MOI.NumberOfConstraints{MOI.VectorOfVariables,MOI.PositiveSemidefiniteConeTriangle},
151+
::MOI.NumberOfConstraints{
152+
MOI.VectorOfVariables,
153+
MOI.PositiveSemidefiniteConeTriangle,
154+
},
144155
)
145156
return 1
146157
end
@@ -157,7 +168,9 @@ function MOI.get(
157168
bridge::HermitianToSymmetricPSDBridge{T},
158169
::MOI.NumberOfConstraints{MOI.ScalarAffineFunction{T},MOI.EqualTo{T}},
159170
) where {T}
160-
return length(bridge.con_11_22) + length(bridge.con12diag) + length(bridge.con_12_21)
171+
return length(bridge.con_11_22) +
172+
length(bridge.con12diag) +
173+
length(bridge.con_12_21)
161174
end
162175
function MOI.get(
163176
bridge::HermitianToSymmetricPSDBridge{T},
@@ -177,7 +190,7 @@ function MOI.delete(model::MOI.ModelLike, bridge::HermitianToSymmetricPSDBridge)
177190
for ci in bridge.con_12_21
178191
MOI.delete(model, ci)
179192
end
180-
MOI.delete(model, bridge.variables)
193+
return MOI.delete(model, bridge.variables)
181194
end
182195

183196
# Attributes, Bridge acting as a constraint
@@ -187,7 +200,9 @@ function MOI.get(
187200
::MOI.ConstraintSet,
188201
bridge::HermitianToSymmetricPSDBridge,
189202
)
190-
return COI.HermitianPositiveSemidefiniteConeTriangle(length(bridge.con12diag))
203+
return COI.HermitianPositiveSemidefiniteConeTriangle(
204+
length(bridge.con12diag),
205+
)
191206
end
192207

193208
function _matrix_indices(k)
@@ -212,7 +227,10 @@ function _variable_map(idx::MOIB.IndexInVector, n)
212227
return idx.value
213228
else
214229
i, j = _matrix_indices(idx.value - N)
215-
return N + j * n + MOI.dimension(MOI.PositiveSemidefiniteConeTriangle(j)) + i
230+
return N +
231+
j * n +
232+
MOI.dimension(MOI.PositiveSemidefiniteConeTriangle(j)) +
233+
i
216234
end
217235
end
218236
function _variable(bridge::HermitianToSymmetricPSDBridge, i::MOIB.IndexInVector)
@@ -227,7 +245,7 @@ function MOI.get(
227245
values = MOI.get(model, attr, bridge.psd_constraint)
228246
M = MOI.dimension(MOI.get(model, MOI.ConstraintSet(), bridge))
229247
n = length(bridge.con12diag)
230-
return [values[_variable_map(MOIB.IndexInVector(i), n)] for i = 1:M]
248+
return [values[_variable_map(MOIB.IndexInVector(i), n)] for i in 1:M]
231249
end
232250

233251
# See docstring of bridge for why we ignore the dual of the constraints
@@ -247,10 +265,10 @@ function MOI.get(
247265
k21 = MOI.dimension(MOI.PositiveSemidefiniteConeTriangle(2n)) + 1
248266
k22 = N
249267
k = 0
250-
for j = 1:n
268+
for j in 1:n
251269
k21 -= n + 1 - j
252270
k22 += n
253-
for i = 1:j
271+
for i in 1:j
254272
k11 += 1
255273
k12 += 1
256274
k21 -= 1
@@ -275,7 +293,7 @@ function MOI.get(
275293
bridge::HermitianToSymmetricPSDBridge{T},
276294
i::MOIB.IndexInVector,
277295
) where {T}
278-
value = MOI.get(model, attr, _variable(bridge, i))
296+
return value = MOI.get(model, attr, _variable(bridge, i))
279297
end
280298

281299
function MOIB.bridged_function(

Diff for: src/ComplexOptInterface.jl

+10-3
Original file line numberDiff line numberDiff line change
@@ -9,24 +9,31 @@ const MOI = MathOptInterface
99
struct HermitianPositiveSemidefiniteConeTriangle <: MOI.AbstractVectorSet
1010
side_dimension::Int
1111
end
12+
1213
function MOI.dimension(set::HermitianPositiveSemidefiniteConeTriangle)
13-
return MOI.dimension(MOI.PositiveSemidefiniteConeTriangle(set.side_dimension)) +
14-
MOI.dimension(MOI.PositiveSemidefiniteConeTriangle(set.side_dimension - 1))
14+
return MOI.dimension(
15+
MOI.PositiveSemidefiniteConeTriangle(set.side_dimension),
16+
) + MOI.dimension(
17+
MOI.PositiveSemidefiniteConeTriangle(set.side_dimension - 1),
18+
)
1519
end
1620

21+
Base.copy(set::HermitianPositiveSemidefiniteConeTriangle) = set
22+
1723
function MOI.Utilities.set_dot(
1824
x::AbstractVector,
1925
y::AbstractVector,
2026
set::HermitianPositiveSemidefiniteConeTriangle,
2127
)
2228
sym = MOI.PositiveSemidefiniteConeTriangle(set.side_dimension)
2329
result = MOI.Utilities.set_dot(x, y, sym)
24-
for k = (MOI.dimension(sym)+1):MOI.dimension(set)
30+
for k in (MOI.dimension(sym)+1):MOI.dimension(set)
2531
result = MA.add_mul!!(result, 2, x[k], y[k])
2632
end
2733
return result
2834
end
2935

3036
include("Bridges/Bridges.jl")
37+
include("jump.jl")
3138

3239
end # module

0 commit comments

Comments
 (0)