Skip to content

Commit

Permalink
Fix getting infeasible primal/dual solutions (#216)
Browse files Browse the repository at this point in the history
  • Loading branch information
odow authored Jun 19, 2024
1 parent 5459398 commit 157b89d
Show file tree
Hide file tree
Showing 2 changed files with 53 additions and 22 deletions.
34 changes: 15 additions & 19 deletions src/MOI_wrapper.jl
Original file line number Diff line number Diff line change
Expand Up @@ -1857,25 +1857,21 @@ function _store_solution(model::Optimizer, ret::HighsInt)
ret = Highs_getPrimalRay(model, statusP, x.colvalue)
# Don't `_check_ret(ret)` here, just bail is there isn't a dual ray.
x.has_primal_ray = (ret == kHighsStatusOk) && (statusP[] == 1)
else
Highs_getIntInfoValue(model, "primal_solution_status", statusP)
x.primal_solution_status = statusP[]
Highs_getIntInfoValue(model, "dual_solution_status", statusP)
x.dual_solution_status = statusP[]
if x.primal_solution_status != kHighsSolutionStatusNone
Highs_getSolution(
model,
x.colvalue,
x.coldual,
x.rowvalue,
x.rowdual,
)
if model.hessian === nothing
# No basis is present in a QP.
resize!(x.colstatus, numCols)
resize!(x.rowstatus, numRows)
Highs_getBasis(model, x.colstatus, x.rowstatus)
end
end
if x.has_dual_ray || x.has_primal_ray
return # If a ray is present, we don't query the solution
end
Highs_getIntInfoValue(model, "primal_solution_status", statusP)
x.primal_solution_status = statusP[]
Highs_getIntInfoValue(model, "dual_solution_status", statusP)
x.dual_solution_status = statusP[]
if x.primal_solution_status != kHighsSolutionStatusNone
Highs_getSolution(model, x.colvalue, x.coldual, x.rowvalue, x.rowdual)
if model.hessian === nothing
# No basis is present in a QP.
resize!(x.colstatus, numCols)
resize!(x.rowstatus, numRows)
Highs_getBasis(model, x.colstatus, x.rowstatus)
end
end
return
Expand Down
41 changes: 38 additions & 3 deletions test/MOI_wrapper.jl
Original file line number Diff line number Diff line change
Expand Up @@ -88,10 +88,13 @@ function test_runtests_ipm_no_presolve()
MOI.Test.runtests(
model,
MOI.Test.Config(),
exclude = String[
exclude = [
# Termination status is OTHER_ERROR
"test_conic_linear_INFEASIBLE",
"test_conic_linear_INFEASIBLE_2",
r"^test_conic_linear_INFEASIBLE$",
r"^test_conic_linear_INFEASIBLE_2$",
# See https://github.com/ERGO-Code/HiGHS/issues/1807
r"^test_conic_NormInfinityCone_INFEASIBLE$",
r"^test_conic_NormOneCone_INFEASIBLE$",
_EXPLICIT_METHOD_FAILURES...,
],
)
Expand Down Expand Up @@ -871,6 +874,7 @@ end

function test_nonbasic_equality_constraint()
model = HiGHS.Optimizer()
MOI.set(model, MOI.Silent(), true)
x = MOI.add_variable(model)
ci = MOI.add_constraint(model, 1.0 * x, MOI.EqualTo(1.0))
MOI.optimize!(model)
Expand All @@ -880,12 +884,43 @@ end

function test_variable_basis_status_zero()
model = HiGHS.Optimizer()
MOI.set(model, MOI.Silent(), true)
x = MOI.add_variable(model)
MOI.optimize!(model)
@test MOI.get(model, MOI.VariableBasisStatus(), x) == MOI.NONBASIC
return
end

function test_optimize_errored()
model = HiGHS.Optimizer()
MOI.set(model, MOI.Silent(), true)
x = MOI.add_variable(model)
MOI.set(model, MOI.NumberOfThreads(), 123_456)
MOI.optimize!(model)
@test MOI.get(model, MOI.TerminationStatus()) == MOI.OTHER_ERROR
@test MOI.get(model, MOI.RawStatusString()) ==
"There was an error calling optimize!"
return
end

function test_infeasible_point()
model = HiGHS.Optimizer()
MOI.set(model, MOI.Silent(), true)
x = MOI.add_variables(model, 2)
MOI.add_constraint.(model, x, MOI.GreaterThan(0.0))
ci = MOI.add_constraint(model, x[1] + 2.0 * x[2], MOI.LessThan(-1.0))
MOI.set(model, MOI.RawOptimizerAttribute("presolve"), "off")
MOI.set(model, MOI.RawOptimizerAttribute("solver"), "ipm")
MOI.optimize!(model)
@test MOI.get(model, MOI.TerminationStatus()) == MOI.INFEASIBLE
@test MOI.get(model, MOI.PrimalStatus()) == MOI.INFEASIBLE_POINT
@test MOI.get(model, MOI.DualStatus()) == MOI.INFEASIBLE_POINT
@test MOI.get(model, MOI.ResultCount()) == 1
@test MOI.get(model, MOI.VariablePrimal(), x) isa Vector{Float64}
@test MOI.get(model, MOI.ConstraintDual(), ci) isa Float64
return
end

end # module

TestMOIHighs.runtests()

0 comments on commit 157b89d

Please sign in to comment.