0

I am exploring fast ways to perform SAT solving in Z3 (Python). To do so, I am trying to imitate the results of Chapter 5.1 of https://theory.stanford.edu/~nikolaj/programmingz3.html#sec-blocking-evaluations.

The code I am using is the following:

def block_modelT(s, terms): #I used the name 'block_modelT' so as not to use 'block_model'
    m = s.model()
    s.add(Or([t != m.eval(t) for t in terms]))

def all_smt(s, terms):
    while sat == s.check():
       print(s.model())
       block_modelT(s, terms)

Thus, I execute it:

pip install z3-solver
from z3 import *

x, y, z = Bools('x y z')
vars = [x,y,z]

phi_0 = x #ignore that I call them phi: it is because I am used to do it like that for predicates (i.e. literals) of other theories: e.g., if x is Int, then phi_0 = (x>0)
phi_1 = y
phi_2 = z

phi = And(phi_0, Or(phi_1, phi_2))

all_smt(s, vars)

And get the following error:

      1 def block_modelT(s, terms):
      2     m = s.model()
----> 3     s.add(Or([t != m.eval(t) for t in terms]))

TypeError: 'builtin_function_or_method' object is not iterable

Any help?

EDIT:

The problem has been solved so I finally try the next piece of code:

def all_smt(s, initial_terms):
    def block_term(s, m, t):
        s.add(t != m.eval(t))
    def fix_term(s, m, t):
        s.add(t == m.eval(t))
    def all_smt_rec(terms):
        if sat == s.check():
           m = s.model()
           yield m
           for i in range(len(terms)):
               s.push()
               block_term(s, m, terms[i])
               for j in range(i):
                   fix_term(s, m, terms[j])
               for m in all_smt_rec(terms[i:]):
                   yield m
               s.pop()   
    for m in all_smt_rec(list(initial_terms)):
        yield m   

I execute it: all_smt(s, varss) #has the same name. And get a generator <generator object all_smt at 0x7... instead of a valid assignment (i.e. a model). How can obtain the correct answer [z = False, y = True, x = True], [z = True, x = True]? I tried both print and return.

Theo Deep
  • 666
  • 4
  • 15
  • I think I got it, **`vars` is a reserved word**!!!! I discovered it when Stack has coloured the word! – Theo Deep Jan 10 '22 at 15:14
  • I don't think so.. `vars` isn't really reserved. – alias Jan 10 '22 at 15:17
  • Changed it with `varss` and I have not received the error though.. – Theo Deep Jan 10 '22 at 15:17
  • 1
    See my answer below. `vars` works just fine for me. I'm using Python 3.9.1, maybe you have some other version. (Though I doubt it'd make a difference.) – alias Jan 10 '22 at 15:19
  • 1
    Note that there's a bug in the implementation of `all_smt` in that paper. See this for the corrected version: https://github.com/Z3Prover/z3/issues/5765#issuecomment-1009135689 – alias Jan 10 '22 at 17:36
  • I was going crazy with that 'terms[i:]', thanks! – Theo Deep Jan 10 '22 at 19:36
  • 1
    I think the `terms[i+1:]` part is an optimization. But the actual bug is with the `yield` statement using the same variable name. (I'd actually call this a bug in Python itself, but I digress.) – alias Jan 10 '22 at 20:01
  • Ah, well yes, I noticed that one :) Thanks a lot! – Theo Deep Jan 10 '22 at 20:36
  • 1
    Turns out `terms[i+1:]` is actually incorrect; see https://stackoverflow.com/a/70656700/936310 for the final version. – alias Jan 11 '22 at 16:17

1 Answers1

1

Your program doesn't define an s; and you haven't added the formula to it. The following works for me:

from z3 import *

def block_modelT(s, terms): #I used the name 'block_modelT' so as not to use 'block_model'
    m = s.model()
    s.add(Or([t != m.eval(t) for t in terms]))

def all_smt(s, terms):
    while sat == s.check():
       print(s.model())
       block_modelT(s, terms)

x, y, z = Bools('x y z')
vars = [x,y,z]

phi_0 = x #ignore that I call them phi: it is because I am used to do it like that for predicates (i.e. literals) of other theories: e.g., if x is Int, then phi_0 = (x>0)
phi_1 = y
phi_2 = z

phi = And(phi_0, Or(phi_1, phi_2))

s = Solver()
s.add(phi)

all_smt(s, vars)

This prints:

[z = False, y = True, x = True]
[z = True, x = True]
alias
  • 28,120
  • 2
  • 23
  • 40
  • I am sorry, I did define the s but did not include it in the code, since it was in another cell. In any case, this is correct. – Theo Deep Jan 10 '22 at 15:19
  • 1
    No problem. If you want to avoid z3 giving you partial models, change the last line of your `block_modelT` to read: `s.add(Or([t != m.eval(t, model_completion=True) for t in terms]))` – alias Jan 10 '22 at 15:29
  • Thanks a lot again! The model completion is very useful for me!! Made a last question in EDIT. – Theo Deep Jan 10 '22 at 15:30
  • 1
    Try: `print(list(all_smt(s, vars)))` – alias Jan 10 '22 at 15:31
  • Got it right! Really curious, since I got the model completion `[[z = False, y = True, x = True], [z = True, y = False, x = True]]` without specifying it like you have just said how to do. Now, I will work on the foundations to understand better why this works and why this is divide and conquer. Thanks very much! By the way, in Collab, `vars` is a reserved word 100%. I do not know why but :( – Theo Deep Jan 10 '22 at 15:37
  • 1
    The internals of model completion is rather opaque, and its behavior can depend on the version of z3 used. It's always a good idea to specify it; in my opinion. I don't use `Collab`, so not quite sure what else it adds to the ecosystem. It's best to stick to plain python in your questions to keep confusion to a minimum. – alias Jan 10 '22 at 15:40
  • Agree, than you :) – Theo Deep Jan 10 '22 at 15:43