Search code examples
z3z3py

Incorrect behaviour of .check() in z3py


Consider a set of constraints F = [a + b > 10, a*a + b + 10 < 50].

When I run it using:

s = Solver()
s.add(F)
s.check()

I get sat solution.

If I run it with:

s = Solver()
s.check(F)

I get an unknown solution. Can someone explain why this is happening?


Solution

  • Let's see:

    from z3 import *
    
    a = Int('a')
    b = Int('b')
    F = [a + b > 10, a*a + b + 10 < 50]
    
    s = Solver()
    s.add(F)
    print (s.check())
    print (s.model())
    

    This prints:

    sat
    [b = 15, a = -4]
    

    That looks good to me.

    Let's try your second variant:

    from z3 import *
    
    a = Int('a')
    b = Int('b')
    F = [a + b > 10, a*a + b + 10 < 50]
    
    s = Solver()
    print (s.check(F))
    print (s.model())
    

    This prints:

    sat
    [b = 7, a = 4]
    

    That looks good to me too.

    So, I don't know how you're getting the unknown answer. Maybe you have an old version of z3; or you've some other things in your program you're not telling us about.

    The important thing to note, however, is that s.add(F); s.check() AND s.check(F) are different operations:

    • s.add(F); s.check() means: Assert the constraints in F; check that they are satisfiable.

    • s.check(F) means: Check that all the other constraints are satisfiable, assuming F is. In particular, it does not assert F. (This is important if you do further asserts/checks later on.)

    So, in general these two different ways of using check are used for different purposes; and can yield different answers. But in the presence of no other assertions around, you'll get a solution for both, though of course the models might be different.

    Aside One reason you can get unknown is in the presence of non-linear constraints. And your a*a+b+10 < 50 is non-linear, since it does have a multiplication of a variable by itself. You can deal with that either by using a bit-vector instead of an Int (if applicable), or using the nonlinear-solver; which can still give you unknown, but might perform better. But just looking at your question as you asked it, z3 is just fine handling it.