Programming Z3

Programming Z3

TU Wien Guest Lectures, October 2025

Nikolaj Bjørner
Microsoft Research

Contents

Programming Z3

Solver methods

s = Solver()


s.add($\varphi$)
s.assert_and_track($\varphi, \ell$)

s.push()
s.pop()

s.check()
s.check($[\ell_1,\ldots, \ell_n]$)

s.model()
s.proof()
s.unsat_core()   

s.statistics()     


  • Create a solver

  • Add assertion to solver state

  • Create local scopes

  • Check satisfiability

  • Retrieve models, proofs, cores

  • Additional information

Assertions

Solver methods

s.add($\varphi$)
s.assert_and_track($\varphi, \ell$)



Assert $\varphi$ to the solver state. Optionally, track the assertion $\varphi$ by a literal $\ell$.

Unsatisfiable cores contain tracked literals.

Scopes

Solver methods

s.push()

s.pop()



Add or remove a scope from the solver.

Assertions added within a scope are removed when the scope is popped.

Check Satisfiability

Solver methods

s.check()

s.check($[\ell_1,\ldots, \ell_n]$)


Is the solver state satisfiable?

Is the solver state satisfiable modulo the assumption literals $\ell_1, \ldots, \ell_n$.

The solver state is the conjunction of assumption literals and assertions that have been added to the solver in the current scope.

Certificates

Methods


s.model()

s.proof()

s.unsat_core()   


An interpretation satisfying current constraints.

A proof term certifying unsatisfiability of constraints.

A subset of assumptions/tracked assertions that suffice to establish unsatisfiability.

Extended SAT queries

Silva

Slide is by Joao Marques-Silva

Logical Queries - SAT+



sat $\varphi$ unsat


model $\varphi$ (clausal) proof


correction set $\subseteq \varphi_1, \ldots, \varphi_n \supseteq $ core


local min correction set $ \subseteq \varphi_1, \ldots, \varphi_n \supseteq$ local min core


min correction set $ \subseteq \varphi_1, \ldots, \varphi_n \supseteq$ min core


$\max x \varphi(x)$

Logical Queries

\[\begin{mdmathpre}%mdk \mathrm{Satisfiability}~~~&~\varphi \rightsquigarrow \mathid{sat},~\mathid{unsat},~\mathid{timeout}~\smallskip \\ \mathrm{Certificates}~~~~~&~\varphi \rightsquigarrow \mathid{model},~\mathid{proof},~\mathid{unsat}~\mathid{core}~\smallskip\\ \mathrm{Interpolation}~~~~&~\varphi[\mathid{x},\mathid{y}]~\rightarrow \mathid{I}[\mathid{x}]~\rightarrow \psi[\mathid{x},\mathid{z}]~\smallskip\\ \mathrm{Optimization}~~~~~&~\max \mathid{x}~\mid \varphi \smallskip \\ \mathrm{Consequences}~~~~~&~\varphi \rightarrow \varphi_1~\wedge \ldots \wedge \varphi_\mathid{n}\smallskip\\ \mathrm{Sat\ subsets}~~~~~&~\psi_1~\wedge \psi_2,\ \psi_1~\wedge \psi_3\smallskip\\ \mathrm{Unsat\ cores}~~~~~&~\neg(\psi_1~\wedge \psi_2),\ \neg(\psi_1~\wedge \psi_3)\medskip\\ \mathrm{Model\ counting}~~&~|\{~\mathid{x}~\mid \varphi\}|~\medskip\\ \mathrm{All\ models}~~~~~~&~\mathid{Ideal}(\varphi),~\mathid{M}_1~\models \varphi,~\mathid{M}_2~\models \varphi,~\ldots \medskip\\ \mathrm{Model\ probability}~&~\ldots \end{mdmathpre}%mdk \]

Programming with Cores and Correction sets

  • Optimization as SMT with preferred models

  • An introduction to cores and correction sets

  • Show examples of algorithms on top of SMT/Z3

Cores, Correction Sets, Satisfying Assignments

  • (M)US (Minimal) unsatisfiable subset

    • (minimal) subset of assertions that are unsatisfiable. Also known as a core
  • (M)SS (Maximal) satisfiable subset

    • (maximal) subset of assertions that are satisfiable.
  • (M)CS (Minimal) correction set

    • complement of an (M)SS.
  • (Prime) implicant

    • $m \Rightarrow \phi$ iff $m$ is a core for $\neg \phi$.

A Duality: MUS $\sim$ MCS (Reiter1987)

Reiter

All Cores and Correction Sets (Liffiton et al.2016)


  • Given $\varphi_1, \ldots, \varphi_n$
    • Find all min unsat cores
    • Find all max satisfying subsets
  • Generate subset $S \subseteq \{1,\ldots, n\}$
    • Not a superset of old core
    • Not a subset of old sat subset
  • Is $\bigwedge_{j \in S} \varphi_j$ satisfiable?
    • If yes, find max sat $S' \supseteq S$
    • If no, find min unsat $S' \subseteq S$
  • Block $S'$ from next iteration


def ff(s, p): 
    return is_false(s.model().eval(p))

def marco(s, ps):
    map = Solver()
    while map.check() == sat:
        seed = {p for p in ps if not ff(map, p)}
        if s.check(seed) == sat:
           mss = get_mss(s, seed, ps)
           map.add(Or(ps - mss))
           yield "MSS", mss
        else:
           mus = get_mus(s, seed)
           map.add(Not(And(mus)))
           yield "MUS", mus

Cores and Correction sets Algorithm

def ff(s, p): 
    return is_false(s.model().eval(p))

def marco(s, ps):
    map = Solver()
    while map.check() == sat:
        seed = {p for p in ps if not ff(map, p)}
        if s.check(seed) == sat:
           mss = get_mss(s, seed, ps)
           map.add(Or(ps - mss))
           yield "MSS", mss
        else:
           mus = get_mus(s, seed)
           map.add(Not(And(mus)))
           yield "MUS", mus

Maximizing Satisfying Assignments (Mencía et al.2015)

def tt(s, f): 
    return is_true(s.model().eval(f))

def get_mss(s, mss, ps):
    ps = ps - mss
    backbones = set([])
    while len(ps) > 0:
       p = ps.pop()
       if sat == s.check(mss | backbones | { p }):
          mss = mss | { p } | { q for q in ps if tt(s, q) }
          ps  = ps - mss
       else:
          backbones = backbones | { Not(p) }
    return mss
          

Minimizing Cores (Junker2004; Bradley and Manna2007; Marques-Silva et al.2013; Bacchus and Katsirelos2015)

Use built-in core minimization:

s.set("sat.core.minimize","true")  # For Bit-vector theories
s.set("smt.core.minimize","true")  # For general SMT 

Or roll your own:


def quick_explain(test, sub):
    return qx(test, set([]), set([]), sub)

def qx(test, B, D, C):
    if {} != D:
       if test(B):
          return set([])
    if len(C) == 1:
       return C
    C1, C2 = split(C)
    D1 = qx(test, B | C1, C1, C2)
    D2 = qx(test, B | D1, D1, C1)
    return D1 | D2
    
def test(s):
    return lambda S: s.check([f for f in S]) == unsat


s = Solver()
a, b, c, d, e = Bools('a b c d e')
s.add(Or(a, b))
s.add(Or(Not(a), Not(b)))
s.add(Or(b, c))
s.add(Or(Not(c), Not(a)))

print s.check([a,b,c,d,e])
print s.unsat_core()

mus = quick_explain(test(s), {a,b,c,d})

All maximal satisfying sets (basic)

def all_mss(s, ps):
    while sat == s.check():
        mss = get_mss(s, { p for p in ps if tt(s, p) }, ps)
        s.add(Or(ps - mss))
        yield "MSS", mss
  • Inefficiency: Same unsat cores may be revisited.

All Correction Sets

Find all satisfying subsets among $\varphi_1, \ldots, \varphi_n$:

  • Initialize: $F_1 \leftarrow \varphi_1, \ldots, F_n \leftarrow \varphi_n$, $F \leftarrow \top$.
  • While $F$ is sat:
    • If $F \wedge F_1\wedge \ldots\wedge F_n$ is sat with model $M$
      • $\{ \varphi_j \mid M(\varphi_j) = \top \}$ is mss.
      • $F \leftarrow F \wedge \bigvee \{ \varphi_j \;\mid\; M(\varphi_j) = \bot \}$ add mcs
    • Else suppose $F_1,\ldots, F_k$ is a core
      • Replace by $F'_1, \ldots, F'_{k-1}$:
      • $F'_1 \leftarrow F_1 \vee F_2$, $F'_2 \leftarrow F_3 \vee (F_2 \wedge F_1)$,
        $\ldots$, $F'_{k-1} \leftarrow F_k \vee (F_{k-1} \wedge \ldots)$.

MaxSMT

  • Typical definition: Minimize the number of violated soft assertions.

  • Is built-in, based on MaxSAT algorithms.

MaxSAT example

(declare-const a Bool)
(declare-const b Bool)
(declare-const c Bool)
(assert-soft a :weight 1)
(assert-soft b :weight 2)
(assert-soft c :weight 3)
(assert (= a c))
(assert (not (and a b)))
(check-sat)
(get-model)

MaxSAT flattened

(declare-const a Bool)
(declare-const b Bool)
(declare-const c Bool)
(assert-soft a :weight 1)
(assert-soft b :weight 1) (assert-soft b :weight 1)
(assert-soft c :weight 1) (assert-soft c :weight 1) (assert-soft c :weight 1) 
(assert (= a c))
(assert (not (and a b)))
(check-sat)
(get-model)
  • NB. Implementations of MaxSAT typically flatten weights on demand.

MaxSAT flat form

\[ \underbrace{(a \equiv c) \wedge \neg (a \wedge b)}_{F}, \underbrace{a}_{F_1} \underbrace{b}_{F_2} \underbrace{b}_{F_3} \underbrace{c}_{F_4} \underbrace{c}_{F_5} \underbrace{c}_{F_6} \]
  • $F$ - hard constraints

  • $F_1, F_2, \ldots, F_6$ - soft constraints

MaxSAT with Cores (Narodytska and Bacchus2014)

A: $F, \underbrace{F_1, F_2, F_3, F_4 }_{core}, F_5$

A': $F, \ F_2 \vee F_1, F_3 \vee (F_2 \wedge F_1), F_4 \vee (F_3 \wedge (F_2 \wedge F_1)), F_5$

Lemma: for any model $M$ of $F$, $cost(M, A) = 1 + cost(M, A')$

Proof: $M(F_j) = \bot, j$ min: $ M(F'_i) = M(F_{i+1}) \vee i = j + 1, \forall i$

MaxSAT with MCS (Bjørner and Narodytska2015)

A: $F, \underbrace{F_1, F_2, F_3, F_4 }_{\mbox{correction set}}, F_5$

A': $\underbrace{ F \wedge (F_1 \vee F_2 \vee F_3 \vee F_4) }_{F`},$
$F_2 \wedge F_1,\ F_3 \wedge (F_2 \vee F_1), \ F_4 \wedge (F_3 \vee (F_2 \vee F_1)), \ F_5$

Lemma: for any model $M$ of $F'$, $cost(M, A) = cost(M, A')$

Proof: $M(F_j) = \top, j$ min:     $ M(F'_i) = M(F_{i+1}) \wedge (i \neq j \vee j = 1), \forall i$

MaxSAT with Cores (python)

def add_def(s, fml):
    name = Bool("%s" % fml)
    s.add(name == fml)
    return name

def relax_core(s, core, Fs):
    prefix = BoolVal(True)
    Fs -= { f for f in core }
    for i in range(len(core)-1):
        prefix = add_def(s, And(core[i], prefix))
        Fs |= { add_def(s, Or(prefix, core[i+1])) }

def maxsat(s, Fs):
    cost = 0
    Fs0 = Fs.copy()
    while unsat == s.check(Fs):
        cost += 1
        relax_core(s, s.unsat_core(), Fs)    
    return cost, { f for f in Fs0 if tt(s, f) }

MaxSAT with MCS (python)

def relax_mcs(s, mcs, Fs):
    prefix = BoolVal(False)
    Fs -= { f for f in mcs }
    s.add(Or(mcs))
    for i in range(len(mcs)-1):
        prefix = add_def(s, Or(mcs[i], prefix))
        Fs |= { add_def(s, And(prefix, mcs[i+1])) }

def maxsat(s, Fs0):
    Fs = Fs0.copy()
    cost = len(Fs)
    while s.check() == sat:
        mss = { f for f in Fs if tt(s, f) }
        model1 = get_mss(s, mss, Fs)
        mcs = Fs - mss
        if cost > len(mcs):
           cost = len(mcs)
           model = model1
        relax_mcs(s, [ f for f in mcs ], Fs)
    return cost, [ f for f in Fs0 if is_true(model.eval(f)) ]

MCS alone is inefficient. In (Bjørner and Narodytska2015) we combine MUS and MCS steps.

References

Fahiem Bacchus, and George Katsirelos. “Using Minimal Correction Sets to More Efficiently Compute Minimal   Unsatisfiable Sets.” In Computer Aided Verification - 27th International Conference, CAV   2015, San Francisco, CA, USA, July 18-24, 2015, Proceedings, Part II, 70–86. 2015. doi:10.1007/978-3-319-21668-3_5🔎
Nikolaj Bjørner, and Nina Narodytska. “Maximum Satisfiability Using Cores and Correction Sets.” In Proceedings of the Twenty-Fourth International Joint Conference on   Artificial Intelligence, IJCAI 2015, Buenos Aires, Argentina, July 25-31, 2015, 246–252. 2015. http://​ijcai.​org/​Abstract/​15/​041🔎
Aaron R. Bradley, and Zohar Manna. “Checking Safety by Inductive Generalization of Counterexamples to   Induction.” In Formal Methods in Computer-Aided Design, 7th International Conference,   FMCAD 2007, Austin, Texas, USA, November 11-14, 2007, Proceedings, 173–180. 2007. doi:10.1109/FAMCAD.2007.15🔎
Ulrich Junker. “QUICKXPLAIN: Preferred Explanations and Relaxations for Over-Constrained   Problems.” In Proceedings of the Nineteenth National Conference on Artificial Intelligence,   Sixteenth Conference on Innovative Applications of Artificial Intelligence, July 25-29, 2004, San Jose, California, USA, 167–172. 2004. http://​www.​aaai.​org/​Library/​AAAI/​2004/​aaai04-​027.​php🔎
Mark H Liffiton, Alessandro Previti, Ammar Malik, and Joao Marques-Silva. “Fast, Flexible MUS Enumeration.” Constraints 21 (2). Springer US: 223–250. 2016. 🔎
João Marques-Silva, Mikolás Janota, and Anton Belov. “Minimal Sets over Monotone Predicates in Boolean Formulae.” In Computer Aided Verification - 25th International Conference, CAV   2013, Saint Petersburg, Russia, July 13-19, 2013. Proceedings, 592–607. 2013. doi:10.1007/978-3-642-39799-8_39🔎
Carlos Mencía, Alessandro Previti, and João Marques-Silva. “Literal-Based MCS Extraction.” In Proceedings of the Twenty-Fourth International Joint Conference on   Artificial Intelligence, IJCAI 2015, Buenos Aires, Argentina, July 25-31, 2015, 1973–1979. 2015. http://​ijcai.​org/​Abstract/​15/​280🔎
Nina Narodytska, and Fahiem Bacchus. “Maximum Satisfiability Using Core-Guided MaxSAT Resolution.” In AAAI 2014, 2717–2723. 2014. 🔎
Raymond Reiter. “A Theory of Diagnosis from First Principles.” Artif. Intell. 32 (1): 57–95. 1987. doi:10.1016/0004-3702(87)90062-2🔎