jump-dev / ComplexOptInterface.jl

@@ -51,10 +51,11 @@
Loading
51 51
    model::MOI.ModelLike,
52 52
    set::COI.HermitianPositiveSemidefiniteConeTriangle,
53 53
) where {T}
54 -
55 54
    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 +
    )
58 59
59 60
    k11 = 0
60 61
    k12 = MOI.dimension(MOI.PositiveSemidefiniteConeTriangle(n))
@@ -72,9 +73,9 @@
Loading
72 73
    con_11_22 = EQ{T}[]
73 74
    con12diag = EQ{T}[]
74 75
    con_12_21 = EQ{T}[]
75 -
    for j = 1:n
76 +
    for j in 1:n
76 77
        k22 += n
77 -
        for i = 1:j
78 +
        for i in 1:j
78 79
            k11 += 1
79 80
            k12 += 1
80 81
            k22 += 1
@@ -124,10 +125,14 @@
Loading
124 125
)
125 126
    return true
126 127
end
127 -
function MOIB.added_constrained_variable_types(::Type{<:HermitianToSymmetricPSDBridge})
128 +
function MOIB.added_constrained_variable_types(
129 +
    ::Type{<:HermitianToSymmetricPSDBridge},
130 +
)
128 131
    return [(MOI.PositiveSemidefiniteConeTriangle,)]
129 132
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}
131 136
    return [(MOI.ScalarAffineFunction{T}, MOI.EqualTo{T})]
132 137
end
133 138
@@ -135,12 +140,18 @@
Loading
135 140
function MOI.get(bridge::HermitianToSymmetricPSDBridge, ::MOI.NumberOfVariables)
136 141
    return length(bridge.variables)
137 142
end
138 -
function MOI.get(bridge::HermitianToSymmetricPSDBridge, ::MOI.ListOfVariableIndices)
143 +
function MOI.get(
144 +
    bridge::HermitianToSymmetricPSDBridge,
145 +
    ::MOI.ListOfVariableIndices,
146 +
)
139 147
    return bridge.variables
140 148
end
141 149
function MOI.get(
142 150
    bridge::HermitianToSymmetricPSDBridge,
143 -
    ::MOI.NumberOfConstraints{MOI.VectorOfVariables,MOI.PositiveSemidefiniteConeTriangle},
151 +
    ::MOI.NumberOfConstraints{
152 +
        MOI.VectorOfVariables,
153 +
        MOI.PositiveSemidefiniteConeTriangle,
154 +
    },
144 155
)
145 156
    return 1
146 157
end
@@ -157,7 +168,9 @@
Loading
157 168
    bridge::HermitianToSymmetricPSDBridge{T},
158 169
    ::MOI.NumberOfConstraints{MOI.ScalarAffineFunction{T},MOI.EqualTo{T}},
159 170
) 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)
161 174
end
162 175
function MOI.get(
163 176
    bridge::HermitianToSymmetricPSDBridge{T},
@@ -177,7 +190,7 @@
Loading
177 190
    for ci in bridge.con_12_21
178 191
        MOI.delete(model, ci)
179 192
    end
180 -
    MOI.delete(model, bridge.variables)
193 +
    return MOI.delete(model, bridge.variables)
181 194
end
182 195
183 196
# Attributes, Bridge acting as a constraint
@@ -187,7 +200,9 @@
Loading
187 200
    ::MOI.ConstraintSet,
188 201
    bridge::HermitianToSymmetricPSDBridge,
189 202
)
190 -
    return COI.HermitianPositiveSemidefiniteConeTriangle(length(bridge.con12diag))
203 +
    return COI.HermitianPositiveSemidefiniteConeTriangle(
204 +
        length(bridge.con12diag),
205 +
    )
191 206
end
192 207
193 208
function _matrix_indices(k)
@@ -212,7 +227,10 @@
Loading
212 227
        return idx.value
213 228
    else
214 229
        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
216 234
    end
217 235
end
218 236
function _variable(bridge::HermitianToSymmetricPSDBridge, i::MOIB.IndexInVector)
@@ -227,7 +245,7 @@
Loading
227 245
    values = MOI.get(model, attr, bridge.psd_constraint)
228 246
    M = MOI.dimension(MOI.get(model, MOI.ConstraintSet(), bridge))
229 247
    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]
231 249
end
232 250
233 251
# See docstring of bridge for why we ignore the dual of the constraints
@@ -247,10 +265,10 @@
Loading
247 265
    k21 = MOI.dimension(MOI.PositiveSemidefiniteConeTriangle(2n)) + 1
248 266
    k22 = N
249 267
    k = 0
250 -
    for j = 1:n
268 +
    for j in 1:n
251 269
        k21 -= n + 1 - j
252 270
        k22 += n
253 -
        for i = 1:j
271 +
        for i in 1:j
254 272
            k11 += 1
255 273
            k12 += 1
256 274
            k21 -= 1
@@ -275,7 +293,7 @@
Loading
275 293
    bridge::HermitianToSymmetricPSDBridge{T},
276 294
    i::MOIB.IndexInVector,
277 295
) where {T}
278 -
    value = MOI.get(model, attr, _variable(bridge, i))
296 +
    return value = MOI.get(model, attr, _variable(bridge, i))
279 297
end
280 298
281 299
function MOIB.bridged_function(

@@ -10,7 +10,8 @@
Loading
10 10
end
11 11
function _nonzero_indices(func::MOI.AbstractVectorFunction)
12 12
    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)
14 15
    ]
15 16
end
16 17
function MOI.Bridges.Constraint.bridge_constraint(
@@ -50,8 +51,12 @@
Loading
50 51
) where {T}
51 52
    return true
52 53
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}
55 60
    return Tuple{DataType,DataType}[(F, MOI.Zeros)]
56 61
end
57 62
function MOI.Bridges.Constraint.concrete_bridge_type(
@@ -64,7 +69,10 @@
Loading
64 69
end
65 70
66 71
# 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}
68 76
    return 1
69 77
end
70 78
function MOI.get(
@@ -76,7 +84,7 @@
Loading
76 84
77 85
# Indices
78 86
function MOI.delete(model::MOI.ModelLike, bridge::SplitZeroBridge)
79 -
    MOI.delete(model, bridge.constraint)
87 +
    return MOI.delete(model, bridge.constraint)
80 88
end
81 89
82 90
# Attributes, Bridge acting as a constraint
@@ -85,7 +93,6 @@
Loading
85 93
    ::Union{MOI.ConstraintPrimalStart,MOI.ConstraintDualStart},
86 94
    ::Type{<:SplitZeroBridge},
87 95
)
88 -
89 96
    return true
90 97
end
91 98
function MOI.get(
@@ -114,12 +121,15 @@
Loading
114 121
    bridge::SplitZeroBridge{T},
115 122
    value,
116 123
) 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 +
    )
118 128
    for (i, idx) in enumerate(bridge.real_indices)
119 129
        input[i] = real(value[idx])
120 130
    end
121 131
    for (i, idx) in enumerate(bridge.imag_indices)
122 132
        input[length(bridge.real_indices)+i] = imag(value[idx])
123 133
    end
124 -
    MOI.set(model, attr, bridge.constraint, input)
134 +
    return MOI.set(model, attr, bridge.constraint, input)
125 135
end

@@ -0,0 +1,113 @@
Loading
1 +
import LinearAlgebra
2 +
import JuMP
3 +
4 +
function add_all_bridges(model::JuMP.Model)
5 +
    JuMP.add_bridge(model, Bridges.Variable.HermitianToSymmetricPSDBridge)
6 +
    JuMP.add_bridge(model, Bridges.Constraint.SplitEqualToBridge)
7 +
    return JuMP.add_bridge(model, Bridges.Constraint.SplitZeroBridge)
8 +
end
9 +
10 +
struct HermitianPSDCone end
11 +
12 +
struct HermitianMatrixShape <: JuMP.AbstractShape
13 +
    side_dimension::Int
14 +
end
15 +
16 +
function JuMP.vectorize(matrix::Matrix, ::HermitianMatrixShape)
17 +
    n = LinearAlgebra.checksquare(matrix)
18 +
    return vcat(
19 +
        JuMP.vectorize(_real.(matrix), JuMP.SymmetricMatrixShape(n)),
20 +
        JuMP.vectorize(
21 +
            _imag.(matrix[1:(end-1), 2:end]),
22 +
            JuMP.SymmetricMatrixShape(n - 1),
23 +
        ),
24 +
    )
25 +
end
26 +
27 +
function JuMP.reshape_vector(
28 +
    v::Vector{T},
29 +
    shape::HermitianMatrixShape,
30 +
) where {T}
31 +
    NewType = MA.promote_operation(MA.add_mul, T, Complex{Bool}, T)
32 +
    n = shape.side_dimension
33 +
    matrix = Matrix{NewType}(undef, n, n)
34 +
    real_k = 0
35 +
    imag_k = MOI.dimension(MOI.PositiveSemidefiniteConeTriangle(n))
36 +
    for j in 1:n
37 +
        for i in 1:(j-1)
38 +
            real_k += 1
39 +
            imag_k += 1
40 +
            matrix[i, j] = v[real_k] + im * v[imag_k]
41 +
            matrix[j, i] = v[real_k] - im * v[imag_k]
42 +
        end
43 +
        real_k += 1
44 +
        matrix[j, j] = v[real_k]
45 +
    end
46 +
    return matrix
47 +
end
48 +
49 +
function _mapinfo(f::Function, v::JuMP.ScalarVariable)
50 +
    info = v.info
51 +
    return JuMP.ScalarVariable(
52 +
        JuMP.VariableInfo(
53 +
            info.has_lb,
54 +
            f(info.lower_bound),
55 +
            info.has_ub,
56 +
            f(info.upper_bound),
57 +
            info.has_fix,
58 +
            f(info.fixed_value),
59 +
            info.has_start,
60 +
            f(info.start),
61 +
            info.binary,
62 +
            info.integer,
63 +
        ),
64 +
    )
65 +
end
66 +
67 +
_real(s::String) = s
68 +
_imag(s::String) = s
69 +
70 +
_real(v::JuMP.ScalarVariable) = _mapinfo(real, v)
71 +
_imag(v::JuMP.ScalarVariable) = _mapinfo(imag, v)
72 +
_conj(v::JuMP.ScalarVariable) = _mapinfo(conj, v)
73 +
function _isreal(v::JuMP.ScalarVariable)
74 +
    info = v.info
75 +
    return isreal(info.lower_bound) &&
76 +
           isreal(info.upper_bound) &&
77 +
           isreal(info.fixed_value) &&
78 +
           isreal(info.start)
79 +
end
80 +
81 +
function _vectorize_variables(_error::Function, matrix::Matrix)
82 +
    n = LinearAlgebra.checksquare(matrix)
83 +
    for j in 1:n
84 +
        if !_isreal(matrix[j, j])
85 +
            _error(
86 +
                "Non-real bounds or starting values for diagonal of hermitian variable.",
87 +
            )
88 +
        end
89 +
        for i in 1:j
90 +
            if matrix[i, j] != _conj(matrix[j, i])
91 +
                _error(
92 +
                    "Non-conjugate bounds, integrality or starting values for hermitian variable.",
93 +
                )
94 +
            end
95 +
        end
96 +
    end
97 +
    return JuMP.vectorize(matrix, HermitianMatrixShape(n))
98 +
end
99 +
100 +
function JuMP.build_variable(
101 +
    _error::Function,
102 +
    variables::Matrix{<:JuMP.AbstractVariable},
103 +
    ::HermitianPSDCone,
104 +
)
105 +
    n = JuMP._square_side(_error, variables)
106 +
    set = HermitianPositiveSemidefiniteConeTriangle(n)
107 +
    shape = HermitianMatrixShape(n)
108 +
    return JuMP.VariablesConstrainedOnCreation(
109 +
        _vectorize_variables(_error, variables),
110 +
        set,
111 +
        shape,
112 +
    )
113 +
end

@@ -36,8 +36,12 @@
Loading
36 36
) where {T}
37 37
    return true
38 38
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}
41 45
    return Tuple{DataType,DataType}[(F, MOI.EqualTo{T})]
42 46
end
43 47
function MOI.Bridges.Constraint.concrete_bridge_type(
@@ -54,7 +58,8 @@
Loading
54 58
    bridge::SplitEqualToBridge{T,F},
55 59
    ::MOI.NumberOfConstraints{F,MOI.EqualTo{T}},
56 60
) where {T,F}
57 -
    return !isnothing(bridge.real_constraint) + !isnothing(bridge.imag_constraint)
61 +
    return !isnothing(bridge.real_constraint) +
62 +
           !isnothing(bridge.imag_constraint)
58 63
end
59 64
function MOI.get(
60 65
    bridge::SplitEqualToBridge{T,F},

@@ -9,11 +9,17 @@
Loading
9 9
struct HermitianPositiveSemidefiniteConeTriangle <: MOI.AbstractVectorSet
10 10
    side_dimension::Int
11 11
end
12 +
12 13
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 +
    )
15 19
end
16 20
21 +
Base.copy(set::HermitianPositiveSemidefiniteConeTriangle) = set
22 +
17 23
function MOI.Utilities.set_dot(
18 24
    x::AbstractVector,
19 25
    y::AbstractVector,
@@ -21,12 +27,13 @@
Loading
21 27
)
22 28
    sym = MOI.PositiveSemidefiniteConeTriangle(set.side_dimension)
23 29
    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)
25 31
        result = MA.add_mul!!(result, 2, x[k], y[k])
26 32
    end
27 33
    return result
28 34
end
29 35
30 36
include("Bridges/Bridges.jl")
37 +
include("jump.jl")
31 38
32 39
end # module
Files Coverage
src 60.45%
Project Totals (5 files) 60.45%
Sunburst
The inner-most circle is the entire project, moving away from the center are folders then, finally, a single file. The size and color of each slice is representing the number of statements and the coverage, respectively.
Icicle
The top section represents the entire project. Proceeding with folders and finally individual files. The size and color of each slice is representing the number of statements and the coverage, respectively.
Grid
Each block represents a single file in the project. The size and color of each block is represented by the number of statements and the coverage, respectively.
Loading