Satisfiability modulo theory
David Monniaux
CNRS / VERIMAG
October 2017
1 / 182
Satisfiability modulo theory David Monniaux CNRS / VERIMAG October - - PowerPoint PPT Presentation
Satisfiability modulo theory David Monniaux CNRS / VERIMAG October 2017 1 / 182 Schedule Introduction Propositional logic First-order logic Applications Beyond DPLL(T) Qvantifier elimination Interpolants 2 / 182 Who I am David
CNRS / VERIMAG
1 / 182
2 / 182
3 / 182
▶ CNRS (9 permanent researchers) ▶ Université Grenoble Alpes (15 faculty) ▶ Grenoble-INP (8 faculty)
4 / 182
▶ formal methods
▶ static analysis ▶ proof assistants ▶ decision procedures ▶ exact analysis
▶ modeling of hardware/sofuware system platforms
▶ hybrid systems
5 / 182
▶ “toy” programming language or formalism (Turing
▶ real programming language
6 / 182
7 / 182
8 / 182
9 / 182
10 / 182
11 / 182
12 / 182
12 / 182
13 / 182
14 / 182
15 / 182
16 / 182
17 / 182
a b b c c c c 1 1 1 1
18 / 182
a b b c c c c 1 1 1 1 identical identical
19 / 182
c 1 a b c 1 1 identical
20 / 182
a b c 1 1
21 / 182
https://en.wikipedia.org/wiki/Hash_consing
22 / 182
23 / 182
▶ Java WeakHashMap ▶ OCaml Weak
24 / 182
▶ Java WeakHashMap ▶ OCaml Weak
24 / 182
▶ maximal sharing: never two identical objects in two ̸=
▶ ultra-fast equality test: sufgicient to compare pointers
25 / 182
▶ Create BDD f, t(1-node constants). ▶ Create BDD for v, for v any variable. ▶ Operations ∧, ∨, etc.
26 / 182
▶ store values of f(a, b) already computed in a hash table ▶ index the table by the unique identifiers of a and b
27 / 182
▶ store values of f(a, b) already computed in a hash table ▶ index the table by the unique identifiers of a and b
▶ without dynamic programming: unfolds DAG into tree
▶ with dynamic programming O(|a|.|b|) where |x| the size
27 / 182
28 / 182
1, . . . , x′ n) =
1, . . . , x′ n)
▶ variable renaming (easy) ▶ constructing the BDD for τ ▶ ∃-elimination for n variables ▶ conjunction
29 / 182
30 / 182
31 / 182
▶ “SAT” with arbitrary formula ▶ “CNF-SAT” with formula in CNF ▶ “3CNF-SAT” with formula in CNF, 3 literals per clause
32 / 182
33 / 182
34 / 182
35 / 182
36 / 182
37 / 182
38 / 182
▶ either find a satisfying assignment ▶ either find an unsatisfiable clause (all literals forced to
▶ pick a variable ▶ do a search subtree for both polarities of the variable
39 / 182
40 / 182
41 / 182
42 / 182
43 / 182
▶ short DAG resolution proofs ▶ only exponential tree resolution proofs.
44 / 182
45 / 182
46 / 182
▶ Minisat http://minisat.se/ ▶ Glucose http:
▶ Armin Biere’s solvers
47 / 182
▶ look for a variable in each clause, “remove it” ▶ how do we backtrack?
48 / 182
▶ for each literal: a linked list of clauses ▶ each clause has two watched literals ▶ invariant: in each clause the two watched literals are not
▶ For each clause with one literal assigned t, ignore the
▶ For each clause with > 1 unassigned literal l′, move
▶ For each clause with 1 unassigned literal l′, l′ := t ▶ 0 unassigned literal, CONFLICT (analyze and backtrack)
49 / 182
▶ heuristics for picking first polarity choice ▶ keep last polarity used in next choices
50 / 182
51 / 182
52 / 182
52 / 182
53 / 182
54 / 182
▶ 0-ary predicates = propositional variables ▶ 1-ary predicates (monadic) ▶ other predicates
55 / 182
56 / 182
57 / 182
58 / 182
59 / 182
60 / 182
61 / 182
62 / 182
63 / 182
64 / 182
65 / 182
66 / 182
67 / 182
68 / 182
69 / 182
70 / 182
71 / 182
72 / 182
▶ branching: if LRA model x = 4.3, then x ≤ 4 ∨ x ≥ 5 ▶ (sometimes) Gomory cuts
73 / 182
74 / 182
▶ x ̸= x0 to f[x] ▶ x0 to y0.
75 / 182
76 / 182
77 / 182
78 / 182
▶ prove it holds initially ▶ prove: if it holds then it holds at next iteration
79 / 182
/*@ requires @ n >= 0 && \valid(t+(0..n-1)) && @ \forall int k1, k2; 0 <= k1 <= k2 <= n-1 ==> t[k1] <= t[k2]; @ assigns \nothing; @ ensures @ (0 <= \result < n && t[\result] == v) || @ (\result == -1 && \forall int k; 0 <= k < n ==> t[k] != v); @*/ int binary_search(int* t, int n, int v) { int l = 0, u = n-1; /*@ loop invariant @ 0 <= l && u <= n-1 @ && (\forall int k; 0 <= k < n ==> t[k] == v ==> l <= k <= u) ; @ loop assigns l,u ; @ loop variant u-l ; @*/ while (l <= u ) { int m = l + (u-l) / 2; //@ assert l <= m <= u; if (t[m] < v) l = m + 1; else if (t[m] > v) u = m - 1; else return m; } return -1; }
80 / 182
▶ Follow paths inside the program ▶ On each path collect constraints on variables (guards in
▶ Check feasibility using SMT-solving ▶ If symbolic execution becomes impossible (calls to native
81 / 182
82 / 182
83 / 182
84 / 182
85 / 182
86 / 182
87 / 182
88 / 182
State 18 file cbmc_boucle.c line 4 function main thread 0 t=0 (00000000000000000000000000000000) State 19 file cbmc_boucle.c line 4 function main thread 0 t=0 (00000000000000000000000000000000) State 20 file cbmc_boucle.c line 4 function main thread 0 x=0 (00000000000000000000000000000000) State 21 file cbmc_boucle.c line 5 function main thread 0 i=0 (00000000000000000000000000000000) State 22 file cbmc_boucle.c line 5 function main thread 0 i=0 (00000000000000000000000000000000) State 27 file cbmc_boucle.c line 6 function main thread 0 x=95 (00000000000000000000000001011111) State 29 file cbmc_boucle.c line 8 function main thread 0 t=95 (00000000000000000000000001011111) State 30 file cbmc_boucle.c line 5 function main thread 0 i=1 (00000000000000000000000000000001) State 36 file cbmc_boucle.c line 6 function main thread 0 x=97 (00000000000000000000000001100001) State 38 file cbmc_boucle.c line 8 function main thread 0 t=192 (00000000000000000000000011000000) State 39 file cbmc_boucle.c line 5 function main thread 0 i=2 (00000000000000000000000000000010) State 45 file cbmc_boucle.c line 6 function main thread 0 x=98 (00000000000000000000000001100010) State 47 file cbmc_boucle.c line 8 function main thread 0 t=290 (00000000000000000000000100100010) State 48 file cbmc_boucle.c line 5 function main thread 0 i=3 (00000000000000000000000000000011) Violated property: file cbmc_boucle.c line 10 function main assertion t < 290
89 / 182
90 / 182
91 / 182
▶ one Boolean per program basic block “the execution goes
▶ constraints expressing program operations and tests (e.g.
92 / 182
93 / 182
entry: assume -10000 < x_old.0 <10000 x.0 = input(-10000,10000) add = x_old.0 + 10 cmp = x.0 > add cmp ? if.then: x.1 = x_old.0 + 10 if.end: x.2 = phi [x.1,if.then], [x.0,entry] sub = x_old.0 - 10 cmp3 = x.2 < sub cmp3 ? if.then4: x.3 = x_old.0 - 10 if.end6: x_old.1 = phi [x.3,if.then4], [x.2,if.end]
94 / 182
▶ 1 Boolean per block ▶ 1 Boolean per
entry: ; b_0 assume -10000 < x_old.0 <10000 x.0 = input(-10000,10000) add = x_old.0 + 10 cmp = x.0 > add cmp ? if.then: ; b_1 x.1 = x_old.0 + 10 if.end: ; b_2 x.2 = phi [x.1,if.then], [x.0,entry] sub = x_old.0 - 10 cmp3 = x.2 < sub cmp3 ? if.then4: ; b_3 x.3 = x_old.0 - 10 if.end6: ; b_4 x_old.1 = phi [x.3,if.then4], [x.2,if.end] t_0_1 cost = 15 t_0_2 cost = 14 t_1_2 cost = 6 t_2_3 cost = 12 t_2_4 cost = 11 t_3_4 cost = 6 95 / 182
−10000 ≤ x_old.0 ≤ 10000 ∧ −10000 ≤ x.0 ≤ 10000 ∧ add = (x_old.0 + 10) ∧ x.1 = (x_old.0 + 10) ∧ sub = (x_old.0 − 10) ∧ x.3 = (x_old.0 − 10) ∧ b_2 ⇒ (x.2 = ite(t_1_2, x.1, x.0)) ∧ b_4 ⇒ (x.1 = ite(t_3_4, x.3, x.2))
entry: ; b_0 assume -10000 < x_old.0 <10000 x.0 = input(-10000,10000) add = x_old.0 + 10 cmp = x.0 > add cmp ? if.then: ; b_1 x.1 = x_old.0 + 10 if.end: ; b_2 x.2 = phi [x.1,if.then], [x.0,entry] sub = x_old.0 - 10 cmp3 = x.2 < sub cmp3 ? if.then4: ; b_3 x.3 = x_old.0 - 10 if.end6: ; b_4 x_old.1 = phi [x.3,if.then4], [x.2,if.end] t_0_1 cost = 15 t_0_2 cost = 14 t_1_2 cost = 6 t_2_3 cost = 12 t_2_4 cost = 11 t_3_4 cost = 6 95 / 182
−10000 ≤ x_old.0 ≤ 10000 ∧ −10000 ≤ x.0 ≤ 10000 ∧ add = (x_old.0 + 10) ∧ x.1 = (x_old.0 + 10) ∧ sub = (x_old.0 − 10) ∧ x.3 = (x_old.0 − 10) ∧ b_2 ⇒ (x.2 = ite(t_1_2, x.1, x.0)) ∧ b_4 ⇒ (x.1 = ite(t_3_4, x.3, x.2))
entry: ; b_0 assume -10000 < x_old.0 <10000 x.0 = input(-10000,10000) add = x_old.0 + 10 cmp = x.0 > add cmp ? if.then: ; b_1 x.1 = x_old.0 + 10 if.end: ; b_2 x.2 = phi [x.1,if.then], [x.0,entry] sub = x_old.0 - 10 cmp3 = x.2 < sub cmp3 ? if.then4: ; b_3 x.3 = x_old.0 - 10 if.end6: ; b_4 x_old.1 = phi [x.3,if.then4], [x.2,if.end] t_0_1 cost = 15 t_0_2 cost = 14 t_1_2 cost = 6 t_2_3 cost = 12 t_2_4 cost = 11 t_3_4 cost = 6 95 / 182
−10000 ≤ x_old.0 ≤ 10000 ∧ −10000 ≤ x.0 ≤ 10000 ∧ add = (x_old.0 + 10) ∧ x.1 = (x_old.0 + 10) ∧ sub = (x_old.0 − 10) ∧ x.3 = (x_old.0 − 10) ∧ b_2 ⇒ (x.2 = ite(t_1_2, x.1, x.0)) ∧ b_4 ⇒ (x.1 = ite(t_3_4, x.3, x.2))
entry: ; b_0 assume -10000 < x_old.0 <10000 x.0 = input(-10000,10000) add = x_old.0 + 10 cmp = x.0 > add cmp ? if.then: ; b_1 x.1 = x_old.0 + 10 if.end: ; b_2 x.2 = phi [x.1,if.then], [x.0,entry] sub = x_old.0 - 10 cmp3 = x.2 < sub cmp3 ? if.then4: ; b_3 x.3 = x_old.0 - 10 if.end6: ; b_4 x_old.1 = phi [x.3,if.then4], [x.2,if.end] t_0_1 cost = 15 t_0_2 cost = 14 t_1_2 cost = 6 t_2_3 cost = 12 t_2_4 cost = 11 t_3_4 cost = 6 95 / 182
∧ b_0 = b_4 = true ∧ b_1 = t_0_1 ∧ b_2 = (t_0_2 ∨ t_1_2) ∧ . . . ∧ . . . ∧ t_0_1 = (b_0 ∧ (x.0 > add)) ∧ . . . ∧ . . .
entry: ; b_0 assume -10000 < x_old.0 <10000 x.0 = input(-10000,10000) add = x_old.0 + 10 cmp = x.0 > add cmp ? if.then: ; b_1 x.1 = x_old.0 + 10 if.end: ; b_2 x.2 = phi [x.1,if.then], [x.0,entry] sub = x_old.0 - 10 cmp3 = x.2 < sub cmp3 ? if.then4: ; b_3 x.3 = x_old.0 - 10 if.end6: ; b_4 x_old.1 = phi [x.3,if.then4], [x.2,if.end] t_0_1 cost = 15 t_0_2 cost = 14 t_1_2 cost = 6 t_2_3 cost = 12 t_2_4 cost = 11 t_3_4 cost = 6 95 / 182
∧ c_0_1 = (if(t_0_1) then 15 else 0) ∧ c_0_2 = (if(t_0_2) then 14 else 0) ∧ . . . ∧ . . . ∧ . . . ∧ cost = (c_0_1 + c_0_2 + c_1_2 + c_2_3 + c_2_4 + c_3_4)
entry: ; b_0 assume -10000 < x_old.0 <10000 x.0 = input(-10000,10000) add = x_old.0 + 10 cmp = x.0 > add cmp ? if.then: ; b_1 x.1 = x_old.0 + 10 if.end: ; b_2 x.2 = phi [x.1,if.then], [x.0,entry] sub = x_old.0 - 10 cmp3 = x.2 < sub cmp3 ? if.then4: ; b_3 x.3 = x_old.0 - 10 if.end6: ; b_4 x_old.1 = phi [x.3,if.then4], [x.2,if.end] t_0_1 cost = 15 t_0_2 cost = 14 t_1_2 cost = 6 t_2_3 cost = 12 t_2_4 cost = 11 t_3_4 cost = 6 95 / 182
entry: ; b_0 assume -10000 < x_old.0 <10000 x.0 = input(-10000,10000) add = x_old.0 + 10 cmp = x.0 > add cmp ? if.then: ; b_1 x.1 = x_old.0 + 10 if.end: ; b_2 x.2 = phi [x.1,if.then], [x.0,entry] sub = x_old.0 - 10 cmp3 = x.2 < sub cmp3 ? if.then4: ; b_3 x.3 = x_old.0 - 10 if.end6: ; b_4 x_old.1 = phi [x.3,if.then4], [x.2,if.end] t_0_1 cost = 15 t_0_2 cost = 14 t_1_2 cost = 6 t_2_3 cost = 12 t_2_4 cost = 11 t_3_4 cost = 6 95 / 182
entry: ; b_0 assume -10000 < x_old.0 <10000 x.0 = input(-10000,10000) add = x_old.0 + 10 cmp = x.0 > add cmp ? if.then: ; b_1 x.1 = x_old.0 + 10 if.end: ; b_2 x.2 = phi [x.1,if.then], [x.0,entry] sub = x_old.0 - 10 cmp3 = x.2 < sub cmp3 ? if.then4: ; b_3 x.3 = x_old.0 - 10 if.end6: ; b_4 x_old.1 = phi [x.3,if.then4], [x.2,if.end] t_0_1 cost = 15 t_0_2 cost = 14 t_1_2 cost = 6 t_2_3 cost = 12 t_2_4 cost = 11 t_3_4 cost = 6 95 / 182
96 / 182
97 / 182
98 / 182
0.01 0.1 1 10 100 1000 10000 10 12 14 16 18 20 22 time (s) n Z3 3.2 Z3 4.3.1 MathSAT 5.2.6 SMTInterpol ~ 2.22^n 99 / 182
0.01 0.1 1 10 100 90 92 94 96 98 100 time (s) B Z3 3.2 ~ 1/2^(B-90) 100 / 182
101 / 182
102 / 182
103 / 182
104 / 182
105 / 182
106 / 182
107 / 182
108 / 182
109 / 182
110 / 182
111 / 182
▶ Z3 (Microsofu Research)
▶ Yices (SRI International)
▶ CVC4 http://cvc4.cs.nyu.edu/web/
▶ MathSAT (Fundazione Bruno Kessler)
112 / 182
113 / 182
114 / 182
115 / 182
i Ci = a set {C1, . . . , Cn} of clauses.
▶ no redundant literals in a clause (e.g. a ∨ a ∨ b) ▶ no trivially true clauses (e.g. a ∨ ¬a ∨ b).
i ∨ a
j ∨ ¬a
j ∨ C′ j
1 ∧ · · · ∧ C′ n′ ≡ ∃a (C1 ∧ · · · ∧ Cn)
116 / 182
▶ Not efgicient if applied blindly. ▶ May be used as simplification if not inflating the set
▶ ≤ 3|V| difgerent clauses, thus termination. ▶ Detect subsumption: do not store a ∨ b ∨ c in addition to
▶ Eliminate all variables: obtain the empty clause (f) ifg
i Ci unsatiasfiable. ▶ (More on this later) DPLL/CDCL SAT-solvers finding
117 / 182
118 / 182
119 / 182
▶ ∀x F ≡ ¬∃x¬ F ▶ ∃x (F1 ∨ F2) ≡ (∃x F1) ∨ (∃x F2) ▶ ∃x F ≡ ∃x F′ where F′ DNF of F
120 / 182
121 / 182
122 / 182
123 / 182
124 / 182
▶ L+, where x has positive coefgicient (n.x + · · · ≤ b), thus
n.(b − . . . ) ▶ L−, where x has negative coefgicient ((−n).x + · · · ≤ b),
n.(b − . . . ) ▶ L0, without x
i
i (y, . . . ) ≤ x ≤ min j
j (y, . . . )
125 / 182
i (y, . . . ) ≤ x ≤ minj l+ j (y, . . . )
i (y, . . . ) ≤ minj l+ j (y, . . . )
i (y, . . . ) ≤ l+ j (y, . . . )
▶ Copy L0 ▶ For all pair (l− i (y, . . . ) ≥ x, x ≤ l+ j (y, . . . )) ∈ L− × L+
i (y, . . . ) ≤ l+ j (y, . . . ).
126 / 182
127 / 182
128 / 182
▶ Syntactic criteria (cf Simon & King, SAS 2005), e.g.
▶ Linear programming: if we have C and add C′
▶ test emptiness of C ∧ ¬C′ by linear programming ▶ or maximize a1x1 + · · · + anxn w.r.t C and keep C′ if B less
▶ Or ray-tracing (Maréchal & Périn, 2017)
129 / 182
▶ Extract a conjunction C ⇒ F of atoms of F (see
▶ Extract maximal conjunction C′ s.t. C ⇒ C′ ⇒ F. From
▶ Project C′ into π(C′), add to output F′. ▶ Conjoin ¬π(C′) to F.
130 / 182
131 / 182
132 / 182
133 / 182
134 / 182
x y
135 / 182
▶ true for x → −∞, x → +∞, ▶ true for all x intersection point or median to intersections
i
i<j
136 / 182
▶ true when x → −∞ ▶ true for all x = xi given x ≥ xi(y, . . . ) ▶ true for all x = xi + ϵ given by x > xi(y dots)
i
j
i+ϵ]
137 / 182
138 / 182
139 / 182
139 / 182
140 / 182
▶ there is an infinity of solutions → −∞ ▶ or there is a least solution
141 / 182
▶ making true all atoms x′ < t ▶ making false all atoms x′ > t.
142 / 182
δ
j=1
−∞[x′ → j] ∨ δ
j=1
t∈B
143 / 182
j=1
t∈B F′[x′ → b + j].
144 / 182
145 / 182
146 / 182
▶ Constants: easy. ▶ Z: use a sign bit, or encode ≥ 0 into even numbers and
▶ Successor, addition etc.: propagate carry inside the
▶ ∧: intersection of regular languages ▶ ∨: union of regular languages ▶ ¬: complement ▶ ∃vi F : make transitions depending on the i-th input
147 / 182
n
148 / 182
148 / 182
149 / 182
▶ any positive number has a square root ▶ axiom scheme indexed by P ∈ Z[X] of odd degree, then P
150 / 182
151 / 182
1, . . . , P′ m′ ∈ Z[Y1, . . . , Yn] such that
1, . . . , P′ m′, keep those for
152 / 182
▶ derivation: given P, add dP/dX ▶ extraction of leading coefgicient: from ∑d k=0 akXk
▶ removal of leading coefgicient: from ∑d k=0 akXk get
k=0 akXk
153 / 182
154 / 182
155 / 182
156 / 182
157 / 182
158 / 182
159 / 182
160 / 182
161 / 182
▶ Rather easy on linear theory of reals. ▶ Harder on linear theory of integers (Presburger) — see
▶ Painful in another way on polynomial real arithmetic
▶ Impossible in general on polynomial integer arithmetic
162 / 182
163 / 182
164 / 182
165 / 182
165 / 182
▶ i1 = 0 ∧ j1 = 0 ∧ i2 = i1 ∧ j2 = j1 ⇒ j2 = 2i2 ∧ i ≥ 100 ▶ j2 = 2i2 ∧ i2 ≥ 100 ⇒ j2 < 210
166 / 182
▶ i1 = 0 ∧ j1 = 0 ∧ i2 = i1 ∧ j2 = j1 ⇒ j2 = 2i2 ∧ i ≥ 100 ▶ j2 = 2i2 ∧ i2 ≥ 100 ⇒ j2 < 210
166 / 182
167 / 182
▶ i1 = 0 ∧ j1 = 0 ∧ i2 = i1 ∧ j2 = j1 ⇒ i2 = 0 ∧ j2 = 0 ▶ i2 = 0 ∧ j2 = 0 ⇒ j2 < 210
168 / 182
A B∧ i = 0∧ j = 0 B
fail i′ = 0 j′ = 0 i < 100 i′ = i + 1 j′ = j + 2 i < 100 i′ = i + 1 j′ = j + 2 i′ = i j′ = j i ≥ 100 j < 210 i′ = i j′ = j i ≥ 100 j ≥ 210
169 / 182
▶ i1 = 0 ∧ j1 = 0 ∧ i2 = i1 ∧ j2 = j1 ⇒ i2 = 0 ∧ j2 = 0 ▶ i2 = 0∧j2 = 0∧i3 = i2 +1∧j3 = j2 +2 ⇒ i3 = 1∧j3 = 2 ▶ i3 = 1 ∧ j3 = 2 ⇒ j2 < 210
170 / 182
A B∧ i = 0∧ j = 0 B∧ i = 1∧ j = 2 B
fail i′ = 0 j′ = 0 i < 100 i′ = i + 1 j′ = j + 2 i < 100 i′ = i + 1 j′ = j + 2 i < 100 i′ = i + 1 j′ = j + 2 i′ = i j′ = j i ≥ 100 j < 210 i′ = i j′ = j i ≥ 100 j ≥ 210
171 / 182
▶ Interpolant j = 2i ∧ i ≤ 100 (polyhedral inductive
▶ Interpolants i = 0 ∧ j = 0, i = 1 ∧ j = 2, i = 2 ∧ j = 4
172 / 182
173 / 182
174 / 182
175 / 182
▶ A |
▶ B, Ic |
▶ p(c) only has global symbols
176 / 182
▶ ¬(ϕ \ g(ϕ)) |
▶ ¬g(ϕ), Iφ |
▶ Iφ only has global symbols
177 / 182
i Ai is a polyhedron over ⃗
i Ai is a polyhedron over ⃗
i Bi is a polyhedron over ⃗
i Bi is a polyhedron over ⃗
178 / 182
179 / 182
180 / 182
181 / 182
182 / 182