Skip to content

HiGHS status kSolutionLimit is not handled #3632

@rschwarz

Description

@rschwarz

Summary

When solving MIP problems with HiGHS and some active solver limits, eg, mip_max_nodes=50, the solver may stop prematurely, ie, before solving the problem to optimality. In that case, the status given by HiGHS is kSolutionLimit. But this is not handled in the if/else chain here:

if status == highspy.HighsModelStatus.kNotset:
results.termination_condition = TerminationCondition.unknown
elif status == highspy.HighsModelStatus.kLoadError:
results.termination_condition = TerminationCondition.error
elif status == highspy.HighsModelStatus.kModelError:
results.termination_condition = TerminationCondition.error
elif status == highspy.HighsModelStatus.kPresolveError:
results.termination_condition = TerminationCondition.error
elif status == highspy.HighsModelStatus.kSolveError:
results.termination_condition = TerminationCondition.error
elif status == highspy.HighsModelStatus.kPostsolveError:
results.termination_condition = TerminationCondition.error
elif status == highspy.HighsModelStatus.kModelEmpty:
results.termination_condition = TerminationCondition.unknown
elif status == highspy.HighsModelStatus.kOptimal:
results.termination_condition = TerminationCondition.optimal
elif status == highspy.HighsModelStatus.kInfeasible:
results.termination_condition = TerminationCondition.infeasible
elif status == highspy.HighsModelStatus.kUnboundedOrInfeasible:
results.termination_condition = TerminationCondition.infeasibleOrUnbounded
elif status == highspy.HighsModelStatus.kUnbounded:
results.termination_condition = TerminationCondition.unbounded
elif status == highspy.HighsModelStatus.kObjectiveBound:
results.termination_condition = TerminationCondition.objectiveLimit
elif status == highspy.HighsModelStatus.kObjectiveTarget:
results.termination_condition = TerminationCondition.objectiveLimit
elif status == highspy.HighsModelStatus.kTimeLimit:
results.termination_condition = TerminationCondition.maxTimeLimit
elif status == highspy.HighsModelStatus.kIterationLimit:
results.termination_condition = TerminationCondition.maxIterations
elif status == highspy.HighsModelStatus.kUnknown:
results.termination_condition = TerminationCondition.unknown
else:
results.termination_condition = TerminationCondition.unknown

Hence, the Pyomo user just gets the result.solver:

- Status: unknown
  Termination condition: unknown
  Termination message: TerminationCondition.unknown

Even though, looking at the solver log, we know quite a bit more, eg, that a feasible solution exists:

Solving report
  Status            Solution limit reached
  Primal bound      153.831642438
  Dual bound        154.134587306
  Gap               0.197% (tolerance: 0.01%)
  P-D integral      0.020659109043
  Solution status   feasible
                    153.831642438 (objective)
                    0 (bound viol.)
                    0 (int. viol.)
                    0 (row viol.)
  Timing            0.17 (total)
                    0.00 (presolve)
                    0.00 (solve)
                    0.00 (postsolve)
  Max sub-MIP depth 3
  Nodes             1

Steps to reproduce the issue

I can provide code to generate tricky Knapsack instances, if needed.

The important bit is to use options=dict(mip_max_nodes=1) or similar.

Information on your system

Pyomo version: 6.7.3 (but the relevant code is still the same on main branch)
Python version: 3.12.
Operating system: Ubuntu 24.04
How Pyomo was installed (PyPI, conda, source): PyPI
Solver (if applicable): HiGHS v1.11.0

Additional information

I'm happy to have a go at this in a PR, but might not get to it immediately.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions