Skip to content

APPSI HiGHS: support partial MIP warm starts - #4046

Open
adbuerger wants to merge 2 commits into
Pyomo:mainfrom
adbuerger:appsi-highs-partial-mip-warm-starts
Open

adbuerger wants to merge 2 commits into
Pyomo:mainfrom
adbuerger:appsi-highs-partial-mip-warm-starts

Conversation

@adbuerger

Copy link
Copy Markdown

Fixes

Part 1 of #4044

Summary/Motivation:

appsi_highs builds the MIP start vector with np.zeros, so every variable without a value is passed to HiGHS as 0. That turns a partial start into a complete assignment, which can easily be infeasible and get rejected. HiGHS has supported partial starts since 1.8: entries set to kHighsUndefined are left free, and HiGHS completes the start by solving a sub-MIP over the unset discrete variables.

Changes proposed in this PR:

  • Initialise the warm-start vector in Highs._warm_start with highspy.kHighsUndefined instead of 0. On highspy < 1.11, which does not export the constant, it falls back to 0.0 (the current behaviour).
  • Add test_partial_warm_start: a small MIP where the unset binary has to be 1 for the start to be feasible. With the change, HiGHS reports the completed start as feasible. Without it, the zero-filled start is rejected. The test is skipped on highspy < 1.11 (via a check for the existence of the kHighsUndefined attribute).

AI-Use Disclosure

  • AI tools were NOT used during the preparation of this PR

or

  • AI tools contributed to the development of this PR

    • AI tools generated documentation (including the PR description/comments, code comments, and/or Sphinx documentation)
    • AI tools generated tests (baselines, examples, and/or code)
    • AI tools generated code (apart from tests)

    Review process (select ONE):

    • Rewritten: All AI-generated content was rewritten by me before being committed.
    • Reviewed/verified: I retained AI-generated content and verified it before committing. Verification included (as applicable):
      • Ran the code and fixed issues
      • Added and ran tests
      • Checked correctness/logic of code and tests
      • Checked for alignment with the contribution guide
      • Considered security implications
    • As-is: AI-generated content was commited directly to the repository

Notes for reviewers (optional):

The new test reuses the model from test_warm_start and adds one constraint, x1 <= 3 + 7 * x3, so that with x1 = 4 the unset binary must be 1. Without the fix, x3 is passed as 0, the start is infeasible and gets rejected. The test only checks for MIP start solution is feasible and leaves out the objective value, because that value depends on how HiGHS completes the partial start. C5 is deliberately loose for x3 = 1: with a tighter version such as x1 <= 3 + x3, HiGHS presolve solves the model before the start is evaluated, and the log line never appears. I verified the test with highspy 1.15.1 only.

Legal Acknowledgement

By contributing to this software project, I have read the contribution guide and agree to the following terms and conditions for my contribution:

  1. I agree my contributions are submitted under the BSD license.
  2. I represent I am authorized to make the contributions and grant the license. If my employer has rights to intellectual property that includes these contributions, I represent that I have received permission to make contributions and grant the required license on behalf of that employer.

Pass unset variables to HiGHS as kHighsUndefined instead of 0, so HiGHS
can complete a partial start rather than rejecting it, and add a test.

@jsiirola jsiirola left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks really good. I have one nit-picky question around how the test is guarded, but otherwise this looks good.

Comment on lines +186 to +189
@unittest.skipUnless(
hasattr(highspy, "kHighsUndefined"),
"Partial MIP starts require highspy>=1.11 (kHighsUndefined)",
)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Style question: should this guard be based on the existence of the attribute or based on the HiGHS version? My only concerns with looking for the attribute are:

  • "assume we mistyped the attribute - it would never be found and the test would never be run - and we would never know because it wouldn't show up on the coverage (because we only look for line coverage and not branch coverage).
  • we would not see if a new HiGHS release removed / renamed that attribute, because we would just silently stop testing the code.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you, good point. I chose this approach because I wanted to make sure the test is run whenever the attribute is available, which I deemed more robust than checking the version, but I think your argument is stronger. I will adapt this.

@codecov

codecov Bot commented Oct 1, 2026 •

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 90.14%. Comparing base (170f653) to head (eb4d375).
⚠️ Report is 8 commits behind head on main.

Additional details and impacted files
@@            Coverage Diff             @@
##             main    #4046      +/-   ##
==========================================
+ Coverage   89.96%   90.14%   +0.17%     
==========================================
  Files         917      917              
  Lines      109282   109282              
==========================================
+ Hits        98311    98507     +196     
+ Misses      10971    10775     -196     
Flag Coverage Δ
builders 29.12% <0.00%> (+<0.01%) ⬆️
default 86.14% <100.00%> (?)
expensive 35.09% <0.00%> (?)
linux 87.67% <100.00%> (-1.80%) ⬇️
linux_other 87.67% <100.00%> (+0.17%) ⬆️
oldsolvers 28.01% <0.00%> (ø)
osx 83.12% <100.00%> (ø)
win 85.44% <100.00%> (+<0.01%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants