Skip to content

Commit 2d8af43

Browse files
authored
Fix TerminationStatus (#114)
* Fix TerminationStatus * Add test * Use nothing instead of a constant
1 parent 8898ce3 commit 2d8af43

File tree

2 files changed

+43
-7
lines changed

2 files changed

+43
-7
lines changed

src/MOI_wrapper.jl

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ const VI = MOI.VariableIndex
66
const MOIU = MOI.Utilities
77

88
struct Solution
9-
ret_val::Int
9+
ret_val::Union{Nothing, Int}
1010
primal::Vector{Float64}
1111
dual_eq::Vector{Float64}
1212
dual_ineq::Vector{Float64}
@@ -16,8 +16,8 @@ struct Solution
1616
objective_constant::Float64
1717
solve_time::Float64
1818
end
19-
const OPTIMIZE_NOT_CALLED = -1
20-
Solution() = Solution(OPTIMIZE_NOT_CALLED, Float64[], Float64[], Float64[],
19+
# The values used by ECOS are from -7 to 10 so -10 should be safe
20+
Solution() = Solution(nothing, Float64[], Float64[], Float64[],
2121
Float64[], NaN, NaN, NaN, NaN)
2222

2323
# Used to build the data with allocate-load during `copy_to`.
@@ -287,7 +287,7 @@ MOI.get(optimizer::Optimizer, ::MOI.SolveTime) = optimizer.sol.solve_time
287287
function MOI.get(optimizer::Optimizer, ::MOI.RawStatusString)
288288
# Strings from https://github.com/ifa-ethz/ecos/blob/master/include/ecos.h
289289
flag = optimizer.sol.ret_val
290-
if flag == OPTIMIZE_NOT_CALLED
290+
if flag === nothing
291291
return "Optimize not called"
292292
elseif flag == ECOS_OPTIMAL
293293
return "Problem solved to optimality"
@@ -318,7 +318,7 @@ end
318318
# Implements getter for result value and statuses
319319
function MOI.get(optimizer::Optimizer, ::MOI.TerminationStatus)
320320
flag = optimizer.sol.ret_val
321-
if flag == OPTIMIZE_NOT_CALLED
321+
if flag === nothing
322322
return MOI.OPTIMIZE_NOT_CALLED
323323
elseif flag == ECOS.ECOS_OPTIMAL
324324
return MOI.OPTIMAL
@@ -327,15 +327,21 @@ function MOI.get(optimizer::Optimizer, ::MOI.TerminationStatus)
327327
elseif flag == ECOS.ECOS_DINF
328328
return MOI.DUAL_INFEASIBLE
329329
elseif flag == ECOS.ECOS_MAXIT
330-
return MOI.IterationLimit
330+
return MOI.ITERATION_LIMIT
331+
elseif flag == ECOS.ECOS_NUMERICS || flag == ECOS.ECOS_OUTCONE
332+
return MOI.NUMERICAL_ERROR
333+
elseif flag == ECOS.ECOS_SIGINT
334+
return MOI.INTERRUPTED
335+
elseif flag == ECOS.ECOS_FATAL
336+
return MOI.OTHER_ERROR
331337
elseif flag == ECOS.ECOS_OPTIMAL + ECOS.ECOS_INACC_OFFSET
332338
return MOI.ALMOST_OPTIMAL
333339
elseif flag == ECOS.ECOS_PINF + ECOS.ECOS_INACC_OFFSET
334340
return MOI.ALMOST_INFEASIBLE
335341
elseif flag == ECOS.ECOS_DINF + ECOS.ECOS_INACC_OFFSET
336342
return MOI.ALMOST_DUAL_INFEASIBLE
337343
else
338-
return MOI.OTHER_ERROR
344+
error("Unrecognized ECOS solve status flag: $flag.")
339345
end
340346
end
341347

test/MOI_wrapper.jl

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,3 +68,33 @@ end
6868
@test MOI.get(model, MOI.RawParameter(:abstol)) 2e-5
6969
@test MOI.get(model, MOI.RawParameter("abstol")) == 2e-5
7070
end
71+
72+
@testset "Iteration Limit" begin
73+
# Problem data
74+
v = [5.0, 3.0, 1.0]
75+
w = [2.0, 1.5, 0.3]
76+
77+
MOI.empty!(bridged)
78+
79+
MOI.set(bridged, MOI.RawParameter("maxit"), 1)
80+
MOI.set(bridged, MOI.Silent(), true)
81+
82+
x = MOI.add_variables(bridged, 3)
83+
for xj in x
84+
MOI.add_constraint(bridged, MOI.SingleVariable(xj), MOI.Interval(0.0, 1.0))
85+
end
86+
87+
# Constraint
88+
MOI.add_constraint(bridged, MOI.ScalarAffineFunction(MOI.ScalarAffineTerm.(w, x), 0.0), MOI.LessThan(3.0))
89+
90+
# Set the objective
91+
MOI.set(bridged,
92+
MOI.ObjectiveFunction{MOI.ScalarAffineFunction{Float64}}(),
93+
MOI.ScalarAffineFunction(MOI.ScalarAffineTerm.(v, x), 0.0)
94+
)
95+
MOI.set(bridged, MOI.ObjectiveSense(), MOI.MAX_SENSE)
96+
97+
MOI.optimize!(bridged)
98+
99+
@test MOI.get(bridged, MOI.TerminationStatus()) == MOI.ITERATION_LIMIT
100+
end

0 commit comments

Comments
 (0)