Skip to content

Commit 07cd808

Browse files
authored
Merge pull request #16 from JuliaOpt/bl/mock
Test with mock optimizer
2 parents 8790829 + ae68e22 commit 07cd808

9 files changed

Lines changed: 437 additions & 47 deletions

File tree

.travis.yml

Lines changed: 3 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -11,27 +11,9 @@ notifications:
1111
git:
1212
depth: 99999999
1313

14-
## uncomment the following lines to allow failures on nightly julia
15-
## (tests will run but not make your overall status red)
16-
#matrix:
17-
# allow_failures:
18-
# - julia: nightly
19-
20-
addons:
21-
apt: # apt-get for linux
22-
packages:
23-
- liblapack-dev
24-
- libblas-dev
25-
#before_script: # homebrew for mac
26-
# - if [ $TRAVIS_OS_NAME = osx ]; then brew install gcc; fi
27-
28-
script:
29-
- julia -e 'Pkg.clone(pwd());
30-
Pkg.build("SemidefiniteOptInterface");
31-
Pkg.add("CSDP");
32-
Pkg.checkout("CSDP");
33-
Pkg.build("CSDP");
34-
Pkg.test("SemidefiniteOptInterface"; coverage=true)'
14+
matrix:
15+
allow_failures:
16+
- julia: nightly
3517

3618
after_success:
3719
# push coverage results to Coveralls

REQUIRE

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
11
julia 0.6
22
MathOptInterface 0.4 0.5
3+
Compat 0.69

appveyor.yml

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -42,10 +42,7 @@ build_script:
4242
- IF EXIST .git\shallow (git fetch --unshallow)
4343
- C:\projects\julia\bin\julia -e "versioninfo();
4444
Pkg.clone(pwd(), \"SemidefiniteOptInterface\");
45-
Pkg.build(\"SemidefiniteOptInterface\");
46-
Pkg.add(\"CSDP\");
47-
Pkg.checkout(\"CSDP\");
48-
Pkg.build(\"CSDP\")"
45+
Pkg.build(\"SemidefiniteOptInterface\")"
4946

5047
test_script:
5148
- C:\projects\julia\bin\julia -e "Pkg.test(\"SemidefiniteOptInterface\")"

src/SemidefiniteOptInterface.jl

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -173,7 +173,9 @@ function getblock(M, blk::Int, s::Type{<:MOI.AbstractVectorSet})
173173
end
174174

175175
getvarprimal(m::SOItoMOIBridge, blk::Int, S) = getblock(getX(m.sdoptimizer), blk, S)
176-
getvardual(m::SOItoMOIBridge, blk::Int, S) = getblock(getZ(m.sdoptimizer), blk, S)
176+
function getvardual(m::SOItoMOIBridge, blk::Int, S)
177+
getblock(getZ(m.sdoptimizer), blk, S)
178+
end
177179

178180
function MOI.get(m::SOItoMOIBridge{T}, ::MOI.VariablePrimal, vi::VI) where T
179181
X = getX(m.sdoptimizer)

src/mock.jl

Lines changed: 157 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,37 @@
1+
struct BlockMatrix{T} <: AbstractMatrix{T}
2+
blocks::Vector{Matrix{T}}
3+
end
4+
Base.getindex(BM::BlockMatrix, i::Integer) = BM.blocks[i]
15
mutable struct MockSDOptimizer{T} <: AbstractSDOptimizer
26
nconstrs::Int
37
blkdims::Vector{Int}
48
constraint_constants::Vector{T}
59
objective_coefficients::Vector{Tuple{T, Int, Int, Int}}
610
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}
720
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[])
935
mockSDoptimizer(T::Type) = SDOIOptimizer(MockSDOptimizer{T}(), T)
1036
coefficienttype(::MockSDOptimizer{T}) where T = T
1137

@@ -34,3 +60,133 @@ getconstraintcoefficients(optimizer::MockSDOptimizer, c) = optimizer.constraint_
3460
function setconstraintcoefficient!(optimizer::MockSDOptimizer, val, c::Integer, blk::Integer, i::Integer, j::Integer)
3561
push!(optimizer.constraint_coefficients[c], (val, blk, i, j))
3662
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

test/REQUIRE

Lines changed: 0 additions & 1 deletion
This file was deleted.

0 commit comments

Comments
 (0)