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

Cannot add solution when using addConsIndicator #717

Open
skyu0221 opened this issue Aug 8, 2023 · 7 comments
Open

Cannot add solution when using addConsIndicator #717

skyu0221 opened this issue Aug 8, 2023 · 7 comments
Labels

Comments

@skyu0221
Copy link

skyu0221 commented Aug 8, 2023

It might be my implementation error, but whenever I have indicator constraints, the constraints seem always needs to be satisfied regardless of the value of the binary variable. Minimum example:

from pyscipopt import Model

if __name__ == "__main__":
    m = Model()
    control = m.addVar(vtype='B')
    v = m.addVar(vtype='C', lb=1, ub=3)
    m.addConsIndicator(v <= 2, control)

    m.setObjective(v, "maximize")

    sol = m.createSol(None)
    m.setSolVal(sol, v, 3)
    m.setSolVal(sol, control, 0)
    m.addSol(sol)
    m.optimize()

    sol = m.getBestSol()
    print(sol[v])
    print(sol[control])
@Joao-Dionisio
Copy link
Collaborator

Good afternoon, @skyu0221! Thank you for your organized issue!

I think the problem here is a different one. Look at the beginning of the solving process:

image

PySCIPOpt is saying that the provided solution is infeasible, so it disregards it. The same thing happens if you set control to 1. Sorry for not helping more, I am a bit busy, I will try looking into it more tomorrow.

@skyu0221
Copy link
Author

skyu0221 commented Aug 8, 2023

Hi @Joao-Dionisio ,

Thanks for replying! Yes, that is basically my question about using an indicator constraint. As you can see, the optimal solution should be v = 3 and control = 0, which I cannot add manually.

If I'm not misunderstanding the concept, I assume if control = 1, then the constraint v <= 2 must hold (https://www.scipopt.org/doc/html/cons__indicator_8c.php). But is it valid to say if I set control = 0, then SCIP can ignore the constraint automatically? Or do I have to do something with the slack variable added by the indicator constraint to make my solution feasible?

@Joao-Dionisio
Copy link
Collaborator

Hello @skyu0221, sorry for the delay. This is indeed a bit puzzling. It's not that SCIP cannot arrive at the optimal solution. At least on my end, he correctly arrives at the solution v = 3, control = 0.

image

And the constraint seems to be activated correctly.

image

But, as you say, SCIP claims that the optimal solution is infeasible, if added manually, even though it arrives at the exact same solution.

image

Trying to add the solution v = 2, control = 1 doesn't get us any problems. I don't know what's going on here, but at least it seems that the optimization process runs smoothly, it's the adding the solution part that's not correct.

@abb-omidi
Copy link

Dear @Joao-Dionisio,

As the question is interesting to me, let me add some points that may be useful.
I think the strange behavior is back to the point that the logical constraint is basically redundant. Now, if you comment the constraint the result would be:

SCIP version 8.0.4 [precision: 8 byte] [memory: block] [mode: optimized] [LP solver: Soplex 6.0.4] [GitHash: a8e51afd1e]
Copyright (c) 2002-2023 Zuse Institute Berlin (ZIB)
presolving:
   (0.0s) symmetry computation started: requiring (bin +, int +, cont +), (fixed: bin -, int -, cont -)
   (0.0s) no symmetry present
presolving (0 rounds: 0 fast, 0 medium, 0 exhaustive):
 0 deleted vars, 0 deleted constraints, 0 added constraints, 0 tightened bounds, 0 added holes, 0 changed sides, 0 changed coefficients
 0 implications, 0 cliques
presolved problem has 2 variables (1 bin, 0 int, 0 impl, 1 cont) and 0 constraints
Presolving Time: 0.00

 time | node  | left  |LP iter|LP it/n|mem/heur|mdpt |vars |cons |rows |cuts |sepa|confs|strbr|  dualbound   | primalbound  |  gap   | compl. 
* 0.0s|     1 |     0 |     0 |     - |    LP  |   0 |   2 |   0 |   0 |   0 |  0 |   0 |   0 | 3.000000e+00 | 3.000000e+00 |   0.00%| unknown
  0.0s|     1 |     0 |     0 |     - |   569k |   0 |   2 |   0 |   0 |   0 |  0 |   0 |   0 | 3.000000e+00 | 3.000000e+00 |   0.00%| unknown

SCIP Status        : problem is solved [optimal solution found]
Solving Time (sec) : 0.01
Solving Nodes      : 1
Primal Bound       : +3.00000000000000e+00 (1 solutions)
Dual Bound         : +3.00000000000000e+00
Gap                : 0.00 %

The logical expression can be translated into the linear one as follows:

$$v \leq 2 + M*(1-control) \quad (1)$$

By assuming the control equals 1 the solution would be v=2 and control=1.

Also, if you write the problem in the .cip format, you can see the following details: (these details cannot be seen in other formats like .lp or .mps)

STATISTICS
  Problem name     : model
  Variables        : 3 (1 binary, 0 integer, 0 implicit integer, 2 continuous)
  Constraints      : 2 initial, 2 maximal
OBJECTIVE
  Sense            : maximize
VARIABLES
  [binary] <x1>: obj=0, original bounds=[0,1]
  [continuous] <x2>: obj=1, original bounds=[1,3]
  [continuous] <indslack_IndicatorCons>: obj=0, original bounds=[0,+inf]
CONSTRAINTS
  [linear] <indlin_IndicatorCons>:  -<indslack_IndicatorCons>[C] +<x2>[C] <= 2;
  [indicator] <IndicatorCons>: <x1> = 1 -> <indslack_IndicatorCons> = 0 (<indlin_IndicatorCons>);
END

The first constraint is the same as what is mentioned in the SCIP host and is equal to:

$$v - slack \leq 2$$

The second is equivalent to:
$$\text{IF:} \quad (control = 1) \implies (slack = 0)$$

It derives the following linear inequalities:

$$slack \geq 0 - m*(1-control) \quad (2)$$

$$slack \leq 0 + M*(1-control) \quad (3)$$

Now, based on the latest two constraints, if control is equal to 1 then slack is equal to 0 and the original constraint is valid. But if we set v to 3 and control to 0 as an initial start, slack can be valued on $+INF$ and causes some violation on the $RHS$. This is why when you are trying to add the solution v = 2, control = 1 it doesn't get us any problems.

Regards
Abbas

@Joao-Dionisio
Copy link
Collaborator

Joao-Dionisio commented Aug 17, 2023

Thank you for the help, @abb-omidi!

But I don't understand your conclusion. If control is 0, then slack can take a value in [0,M]. The "worst" possible case (slack = M) simply gives us v <= 2 + M. But we also have a bound constraint on the variable itself, and so the constraint simplifies to v <= 3. I don't understand why this should cause problems.

@abb-omidi
Copy link

Dear @Joao-Dionisio,

I am actually not sure how the SCIP can deal with the slack variable internally. There are two things that may come:

  1. As the constraint is basically redundant, SCIP may remove this slack variable in the solving process. By that, the predefined solution causes the constraint being violated. 3 <= 2.
  2. When We set control to 0, the slack variable actually falls in $[- \infty, + \infty ]$. (In my previous comment I bounded it just from the positive side). Again in many cases, e.g. M=0, the constraint would be violated.

I managed to ask some questions w.r.t. the slack variable and its rule in the constraints from the SCIP community. I will update this issue if I can get any feedback.

Regards
Abbas

@Joao-Dionisio Joao-Dionisio moved this to Todo in PySCIPOpt Oct 9, 2023
@Joao-Dionisio Joao-Dionisio moved this from Todo to Seems Doable in PySCIPOpt Oct 10, 2023
@Joao-Dionisio Joao-Dionisio moved this from Seems Doable to Todo in PySCIPOpt Oct 10, 2023
@mmghannam mmghannam added the bug label Oct 15, 2023
@mmghannam mmghannam moved this from Todo to Backlog in PySCIPOpt May 3, 2024
@Joao-Dionisio
Copy link
Collaborator

Joao-Dionisio commented Dec 9, 2024

EDIT: Looking into the C code, this is only really a problem with the Output, because SCIP tries to repair the solution if indicators are present. I checked that this is what happens in your case. But since the original solution is infeasible without this repair step, then it has this message. It shouldn't so we're working on removing it for these cases.

Hello, @skyu0221! You probably don't have this issue anymore, but I was looking at it today, and I think I figured it out. The problem is that addConsIndicator adds an additional variable to the problem, and this variable is not being set in the solution you are providing. For this, you need to use createPartialSol, instead of createSol. If I add an appropriate value to the auxiliary variable (which you can see with getVars(transformed=True)), then I don't get the infeasible output.

There is the question of whether users are expected to know that this is the case or if SCIP should do some more work behind the scenes. I'll discuss this with the others.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
Status: Backlog
Development

No branches or pull requests

4 participants