1

I have a (satisfiable) (linear) integer satisfiability problem. The problem contains, among others, a bunch of boolean-valued variables, call them x1...xn, with one of the constraints being that sum(x1...xn) = C. I wish to determine which of these variables are fixed, and the fixed values of said variables (as in: which of these variables take a specific value (0 or 1, as these are again boolean valued) in all possible solutions).

I have a working solution, it's just slow (to put it mildly):

  1. Add a constraint that x1 == 0
  2. Check if the problem is solvable
  3. Remove the constraint added in step 1.
  4. Add a constraint that x1 == 1
  5. Check if the problem is solvable
  6. Remove the constraint added in step 4
  7. Assert that at least one of 2 and 5 succeeded.
  8. If both succeeded, the variable is not fixed. Otherwise, the variable is fixed to whichever constraint the problem was still satisfiable under.
  9. Repeat 1...8 for x2...xn

The problem with this is that it's slow. In particular, it requires solving the problem O(n), or rather 2*n, times. (I'm passing in the previous solution to warm-start the solver, but just starting the solver is taking almost all the time.)

Is there a faster method? In particular, one that requires calling the solver less times?


Something I was thinking of, that unfortunately doesn't work as-is, is to turn it into a ILP problem and solve it twice, once with the objective of maximizing sum(x1...xn), one with the objective of minimizing the same, and checking which variables change. Unfortunately, this doesn't work in general. For (counter)example: boolean variables x and y, where x+y=1. Maximizing and minimizing can yield the same thing even though neither variable is fixed.

TLW
  • 1,373
  • 9
  • 22

2 Answers2

2

What you describe in your question what you do for a variable is commonly called probing in the MILP (mixed integer linear programming) community and unfortunately there really is nothing that is theoretically better that you can do. In practice, however, you can speed things up quite a bit.

As you noted in your own answer, for each variable you can keep track of whether you have seen that variable as False and as True in some solution, and test only that setting that you have not seen before. (Note that the very first solution you get when fixing x_1 will set one of seenFalse or seenTrue for every variable cutting the number of instances to solve in half.)

You can do even more. When you look at a particular instance (i.e., when for example, seenFalse_i is not set and you set x_i to False) then you can turn the ILSAT into an ILP using a random objective. Having an objective has several purposes

  • by using a different random objective in every instance you must solve hopefully you'll get a wide variety of solutions and you will be able to set many seen... flags.
  • Using the optimal solution value for this ILP and the LP relaxation of the ILP you may be able to perform reduced cost fixing, i.e., based on the reduced cost of out-of-basis boolean variables you may be able to prove that they can't take any other value than the one they are currently at, thus potentially being able to set more seen... flags.
LaszloLadanyi
  • 973
  • 4
  • 12
0

It would appear as though I have a solution to my own question. It's not ideal, and as such I'd accept other answers, but here goes:

  1. Turn the ILSAT into a ILP.
  2. For each variable to check, set seenTrue and seenFalse for that variable to False
  3. Set the objective function to maximize the sum of variables that have been seen to be False but not True, minus the sum of variables that have been seen to be True but not False.
  4. Solve the ILP.
  5. If none of the values that are not known to be unknown have changed since last iteration, break to 8.
  6. For each variable in the solution, set seenTrue or seenFalse to True, depending on if the variable is True or False.
  7. Goto 2
  8. For each variable, if it was only seen to be one of True or False, the variable is fixed to that value. Otherwise (it has been seen to be both) it is not fixed.

Effectively what I'm doing is always trying to maximize the number of variables set to values that they haven't already been set to.

TLW
  • 1,373
  • 9
  • 22
  • 1
    I don't think this algo will work. The ILP you set up may very well have several alternate optimal solutions. Thus jumping out in 5 may claim that a variable must be fixed one way when in fact there is an alternate solution that would prove otherwise. – LaszloLadanyi Jun 27 '14 at 01:43
  • 1
    I agree; this looks wrong. I think a better approach is to modify your original program to look at each solution and note if variable values have changed between it and the previous solution. Depending on which solutions are found, you may only have to run the solver a few times. Also, record the solution as a new constraint so that you never find it again. I.e. if the solution was x1 !x2 x3 x4, add a clause demanding (!x1 or x2 or !x3 or !x4) which guarantees you won't ever see the same solution twice as you test each variable. – Kyle Jones Jun 27 '14 at 03:06
  • Can you provide a counterexample? Because this provides the expected results for me in every instance I've tested thus far. The objective basically boils down to "change as many variables as possible from last time that we don't already know aren't fixed" - which means that the only case where it breaks out is if it cannot find a solution that changes any variables not already known to be not fixed, hence all of the variables left are fixed. – TLW Jun 27 '14 at 12:23