Skip to content

Commit d640a22

Browse files
authored
Add checks for an invalid model (#135)
1 parent 7e903b4 commit d640a22

File tree

2 files changed

+56
-5
lines changed

2 files changed

+56
-5
lines changed

src/MOI_wrapper/MOI_wrapper.jl

Lines changed: 31 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -179,6 +179,15 @@ function MOI.supports_constraint(
179179
return true
180180
end
181181

182+
# This should be a valid idxint, but not one of the constants ECOS uses.
183+
const _ECOS_INVALID_MODEL = -9999
184+
185+
function _set_errored_solution_status(dest::Optimizer, status)
186+
dest.sol = _Solution()
187+
dest.sol.ret_val = status
188+
return
189+
end
190+
182191
function _optimize!(dest::Optimizer, src::OptimizerCache)
183192
MOI.empty!(dest)
184193
Ab = MOI.Utilities.constraints(
@@ -202,6 +211,10 @@ function _optimize!(dest::Optimizer, src::OptimizerCache)
202211
)
203212
q = MOI.dimension.(MOI.get.(Gh, MOI.ConstraintSet(), soc_indices))
204213
@assert A.n == G.n
214+
if A.n == 0
215+
_set_errored_solution_status(dest, _ECOS_INVALID_MODEL)
216+
return
217+
end
205218
max_sense = MOI.get(src, MOI.ObjectiveSense()) == MOI.MAX_SENSE
206219
obj =
207220
MOI.get(src, MOI.ObjectiveFunction{MOI.ScalarAffineFunction{pfloat}}())
@@ -247,7 +260,8 @@ function _optimize!(dest::Optimizer, src::OptimizerCache)
247260
Ab.constants,
248261
)
249262
if inner == C_NULL
250-
error("ECOS failed to construct problem.")
263+
_set_errored_solution_status(dest, ECOS_FATAL)
264+
return
251265
end
252266
unsafe_add_settings(inner, options)
253267
ret_val = ECOS_solve(inner)
@@ -331,9 +345,11 @@ function MOI.get(optimizer::Optimizer, ::MOI.RawStatusString)
331345
return "s or z got outside the cone, numerics?"
332346
elseif flag == ECOS_SIGINT
333347
return "solver interrupted by a signal/ctrl-c"
334-
else
335-
@assert flag == ECOS_FATAL
348+
elseif flag == ECOS_FATAL
336349
return "Unknown problem in solver"
350+
else
351+
@assert flag == _ECOS_INVALID_MODEL
352+
return "Invalid model: you must have at least one variable"
337353
end
338354
end
339355

@@ -360,9 +376,11 @@ function MOI.get(optimizer::Optimizer, ::MOI.TerminationStatus)
360376
return MOI.ALMOST_OPTIMAL
361377
elseif flag == ECOS_PINF + ECOS_INACC_OFFSET
362378
return MOI.ALMOST_INFEASIBLE
363-
else
364-
@assert flag == ECOS_DINF + ECOS_INACC_OFFSET
379+
elseif flag == ECOS_DINF + ECOS_INACC_OFFSET
365380
return MOI.ALMOST_DUAL_INFEASIBLE
381+
else
382+
@assert flag == _ECOS_INVALID_MODEL
383+
return MOI.INVALID_MODEL
366384
end
367385
end
368386

@@ -395,6 +413,10 @@ function MOI.get(optimizer::Optimizer, attr::MOI.PrimalStatus)
395413
return MOI.INFEASIBLE_POINT
396414
elseif flag == ECOS_DINF + ECOS_INACC_OFFSET
397415
return MOI.NEARLY_INFEASIBILITY_CERTIFICATE
416+
elseif flag == ECOS_FATAL
417+
return MOI.NO_SOLUTION
418+
elseif flag == _ECOS_INVALID_MODEL
419+
return MOI.NO_SOLUTION
398420
else
399421
return MOI.OTHER_RESULT_STATUS
400422
end
@@ -446,6 +468,10 @@ function MOI.get(optimizer::Optimizer, attr::MOI.DualStatus)
446468
return MOI.NEARLY_INFEASIBILITY_CERTIFICATE
447469
elseif flag == ECOS_DINF + ECOS_INACC_OFFSET
448470
return MOI.INFEASIBLE_POINT
471+
elseif flag == ECOS_FATAL
472+
return MOI.NO_SOLUTION
473+
elseif flag == _ECOS_INVALID_MODEL
474+
return MOI.NO_SOLUTION
449475
end
450476
return MOI.OTHER_RESULT_STATUS
451477
end

test/MOI_wrapper.jl

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,31 @@ function test_iteration_limit()
9191
return
9292
end
9393

94+
function test_empty_problem()
95+
model = MOI.Utilities.Model{Float64}()
96+
ecos = ECOS.Optimizer()
97+
MOI.optimize!(ecos, model)
98+
@test MOI.get(ecos, MOI.TerminationStatus()) == MOI.INVALID_MODEL
99+
@test MOI.get(ecos, MOI.PrimalStatus()) == MOI.NO_SOLUTION
100+
@test MOI.get(ecos, MOI.DualStatus()) == MOI.NO_SOLUTION
101+
return
102+
end
103+
104+
function test_conic_no_variables()
105+
model = MOI.Utilities.Model{Float64}()
106+
ecos = ECOS.Optimizer()
107+
f = MOI.VectorAffineFunction(
108+
MOI.VectorAffineTerm{Float64}[],
109+
[1.0, 0.5, 0.5],
110+
)
111+
MOI.add_constraint(model, f, MOI.SecondOrderCone(3))
112+
MOI.optimize!(ecos, model)
113+
@test MOI.get(ecos, MOI.TerminationStatus()) == MOI.INVALID_MODEL
114+
@test MOI.get(ecos, MOI.PrimalStatus()) == MOI.NO_SOLUTION
115+
@test MOI.get(ecos, MOI.DualStatus()) == MOI.NO_SOLUTION
116+
return
117+
end
118+
94119
end # module
95120

96121
TestECOS.runtests()

0 commit comments

Comments
 (0)