Skip to content

Aggregate implications - #3264

Open
fwesselm wants to merge 30 commits into
latestfrom
aggregatedImplications
Open

Aggregate implications#3264
fwesselm wants to merge 30 commits into
latestfrom
aggregatedImplications

Conversation

@fwesselm

@fwesselm fwesselm commented Sep 10, 2026

Copy link
Copy Markdown
Collaborator

Description

This PR adds aggregations for implied bounds (implications) as described by Chen et al., Exploiting Variable Implications in Presolve for Mixed Integer Programming.

Note that the current code does not consider cliques, i.e. "implications" between binary variables.

Unfortunately, the effect on performance is relatively small (ratios of shifted geometric means are close to 1.0). However, the models gfd-schedulen180f7d50m30k18 and neos-4763324-toguru (where 50% of the rows are eliminated) can be solved to optimality within a time limit of two hours with the new technique.

I added unit tests for the new technique.

Note that the paper also describes "implication aware" constraint propagation, which I will investigate next.

Checklist

  • I have read the contributing guidelines
  • This PR targets the latest branch
  • Tests are passing
  • Documentation was updated where relevant
  • This PR is not primarily AI-generated (per the AI contributions policy in CONTRIBUTING.md)

@fwesselm
fwesselm requested a review from Opt-Mucca September 10, 2026 11:46
@codecov

codecov Bot commented Sep 10, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 96.41944% with 14 lines in your changes missing coverage. Please review.
✅ Project coverage is 73.43%. Comparing base (a2b94fa) to head (b5f97b2).
⚠️ Report is 36 commits behind head on latest.

Files with missing lines Patch % Lines
highs/mip/HighsCliqueTable.cpp 79.59% 10 Missing ⚠️
check/TestPresolveRules.cpp 98.46% 2 Missing ⚠️
highs/presolve/HPresolve.cpp 98.44% 2 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##           latest    #3264      +/-   ##
==========================================
+ Coverage   73.29%   73.43%   +0.13%     
==========================================
  Files         446      446              
  Lines      108244   108549     +305     
  Branches    17352    17395      +43     
==========================================
+ Hits        79342    79711     +369     
+ Misses      28626    28562      -64     
  Partials      276      276              

☔ 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.

@Opt-Mucca Opt-Mucca left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

@fwesselm I've got one C++ question and one potential correctness error that I believe is a one line fix. The rest looks good!

Comment thread highs/mip/HighsCliqueTable.cpp
HighsInt row = -1;
for (const auto& var : clique) {
const auto* bounds = boundsMap.find(var.col);
HighsInt currentrow = bounds->originalBound.origin;

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

I think there needs to be a check here that currentrow is still single sided.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

@Opt-Mucca, currently, the code only stores origin with a VLB/VUB if the source row is not ranged:

   // only record origin for size-2 one-sided rows that can be safely rewritten
    HighsInt origin = rowsize[row] == 2 && !isRanged(row) ? row : -1;

Therefore, all rows will be one-sided in this loop.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Can't the source row get updated to become double-sided though, e.g., parallel row merging? Or all origins invalidated by such a solution path?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

@Opt-Mucca, any modification made to the row (via addToMatrix) will reset the origin. I will have a closer look and double-check.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Helloooo @Opt-Mucca! Looks like there are a couple of cases where just the row side(s) are manipulated in presolve, which should also trigger a reset of the origin. Also, I noticed that dual row bounds are not updated in these cases, so there is more to investigate. Hoooooray!

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

I was also completely missing the case where the RHS value changes.....

@jajhall jajhall added Enhancement New feature or request MIP labels Sep 11, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Enhancement New feature or request MIP

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants