Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Separate presolve routines for LP / MIP? #17

Open
mtanneau opened this issue Jan 11, 2021 · 3 comments
Open

Separate presolve routines for LP / MIP? #17

mtanneau opened this issue Jan 11, 2021 · 3 comments

Comments

@mtanneau
Copy link
Owner

mtanneau commented Jan 11, 2021

The question of how MIP reductions (resp. LP reductions) should handle continuous (resp integer) variables has come up a few times now.

It might make sense to fully separate LP reductions from MIP reductions (incidentally, we already have src/lp and src/mip), at least for now.
We can still have a "meta-main" presolve! function that would check whether a problem is LP/MIP and call the appropriate LP/MIP-specific "main" presolve. Data structures like ProblemData and style conventions can also be shared.

Pros:

  • No need to ensure that each reduction handles LP/MIP models satisfactorily
  • MIP presolve can completely ignore dual reductions & dual presolve
  • Future MIP-specific data structures (e.g. clique tables) can be added directly

Cons:

  • We'll inevitably end up with some duplicate code

@joehuchette what do you think?

@joehuchette
Copy link
Collaborator

I think that this would be OK. I'm a bit concerned that it does not mesh well with user configuration: what if I want to run presolve that mixes together LP and MIP presolve routines? But, I'm not sure this is something anyone would realistically want to do. I guess worst case, someone could write their own presolve loop using the apply! interface.

How different would the two main functions be?

@mtanneau
Copy link
Owner Author

what if I want to run presolve that mixes together LP and MIP presolve routines?

At first, I guess the simplest would be to duplicate such routines. There aren't that many though, and they are not very complicated.
In the longer term, we can always merge the implementations where applicable.

How different would the two main functions be?

Likely very similar.
In everything I've seen so far, "quick and easy" reductions are run in an inner-most loop, and costlier reductions in an outer loop, with work limits on how many passes should be done.
Scaling usually happens last, though it's not a requirement. For instance, you'd likely want to re-scale MIP constraints on the fly, in order to have only integer coefficients. Doing so simplifies rounding, detection of implied-integers, etc.

The two can be wrapped as follows

function apply!(ps, ::GenericPresolve, config)
    if ps.pb0.is_continuous
        apply!(ps, LPPresolve(), config)
    else
        apply!(ps, MIPPresolve(), config)
    end
    return nothing
end

@joehuchette
Copy link
Collaborator

I guess this also makes it easier to eventually add QP support. This design seems fine by me. I would like to avoid duplicating the actual reductions, but having two slightly different top-level presolve reductions is fine.

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

No branches or pull requests

2 participants