Search code examples
constraintsz3smt

Z3 soft constraint


I am confused by the use of soft constraints in z3. When running this program, I obtain the following output.

from z3 import *
o = Solver()

expr = f"""
(declare-const v Real)
(declare-const v1 Bool)
(assert-soft v1)
(assert (= v1 (<= 0 v)))
(assert (> 10 v))

"""

p = parse_smt2_string(expr)
o.add(p)

print(o.check())
print(o.model())

output: [v1 = False, v = -1]

Would someone please know why is the soft constraint not satisfied while there exist values for v which allow it?

Similarly, this program does not return the expected output:

from z3 import *
o = Optimize()


expr = f"""
(declare-const v1 Real)
(declare-const e Bool)
(assert (= e (<= 6 v1)))
(assert-soft e)
"""

p = parse_smt2_string(expr)
o.add(p)

print(o.check())
print(o.model())

It returns [v1 = 0, e = False]. Why can't the soft constraints be fulfilled?


Solution

  • It appears parse_smt2_string does not preserve soft assertions.

    If you add print(o.sexpr()) right before you call check, it prints:

    (declare-fun v () Real)
    (declare-fun v1 () Bool)
    (assert (= v1 (<= (to_real 0) v)))
    (assert (> (to_real 10) v))
    

    As you see, the soft-constraint has disappeared. So, what z3 sees is not what you thought it did. This explains the unexpected output.

    I know that parse_smt2_string isn't exactly faithful, in the sense that it doesn't handle arbitrary SMTLib inputs. Whether this particular case is supported, I'm not sure. File it as an issue at https://github.com/Z3Prover/z3/issues and the developers might take a look.