|
| 1 | +struct BlockMatrix{T} <: AbstractMatrix{T} |
| 2 | + blocks::Vector{Matrix{T}} |
| 3 | +end |
| 4 | +Base.getindex(BM::BlockMatrix, i::Integer) = BM.blocks[i] |
1 | 5 | mutable struct MockSDOptimizer{T} <: AbstractSDOptimizer |
2 | 6 | nconstrs::Int |
3 | 7 | blkdims::Vector{Int} |
4 | 8 | constraint_constants::Vector{T} |
5 | 9 | objective_coefficients::Vector{Tuple{T, Int, Int, Int}} |
6 | 10 | constraint_coefficients::Vector{Vector{Tuple{T, Int, Int, Int}}} |
| 11 | + optimize!::Function # Function used to set dummy primal/dual values and statuses |
| 12 | + hasprimal::Bool |
| 13 | + hasdual::Bool |
| 14 | + terminationstatus::MOI.TerminationStatusCode |
| 15 | + primalstatus::MOI.ResultStatusCode |
| 16 | + dualstatus::MOI.ResultStatusCode |
| 17 | + X::BlockMatrix{T} |
| 18 | + Z::BlockMatrix{T} |
| 19 | + y::Vector{T} |
7 | 20 | end |
8 | | -MockSDOptimizer{T}() where T = MockSDOptimizer{T}(0, Int[], T[], Tuple{T, Int, Int, Int}[], Vector{Tuple{T, Int, Int, Int}}[]) |
| 21 | +MockSDOptimizer{T}() where T = MockSDOptimizer{T}(0, |
| 22 | + Int[], |
| 23 | + T[], |
| 24 | + Tuple{T, Int, Int, Int}[], |
| 25 | + Vector{Tuple{T, Int, Int, Int}}[], |
| 26 | + (::MockSDOptimizer) -> begin end, |
| 27 | + false, |
| 28 | + false, |
| 29 | + MOI.Success, |
| 30 | + MOI.UnknownResultStatus, |
| 31 | + MOI.UnknownResultStatus, |
| 32 | + BlockMatrix{T}(Matrix{T}[]), |
| 33 | + BlockMatrix{T}(Matrix{T}[]), |
| 34 | + T[]) |
9 | 35 | mockSDoptimizer(T::Type) = SDOIOptimizer(MockSDOptimizer{T}(), T) |
10 | 36 | coefficienttype(::MockSDOptimizer{T}) where T = T |
11 | 37 |
|
@@ -34,3 +60,133 @@ getconstraintcoefficients(optimizer::MockSDOptimizer, c) = optimizer.constraint_ |
34 | 60 | function setconstraintcoefficient!(optimizer::MockSDOptimizer, val, c::Integer, blk::Integer, i::Integer, j::Integer) |
35 | 61 | push!(optimizer.constraint_coefficients[c], (val, blk, i, j)) |
36 | 62 | end |
| 63 | + |
| 64 | +MOI.canget(mock::MockSDOptimizer, ::MOI.PrimalStatus) = mock.hasprimal |
| 65 | +MOI.canget(mock::MockSDOptimizer, ::MOI.DualStatus) = mock.hasdual |
| 66 | +MOI.canset(mock::MockSDOptimizer, ::Union{MOI.PrimalStatus,MOI.DualStatus}) = true |
| 67 | +MOI.get(mock::MockSDOptimizer, ::MOI.TerminationStatus) = mock.terminationstatus |
| 68 | +MOI.set!(mock::MockSDOptimizer, ::MOI.TerminationStatus, value::MOI.TerminationStatusCode) = (mock.terminationstatus = value) |
| 69 | +MOI.get(mock::MockSDOptimizer, ::MOI.PrimalStatus) = mock.primalstatus |
| 70 | +MOI.set!(mock::MockSDOptimizer, ::MOI.PrimalStatus, value::MOI.ResultStatusCode) = (mock.primalstatus = value) |
| 71 | +MOI.get(mock::MockSDOptimizer, ::MOI.DualStatus) = mock.dualstatus |
| 72 | +MOI.set!(mock::MockSDOptimizer, ::MOI.DualStatus, value::MOI.ResultStatusCode) = (mock.dualstatus = value) |
| 73 | + |
| 74 | +getX(mock::MockSDOptimizer) = mock.X |
| 75 | +getZ(mock::MockSDOptimizer) = mock.Z |
| 76 | +gety(mock::MockSDOptimizer) = mock.y |
| 77 | +function getprimalobjectivevalue(mock::MockSDOptimizer{T}) where T |
| 78 | + v = zero(T) |
| 79 | + for (α, blk, i, j) in mock.objective_coefficients |
| 80 | + v += α * mock.X[blk][i, j] |
| 81 | + if i != j |
| 82 | + v += α * mock.X[blk][j, i] |
| 83 | + end |
| 84 | + end |
| 85 | + v |
| 86 | +end |
| 87 | +function getdualobjectivevalue(mock::MockSDOptimizer{T}) where T |
| 88 | + v = zero(T) |
| 89 | + for c in 1:mock.nconstrs |
| 90 | + v += mock.constraint_constants[c] * mock.y[c] |
| 91 | + end |
| 92 | + v |
| 93 | +end |
| 94 | + |
| 95 | +function MOI.optimize!(mock::MockSDOptimizer) |
| 96 | + mock.hasprimal = true |
| 97 | + mock.hasdual = true |
| 98 | + mock.optimize!(mock) |
| 99 | +end |
| 100 | + |
| 101 | +function MOIU.set_mock_optimize!(mock::MockSDOptimizer, opts::Function...) |
| 102 | + mock.optimize! = MOIU.rec_mock_optimize(mock, opts...) |
| 103 | +end |
| 104 | +# TODO remove the following methods once it is defined for AbstractMockOptimizer in MOIU |
| 105 | +function MOIU.rec_mock_optimize(mock::MockSDOptimizer, opt::Function, opts::Function...) |
| 106 | + # TODO replace mock.optimize! = ... by MOI.set!(..., MOIU.MockOptimizeFunction, ...) |
| 107 | + # where MOIU.MockOptimizeFunction is a MockModelAttribute |
| 108 | + (mock::MockSDOptimizer) -> (opt(mock); mock.optimize! = MOIU.rec_mock_optimize(mock, opts...)) |
| 109 | +end |
| 110 | +MOIU.rec_mock_optimize(mock::MockSDOptimizer, opt::Function) = opt |
| 111 | + |
| 112 | +# TOD remove the following methods once it is defined for AbstractMockSDOptimizer in MOIU |
| 113 | +function MOIU.mock_optimize!(mock::MockSDOptimizer, termstatus::MOI.TerminationStatusCode, primal, dual...) |
| 114 | + MOI.set!(mock, MOI.TerminationStatus(), termstatus) |
| 115 | + MOIU.mock_primal!(mock, primal) |
| 116 | + MOIU.mock_dual!(mock, dual...) |
| 117 | +end |
| 118 | +# Default termination status |
| 119 | +MOIU.mock_optimize!(mock::MockSDOptimizer, primdual...) = MOIU.mock_optimize!(mock, MOI.Success, primdual...) |
| 120 | +function MOIU.mock_optimize!(mock::MockSDOptimizer, termstatus::MOI.TerminationStatusCode) |
| 121 | + MOI.set!(mock, MOI.TerminationStatus(), termstatus) |
| 122 | +end |
| 123 | + |
| 124 | +# Primal |
| 125 | +function MOIU.mock_primal!(mock::MockSDOptimizer, primstatus::MOI.ResultStatusCode, varprim...) |
| 126 | + MOI.set!(mock, MOI.PrimalStatus(), primstatus) |
| 127 | + MOIU.mock_varprimal!(mock, varprim...) |
| 128 | +end |
| 129 | +# Default primal status |
| 130 | +MOIU.mock_primal!(mock::MockSDOptimizer, varprim::Vector) = MOIU.mock_primal!(mock, MOI.FeasiblePoint, varprim) |
| 131 | +function MOIU.mock_primal!(mock::MockSDOptimizer) |
| 132 | + # No primal solution |
| 133 | + mock.hasprimal = false |
| 134 | +end |
| 135 | + |
| 136 | +# Sets variable primal to varprim |
| 137 | +function MOIU.mock_varprimal!(mock::MockSDOptimizer) end |
| 138 | +function MOIU.mock_varprimal!(mock::MockSDOptimizer{T}, X::Vector{Matrix{T}}) where T |
| 139 | + mock.X = BlockMatrix{T}(X) |
| 140 | +end |
| 141 | +to_matrix(X::Matrix) = X |
| 142 | +function to_matrix(X::Vector) |
| 143 | + @assert length(X) == 1 |
| 144 | + reshape(X, 1, 1) |
| 145 | +end |
| 146 | +function MOIU.mock_varprimal!(mock::MockSDOptimizer{T}, X::Vector) where T |
| 147 | + MOIU.mock_varprimal!(mock, to_matrix.(X)) |
| 148 | +end |
| 149 | + |
| 150 | +# Dual |
| 151 | +function MOIU.mock_dual!(mock::MockSDOptimizer, dualstatus::MOI.ResultStatusCode, conduals...) |
| 152 | + MOI.set!(mock, MOI.DualStatus(), dualstatus) |
| 153 | + MOIU.mock_condual!(mock, conduals...) |
| 154 | +end |
| 155 | +# Default dual status |
| 156 | +function MOIU.mock_dual!(mock::MockSDOptimizer, conduals...) |
| 157 | + status = !mock.hasprimal || MOI.get(mock, MOI.PrimalStatus()) == MOI.InfeasiblePoint ? MOI.InfeasibilityCertificate : MOI.FeasiblePoint |
| 158 | + MOIU.mock_dual!(mock, status, conduals...) |
| 159 | +end |
| 160 | +function MOIU.mock_dual!(mock::MockSDOptimizer) |
| 161 | + # No dual solution |
| 162 | + mock.hasdual = false |
| 163 | +end |
| 164 | + |
| 165 | +# Sets constraint dual to conduals |
| 166 | +function MOIU.mock_condual!(mock::MockSDOptimizer) end |
| 167 | +function MOIU.mock_condual!(mock::MockSDOptimizer{T}, y::Vector{T}) where T |
| 168 | + mock.y = y |
| 169 | + # blockdims can be negative for diagonal blocks. We allocate full blocks |
| 170 | + # here. As mock optimizers are used only for testing, we favor simplicity. |
| 171 | + mock.Z = BlockMatrix{T}(map(n -> zeros(T, abs(n), abs(n)), mock.blkdims)) |
| 172 | + # FIXME shouldn't Z be defined as the opposite i.e. Z = C - sum y_i A_i >= 0 |
| 173 | + # instead of sum y_i A_i - C <= 0 ? |
| 174 | + if mock.dualstatus != MOI.InfeasibilityCertificate |
| 175 | + # Infeasibility certificate is a ray so we only take the homogeneous part |
| 176 | + # FIXME:check that this is also done IN MOIU.MockOptimizer |
| 177 | + for (α, blk, i, j) in mock.objective_coefficients |
| 178 | + mock.Z[blk][i, j] -= α |
| 179 | + if i != j |
| 180 | + mock.Z[blk][j, i] -= α |
| 181 | + end |
| 182 | + end |
| 183 | + end |
| 184 | + for (c, constraint_coefficients) in enumerate(mock.constraint_coefficients) |
| 185 | + for (α, blk, i, j) in constraint_coefficients |
| 186 | + mock.Z[blk][i, j] += α * y[c] |
| 187 | + if i != j |
| 188 | + mock.Z[blk][j, i] += α * y[c] |
| 189 | + end |
| 190 | + end |
| 191 | + end |
| 192 | +end |
0 commit comments