scipopt / scip

SCIP - Solving Constraint Integer Programs
Other
366 stars 63 forks source link

Changing variable bounds during reoptimization #95

Open cdanielmachado opened 3 days ago

cdanielmachado commented 3 days ago

I am trying to solve an LP problem multiple times, where both the objective coefficients and the bounds of the variables may get modified between iterations. Something of the form:

for iteration i in {1,2,3... }:

solve:
    max c(i) * x
    where
        A * x = b
        lb(i) < x < ub(i)

I start with enableReoptimization() before populating the model with variables and constraints. After solving the problem in each iteration, I free the problem with freeReoptSolve(), and then modify the objective coefficients and the variable bounds.

Changing the objective coefficients is successful, however something strange happens with the variable bounds. I am able to change them (if I retrieve the bounds from the variables, i see they have been updated), but the model is still solved with the original values (and if I write the problem to a file, I see that the old values are still there).

1) Is this an issue or is it expected behavior?

2) How can I (properly) modify variable bounds using re-optimization?

cdanielmachado commented 3 days ago

Small correction to what i said above: changing the bounds after freeReoptSolve() (stage moves to PRESOLVED) updates the "global" bounds but not "local" or "original".

This is likely a result of this:

    switch( scip->set->stage )
    {
    case SCIP_STAGE_PROBLEM:
       assert(!SCIPvarIsTransformed(var));
       SCIP_CALL( SCIPvarChgLbGlobal(var, scip->mem->probmem, scip->set, scip->stat, scip->lp,
             scip->branchcand, scip->eventqueue, scip->cliquetable, newbound) );
       SCIP_CALL( SCIPvarChgLbLocal(var, scip->mem->probmem, scip->set, scip->stat, scip->lp,
             scip->branchcand, scip->eventqueue, newbound) );
       SCIP_CALL( SCIPvarChgLbOriginal(var, scip->set, newbound) );
       break;

    case SCIP_STAGE_TRANSFORMING:
    case SCIP_STAGE_PRESOLVED:
       SCIP_CALL( SCIPvarChgLbGlobal(var, scip->mem->probmem, scip->set, scip->stat, scip->lp,
             scip->branchcand, scip->eventqueue, scip->cliquetable, newbound) );
       break;

And somehow changing only the global bounds does not affect the next optimization, since they are somehow ignored.

According to the documentation https://www.scipopt.org/doc-8.0.3/html/REOPT.php it should be possible to change variable bounds between P(i) and P(i+1)...

svigerske commented 3 days ago

It is not related directly to the issue raised here, but I doubt that the reoptimization feature of SCIP is useful to solve a sequence of similar LPs. For LPs, you would want that at least the basis solution of one solve is somehow used as a starting point for the next solve. However, that won't happen here. SCIP's reoptimization is for solving a sequence of MIPs (with changing objective or shrinking feasible region) and focuses on reusing some information from the branch-and-bound tree of one solve for the next one. When solving LPs with SCIP, there is no branch-and-bound.

You may want to look into using LP solvers directly instead, e.g., SoPlex.

cdanielmachado commented 2 days ago

Thanks for the clarification. Although my code is mostly meant to solve LPs, I sometimes need to solve MILPs, and would like to keep the code generic enough to cover both cases.

It's ok with me if there is no advantage of reoptimization for LPs. I mostly want to avoid the time overhead of re-creating the whole problem object in memory when I need to solve thousands of variations of the same problem.

In theory, using freeProblem() instead of freeReOptSolve() to discard all information after solving should be enough for I want to do. But this is not working either. It brings the problem back to stage PROBLEM, but refuses to be solved a second time (throws an error if solve() is called again).

On Fri, 5 Jul 2024, 17:39 Stefan Vigerske, @.***> wrote:

It is not related directly to the issue raised here, but I doubt that the reoptimization feature of SCIP is useful to solve a sequence of similar LPs. For LPs, you would want that at least the basis solution of one solve is somehow used as a starting point for the next solve. However, that won't happen here. SCIP's reoptimization is for solving a sequence of MIPs (with changing objective or shrinking feasible region) and focuses on reusing some information from the branch-and-bound tree of one solve for the next one. When solving LPs with SCIP, there is no branch-and-bound.

You may want to look into using LP solvers directly instead, e.g., SoPlex https://soplex.zib.de/.

— Reply to this email directly, view it on GitHub https://github.com/scipopt/scip/issues/95#issuecomment-2211083985, or unsubscribe https://github.com/notifications/unsubscribe-auth/AATX4VLLZ5DO6I5G5QMMLIDZK24ZTAVCNFSM6AAAAABKNAUP2GVHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMZDEMJRGA4DGOJYGU . You are receiving this because you authored the thread.Message ID: @.***>

svigerske commented 7 hours ago

It should not throw an error when solved again from PROBLEM stage. Can you include more information on this error?

cdanielmachado commented 6 hours ago

Sure, here is what happens if I try to solve a second time (by the way, I'm using PySCIPOpt API, but i don't think it is a problem with the python API):

Screen Shot 2024-07-08 at 15 02 02