|
1 | | -CONIC_OPTIMIZERS = [SCS.Optimizer, ProxSDP.Optimizer, COSMO.Optimizer] |
2 | | - |
3 | | -@testset "MOI to MatOI conversion 1" begin |
4 | | - # _psd1test: https://github.com/jump-dev/MathOptInterface.jl/blob/master/src/Test/contconic.jl#L2417 |
5 | | - |
6 | | - for optimizer in CONIC_OPTIMIZERS |
7 | | - model = MOI.instantiate(optimizer, with_bridge_type=Float64) |
8 | | - δ = √(1 + (3*√2+2)*√(-116*√2+166) / 14) / 2 |
9 | | - ε = √((1 - 2*(√2-1)*δ^2) / (2-√2)) |
10 | | - y2 = 1 - ε*δ |
11 | | - y1 = 1 - √2*y2 |
12 | | - obj = y1 + y2/2 |
13 | | - k = -2*δ/ε |
14 | | - x2 = ((3-2obj)*(2+k^2)-4) / (4*(2+k^2)-4*√2) |
15 | | - α = √(3-2obj-4x2)/2 |
16 | | - β = k*α |
17 | | - |
18 | | - X = MOI.add_variables(model, 6) |
19 | | - x = MOI.add_variables(model, 3) |
20 | | - |
21 | | - vov = MOI.VectorOfVariables(X) |
22 | | - |
23 | | - cX = MOI.add_constraint( |
24 | | - model, |
25 | | - MOI.VectorAffineFunction{Float64}(vov), MOI.PositiveSemidefiniteConeTriangle(3) |
26 | | - ) |
| 1 | +function _test_matrix_equal(A::SparseMatrixCSC, B::SparseMatrixCSC) |
| 2 | + @test A.m == B.m |
| 3 | + @test A.n == B.n |
| 4 | + @test A.nzval ≈ B.nzval atol=ATOL rtol=RTOL |
| 5 | + @test A.rowval == B.rowval |
| 6 | + @test A.colptr == B.colptr |
| 7 | +end |
| 8 | +function _test_matrix_equal(A::MatOI.SparseMatrixCSRtoCSC, B::SparseMatrixCSC) |
| 9 | + @test A.m == B.m |
| 10 | + @test A.n == B.n |
| 11 | + @test A.nzval ≈ B.nzval atol=ATOL rtol=RTOL |
| 12 | + @test A.rowval == B.rowval .- 1 |
| 13 | + @test A.colptr == B.colptr .- 1 |
| 14 | + sA = convert(typeof(B), A) |
| 15 | + @test typeof(sA) == typeof(B) |
| 16 | + _test_matrix_equal(sA, B) |
| 17 | +end |
27 | 18 |
|
28 | | - cx = MOI.add_constraint( |
29 | | - model, |
30 | | - MOI.VectorAffineFunction{Float64}(MOI.VectorOfVariables(x)), MOI.SecondOrderCone(3) |
| 19 | +# _psd1test: https://github.com/jump-dev/MathOptInterface.jl/blob/master/src/Test/contconic.jl#L2417 |
| 20 | +function psd1(::Type{T}) where T |
| 21 | + # We use `MockOptimizer` to have indices xor'ed so that it tests that we don't assumes they are `1:n`. |
| 22 | + model = MOIU.MockOptimizer(MOIU.Model{T}()) |
| 23 | + |
| 24 | + X = MOI.add_variables(model, 6) |
| 25 | + x = MOI.add_variables(model, 3) |
| 26 | + |
| 27 | + vov = MOI.VectorOfVariables(X) |
| 28 | + |
| 29 | + cX = MOI.add_constraint( |
| 30 | + model, |
| 31 | + MOI.VectorAffineFunction{T}(vov), MOI.PositiveSemidefiniteConeTriangle(3) |
| 32 | + ) |
| 33 | + |
| 34 | + cx = MOI.add_constraint( |
| 35 | + model, |
| 36 | + MOI.VectorAffineFunction{T}(MOI.VectorOfVariables(x)), MOI.SecondOrderCone(3) |
| 37 | + ) |
| 38 | + |
| 39 | + c1 = MOI.add_constraint( |
| 40 | + model, |
| 41 | + MOI.VectorAffineFunction( |
| 42 | + MOI.VectorAffineTerm.(1:1, MOI.ScalarAffineTerm.(ones(T, 4), [X[1], X[3], X[end], x[1]])), |
| 43 | + [-one(T)] |
| 44 | + ), |
| 45 | + MOI.Zeros(1) |
| 46 | + ) |
| 47 | + |
| 48 | + c2 = MOI.add_constraint( |
| 49 | + model, |
| 50 | + MOI.VectorAffineFunction( |
| 51 | + MOI.VectorAffineTerm.(1:1, MOI.ScalarAffineTerm.(T[1, 2, 1, 2, 2, 1, 1, 1], [X; x[2]; x[3]])), |
| 52 | + [-inv(T(2))] |
| 53 | + ), |
| 54 | + MOI.Zeros(1) |
| 55 | + ) |
| 56 | + |
| 57 | + objXidx = [1:3; 5:6] |
| 58 | + objXcoefs = 2ones(T, 5) |
| 59 | + MOI.set( |
| 60 | + model, |
| 61 | + MOI.ObjectiveFunction{MOI.ScalarAffineFunction{T}}(), |
| 62 | + MOI.ScalarAffineFunction( |
| 63 | + MOI.ScalarAffineTerm.([objXcoefs; one(T)], [X[objXidx]; x[1]]), |
| 64 | + zero(T) |
31 | 65 | ) |
32 | | - |
33 | | - c1 = MOI.add_constraint( |
34 | | - model, |
35 | | - MOI.VectorAffineFunction( |
36 | | - MOI.VectorAffineTerm.(1:1, MOI.ScalarAffineTerm.([1., 1., 1., 1.], [X[1], X[3], X[end], x[1]])), |
37 | | - [-1.0] |
38 | | - ), |
39 | | - MOI.Zeros(1) |
| 66 | + ) |
| 67 | + MOI.set(model, MOI.ObjectiveSense(), MOI.MIN_SENSE) |
| 68 | + |
| 69 | + conic_form = MatOI.GeometricConicForm{T, MatOI.SparseMatrixCSRtoCSC{T, Int}, Vector{T}}([MOI.PositiveSemidefiniteConeTriangle, MOI.SecondOrderCone, MOI.Zeros]) |
| 70 | + index_map = MOI.copy_to(conic_form, model) |
| 71 | + |
| 72 | + @test conic_form.c' ≈ T[2 2 2 0 2 2 1 0 0] |
| 73 | + @test conic_form.b' ≈ T[0 0 0 0 0 0 0 0 0 -1 -inv(T(2))] |
| 74 | + _test_matrix_equal( |
| 75 | + conic_form.A, |
| 76 | + SparseMatrixCSC( |
| 77 | + 11, 9, |
| 78 | + [1, 4, 6, 9, 11, 13, 16, 18, 20, 22], |
| 79 | + [1, 10, 11, 2, 11, 3, 10, 11, 4, 11, 5, 11, 6, 10, 11, 7, 10, 8, 11, 9, 11], |
| 80 | + T[-1, -1, -1, -1, -2, -1, -1, -1, -1, -2, -1, -2, -1, -1, -1, -1, -1, -1, -1, -1, -1], |
40 | 81 | ) |
41 | | - |
42 | | - c2 = MOI.add_constraint( |
43 | | - model, |
44 | | - MOI.VectorAffineFunction( |
45 | | - MOI.VectorAffineTerm.(1:1, MOI.ScalarAffineTerm.([1., 2, 1, 2, 2, 1, 1, 1], [X; x[2]; x[3]])), |
46 | | - [-0.5] |
47 | | - ), |
48 | | - MOI.Zeros(1) |
49 | | - ) |
50 | | - |
51 | | - objXidx = [1:3; 5:6] |
52 | | - objXcoefs = 2*ones(5) |
53 | | - MOI.set(model, MOI.ObjectiveFunction{MOI.ScalarAffineFunction{Float64}}(), |
54 | | - MOI.ScalarAffineFunction(MOI.ScalarAffineTerm.([objXcoefs; 1.0], [X[objXidx]; x[1]]), 0.0)) |
55 | | - MOI.set(model, MOI.ObjectiveSense(), MOI.MIN_SENSE) |
56 | | - |
57 | | - MatModel = MatOI.get_conic_form(Float64, model, [cX; cx; c1; c2]) |
58 | | - |
59 | | - @test MatModel.c' ≈ [2. 2. 2. 0. 2. 2. 1. 0. 0.] |
60 | | - @test MatModel.b' ≈ [0. 0. 0. 0. 0. 0. 0. 0. 0. -1. -0.5 ] |
61 | | - @test MatModel.A.nzval ≈ [-1.0, -1.0, -1.0, -1.0, -2.0, -1.0, -1.0, -1.0, -1.0, -2.0, -1.0, -2.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0] atol=ATOL rtol=RTOL |
62 | | - end |
| 82 | + ) |
63 | 83 | end |
64 | 84 |
|
65 | | -@testset "MOI to MatOI conversion 2" begin |
66 | | - # find equivalent diffcp program here - https://github.com/AKS1996/jump-gsoc-2020/blob/master/diffcp_sdp_3_py.ipynb |
67 | | - |
68 | | - for optimizer in CONIC_OPTIMIZERS |
69 | | - model = MOI.instantiate(optimizer, with_bridge_type=Float64) |
70 | | - |
71 | | - x = MOI.add_variables(model, 7) |
72 | | - @test MOI.get(model, MOI.NumberOfVariables()) == 7 |
73 | | - |
74 | | - η = 10.0 |
75 | | - |
76 | | - c1 = MOI.add_constraint( |
77 | | - model, |
78 | | - MOI.VectorAffineFunction( |
79 | | - MOI.VectorAffineTerm.(1, MOI.ScalarAffineTerm.(-1.0, x[1:6])), |
80 | | - [η] |
81 | | - ), |
82 | | - MOI.Nonnegatives(1) |
| 85 | +# Taken from `MOI.Test.psdt2test`. |
| 86 | +# find equivalent diffcp program here - https://github.com/AKS1996/jump-gsoc-2020/blob/master/diffcp_sdp_3_py.ipynb |
| 87 | +function psd2(::Type{T}, η::T = T(10), α::T = T(4)/T(5), δ::T = T(9)/T(10)) where T |
| 88 | + # We use `MockOptimizer` to have indices xor'ed so that it tests that we don't assumes they are `1:n`. |
| 89 | + model = MOIU.MockOptimizer(MOIU.Model{T}()) |
| 90 | + |
| 91 | + x = MOI.add_variables(model, 7) |
| 92 | + |
| 93 | + c1 = MOI.add_constraint( |
| 94 | + model, |
| 95 | + MOI.VectorAffineFunction( |
| 96 | + MOI.VectorAffineTerm.(1, MOI.ScalarAffineTerm.(-one(T), x[1:6])), |
| 97 | + [η] |
| 98 | + ), |
| 99 | + MOI.Nonnegatives(1) |
| 100 | + ) |
| 101 | + c2 = MOI.add_constraint(model, MOI.VectorAffineFunction(MOI.VectorAffineTerm.(1:6, MOI.ScalarAffineTerm.(one(T), x[1:6])), zeros(T, 6)), MOI.Nonnegatives(6)) |
| 102 | + |
| 103 | + c3 = MOI.add_constraint( |
| 104 | + model, |
| 105 | + MOI.VectorAffineFunction( |
| 106 | + MOI.VectorAffineTerm.( |
| 107 | + [fill(1, 7); fill(2, 5); fill(3, 6)], |
| 108 | + MOI.ScalarAffineTerm.( |
| 109 | + [ δ/2, α, δ, δ/4, δ/8, 0, -1, |
| 110 | + -δ/(2*√2), -δ/4, 0, -δ/(8*√2), 0, |
| 111 | + δ/2, δ-α, 0, δ/8, δ/4, -1], |
| 112 | + [x[1:7]; x[1:3]; x[5:6]; x[1:3]; x[5:7]])), |
| 113 | + zeros(T, 3) |
| 114 | + ), |
| 115 | + MOI.PositiveSemidefiniteConeTriangle(2) |
| 116 | + ) |
| 117 | + c4 = MOI.add_constraint( |
| 118 | + model, |
| 119 | + MOI.VectorAffineFunction( |
| 120 | + MOI.VectorAffineTerm.(1, MOI.ScalarAffineTerm.(zero(T), [x[1:3]; x[5:6]])), |
| 121 | + [zero(T)] |
| 122 | + ), |
| 123 | + MOI.Zeros(1) |
| 124 | + ) |
| 125 | + |
| 126 | + MOI.set(model, MOI.ObjectiveFunction{MOI.ScalarAffineFunction{T}}(), MOI.ScalarAffineFunction([MOI.ScalarAffineTerm(one(T), x[7])], zero(T))) |
| 127 | + MOI.set(model, MOI.ObjectiveSense(), MOI.MAX_SENSE) |
| 128 | + |
| 129 | + conic_form = MatOI.GeometricConicForm{T, MatOI.SparseMatrixCSRtoCSC{T, Int}, Vector{T}}([MOI.Nonnegatives, MOI.Zeros, MOI.PositiveSemidefiniteConeTriangle]) |
| 130 | + index_map = MOI.copy_to(conic_form, model) |
| 131 | + |
| 132 | + @test conic_form.c ≈ [zeros(T, 6); one(T)] |
| 133 | + @test conic_form.b ≈ [T(10); zeros(T, 10)] |
| 134 | + _test_matrix_equal( |
| 135 | + conic_form.A, |
| 136 | + SparseMatrixCSC( |
| 137 | + 11, 7, |
| 138 | + [1, 6, 11, 14, 17, 22, 25, 27], |
| 139 | + [1, 2, 9, 10, 11, 1, 3, 9, 10, 11, 1, 4, 9, 1, 5, 9, 1, 6, 9, 10, 11, 1, 7, 11, 9, 11], |
| 140 | + T[1.0, -1.0, -0.45, 0.318198, -0.45, 1.0, -1.0, -0.8, 0.225, -0.1, 1.0, -1.0, -0.9, 1.0, -1.0, -0.225, 1.0, -1.0, -0.1125, 0.0795495, -0.1125, 1.0, -1.0, -0.225, 1.0, 1.0], |
83 | 141 | ) |
84 | | - c2 = MOI.add_constraint(model, MOI.VectorAffineFunction(MOI.VectorAffineTerm.(1:6, MOI.ScalarAffineTerm.(1.0, x[1:6])), zeros(6)), MOI.Nonnegatives(6)) |
85 | | - α = 0.8 |
86 | | - δ = 0.9 |
87 | | - c3 = MOI.add_constraint(model, MOI.VectorAffineFunction(MOI.VectorAffineTerm.([fill(1, 7); fill(2, 5); fill(3, 6)], |
88 | | - MOI.ScalarAffineTerm.( |
89 | | - [ δ/2, α, δ, δ/4, δ/8, 0.0, -1.0, |
90 | | - -δ/(2*√2), -δ/4, 0, -δ/(8*√2), 0.0, |
91 | | - δ/2, δ-α, 0, δ/8, δ/4, -1.0], |
92 | | - [x[1:7]; x[1:3]; x[5:6]; x[1:3]; x[5:7]])), |
93 | | - zeros(3)), MOI.PositiveSemidefiniteConeTriangle(2)) |
94 | | - c4 = MOI.add_constraint( |
95 | | - model, |
96 | | - MOI.VectorAffineFunction( |
97 | | - MOI.VectorAffineTerm.(1, MOI.ScalarAffineTerm.(0.0, [x[1:3]; x[5:6]])), |
98 | | - [0.0] |
99 | | - ), |
100 | | - MOI.Zeros(1) |
101 | | - ) |
102 | | - |
103 | | - MOI.set(model, MOI.ObjectiveFunction{MOI.ScalarAffineFunction{Float64}}(), MOI.ScalarAffineFunction([MOI.ScalarAffineTerm(1.0, x[7])], 0.0)) |
104 | | - MOI.set(model, MOI.ObjectiveSense(), MOI.MAX_SENSE) |
105 | | - |
106 | | - MatModel = MatOI.get_conic_form(Float64, model, [c1; c2; c3; c4]) |
107 | | - |
108 | | - @test MatModel.c ≈ [-0.0, -0.0, -0.0, -0.0, -0.0, -0.0, -1.0] |
109 | | - @test MatModel.b ≈ [10.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0] |
110 | | - @test MatModel.A.nzval ≈ [1.0, -1.0, -0.45, 0.318198, -0.45, 1.0, -1.0, -0.8, 0.225, -0.1, 1.0, -1.0, -0.9, 1.0, -1.0, -0.225, 1.0, -1.0, -0.1125, 0.0795495, -0.1125, 1.0, -1.0, -0.225, 1.0, 1.0] atol=ATOL rtol=RTOL |
111 | | - end |
| 142 | + ) |
112 | 143 | end |
113 | 144 |
|
114 | | -@testset "Testing minor utilities" begin |
115 | | - model = MOI.instantiate(SCS.Optimizer, with_bridge_type=Float64) |
116 | | - cf = MatOI.get_conic_form(Float64,model,[]) |
117 | | - @test MOI.is_empty(cf) == false |
118 | | - MOI.empty!(cf) |
119 | | - @test MOI.is_empty(cf) == true |
| 145 | +@testset "PSD $T" for T in [Float64, BigFloat] |
| 146 | + psd1(T) |
| 147 | + psd2(T) |
120 | 148 | end |
0 commit comments