├── README.md ├── advanced-examples.htm ├── examples ├── advanced.htm ├── arith.1.py ├── arith.2.py ├── arith.3.py ├── arith.4.py ├── arith.5.py ├── array.1.py ├── array.2.py ├── array.3.py ├── array.4.py ├── array.5.py ├── array.py ├── bintree.py ├── bit.1.py ├── bit.2.py ├── bitvec.1.py ├── bitvec.2.py ├── bitvec.3.py ├── circuit.py ├── comment.py ├── datatype.1.py ├── datatype.2.py ├── datatype.3.py ├── datatype.4.py ├── datatype.5.py ├── euf1.py ├── euf2.py ├── euf3.py ├── expr.1.py ├── expr.2.py ├── expr.3.py ├── expr.4.py ├── expr.5.py ├── expr.6.py ├── expr.7.py ├── expr.8.py ├── fixedpoint.1.py ├── fixedpoint.10.py ├── fixedpoint.2.py ├── fixedpoint.3.py ├── fixedpoint.4.py ├── fixedpoint.5.py ├── fixedpoint.8.py ├── fixedpoint.9.py ├── fixedpoints.htm ├── format.py ├── guide.htm ├── install.1.py ├── install.2.py ├── k.1.py ├── k.2.py ├── list.1.py ├── list.2.py ├── list1.py ├── list2.py ├── msolver.1.py ├── nqueens.py ├── printer.py ├── probe.1.py ├── probe.1.ty ├── probe.2.py ├── probe.3.py ├── puzzle.1.py ├── puzzle.2.py ├── puzzle.3.py ├── quant.1.py ├── quant.2.py ├── quant.3.py ├── quant.4.py ├── quant.5.py ├── quant.6.py ├── quant.7.py ├── quant.8.py ├── queens.png ├── strategies.htm ├── sudoku.png ├── sudoku.py ├── tactic.1.py ├── tactic.10.py ├── tactic.2.py ├── tactic.3.py ├── tactic.4.py ├── tactic.5.py ├── tactic.6.py ├── tactic.7.py ├── tactic.8.py ├── tactic.9.py ├── tree.py ├── uninterp.1.py ├── unsatcore.1.py ├── z3py.1.py ├── z3py.10.py ├── z3py.11.py ├── z3py.12.py ├── z3py.13.py ├── z3py.14.py ├── z3py.15.py ├── z3py.16.py ├── z3py.2.py ├── z3py.3.py ├── z3py.4.py ├── z3py.5.py ├── z3py.6.py ├── z3py.6a.py ├── z3py.6aa.py ├── z3py.7.py ├── z3py.8.py └── z3py.9.py ├── fixpoint-examples.htm ├── guide-examples.htm ├── index.html ├── installation-guide.pdf ├── strategies-examples.htm └── style.css /README.md: -------------------------------------------------------------------------------- 1 | # Z3py tutorial 2 | 3 | This project archives files in the official [Z3py website](http://rise4fun.com/z3py), which was shut down due to security issues. The official [Z3 website](http://z3.codeplex.com/) however is still online and [active](https://github.com/Z3Prover/z3). 4 | 5 | * [Introduction](http://ericpony.github.io/z3py-tutorial/guide-examples.htm) 6 | * [Strategies](http://ericpony.github.io/z3py-tutorial/strategies-examples.htm) 7 | * [Fixed-point computation](http://ericpony.github.io/z3py-tutorial/fixpoint-examples.htm) 8 | * [Advanced topics](http://ericpony.github.io/z3py-tutorial/advanced-examples.htm) 9 | * [API documentation](http://z3prover.github.io/api/html/namespacez3py.html) (also available in [pydoc format](http://z3prover.github.io/api/html/z3.html)) 10 | 11 | The source code of Z3Py is available in the Z3 distribution, where you can also find APIs in C, .NET, OCaml, and Java. Other cool front-ends for Z3 includes [ScalaZ3](https://github.com/epfl-lara/ScalaZ3) and [SBV](https://github.com/LeventErkok/sbv). 12 | 13 | ## Related projects 14 | 15 | * [A symbolic execution engine using Z3py](https://github.com/thomasjball/PyExZ3) 16 | * [Z3py with set comprehensions](https://github.com/sllam/pysetcomp) 17 | * [More Z3py examples](https://github.com/0vercl0k/z3-playground) 18 | -------------------------------------------------------------------------------- /examples/advanced.htm: -------------------------------------------------------------------------------- 1 | 2 | 3 | Z3Py Advanced 4 | 5 | 6 | 7 | 8 |

Advanced Topics

9 | 10 |

11 | Please send feedback, comments and/or corrections to leonardo@microsoft.com. 12 | Your comments are very valuable. 13 |

14 | 15 |

Expressions, Sorts and Declarations

16 | 17 |

In Z3, expressions, sorts and declarations are called ASTs. 18 | ASTs are directed acyclic graphs. Every expression has a sort (aka type). 19 | The method sort() retrieves the sort of an expression. 20 |

21 | 22 |
 23 | 
 24 | 

The function eq(n1, n2) returns True if n1 25 | and n2 are the same AST. This is a structural test. 26 |

27 | 28 |
 29 | 
 30 | 

The method hash() returns a hashcode for an AST node. 31 | If eq(n1, n2) returns True, then n1.hash() 32 | is equal to n2.hash(). 33 |

34 | 35 |
 36 | 
 37 | 

Z3 expressions can be divided in three basic groups: applications, 38 | quantifiers and bounded/free variables. 39 | Applications are all you need if your problems do not contain 40 | universal/existential quantifiers. Although we say Int('x') is an 41 | integer "variable", it is technically an integer constant, and internally 42 | is represented as a function application with 0 arguments. 43 | Every application is associated with a declaration and contains 44 | 0 or more arguments. The method decl() returns 45 | the declaration associated with an application. The method num_args() 46 | returns the number of arguments of an application, and arg(i) one of the arguments. 47 | The function is_expr(n) returns True 48 | if n is an expression. Similarly is_app(n) (is_func_decl(n)) 49 | returns True if n is an application (declaration). 50 |

51 | 52 |
 53 | 
 54 | 

Declarations have names, they are retrieved using the method name(). 55 | A (function) declaration has an arity, a domain and range sorts. 56 |

57 | 58 |
 59 | 
 60 | 

61 | The built-in declarations are identified using their kind. The kind 62 | is retrieved using the method kind(). The complete list of built-in declarations 63 | can be found in the file z3consts.py (z3_api.h) in the Z3 distribution. 64 |

65 | 66 |
 67 | 
 68 | 

69 | The following example demonstrates how to substitute sub-expressions in Z3 expressions. 70 |

71 | 72 |
 73 | 
 74 | 

75 | The function Const(name, sort) declares a constant (aka variable) of the given sort. 76 | For example, the functions Int(name) and Real(name) are shorthands for 77 | Const(name, IntSort()) and Const(name, RealSort()). 78 |

79 | 80 |
 81 | 
 82 | 

Arrays

83 | 84 |

As part of formulating a programme of a mathematical theory of computation 85 | McCarthy proposed a basic theory of arrays as characterized by 86 | the select-store axioms. The expression Select(a, i) returns 87 | the value stored at position i of the array a; 88 | and Store(a, i, v) returns a new array identical to a, 89 | but on position i it contains the value v. 90 | In Z3Py, we can also write Select(a, i) as a[i]. 91 |

92 | 93 |
 94 | 
 95 | 

96 | By default, Z3 assumes that arrays are extensional over select. 97 | In other words, Z3 also enforces that if two arrays agree on all positions, 98 | then the arrays are equal. 99 |

100 | 101 |

102 | Z3 also contains various extensions 103 | for operations on arrays that remain decidable and amenable 104 | to efficient saturation procedures (here efficient means, 105 | with an NP-complete satisfiability complexity). 106 | We describe these extensions in the following using a collection of examples. 107 | Additional background on these extensions is available in the 108 | paper Generalized and Efficient Array Decision Procedures. 109 |

110 | 111 |

112 | Arrays in Z3 are used to model unbounded or very large arrays. 113 | Arrays should not be used to model small finite collections of values. 114 | It is usually much more efficient to create different variables using list comprehensions. 115 |

116 | 117 |
118 | 
119 | 

Select and Store

120 | 121 | 122 |

Let us first check a basic property of arrays. 123 | Suppose A is an array of integers, then the constraints 124 | A[x] == x, Store(A, x, y) == A 125 | are satisfiable for an array that contains an index x that maps to x, 126 | and when x == y. 127 | We can solve these constraints. 128 |

129 | 130 |
131 | 
132 | 

The interpretation/solution for array variables is very similar to the one used for functions.

133 | 134 |

The problem becomes unsatisfiable/infeasible if we add the constraint x != y. 135 | 136 |

137 | 
138 | 

Constant arrays

139 | 140 |

141 | The array that maps all indices to some fixed value can be specified in Z3Py using the 142 | K(s, v) construct where s is a sort/type and v is an expression. 143 | K(s, v) returns a array that maps any value of s into v. 144 | The following example defines a constant array containing only ones. 145 |

146 | 147 |
148 | 
149 | 

Datatypes

150 | 151 |

Algebraic datatypes, known from programming languages such as ML, 152 | offer a convenient way for specifying common data structures. Records 153 | and tuples are special cases of algebraic datatypes, and so are 154 | scalars (enumeration types). But algebraic datatypes are more 155 | general. They can be used to specify finite lists, trees and other 156 | recursive structures.

157 | 158 |

159 | The following example demonstrates how to declare a List in Z3Py. It is 160 | more verbose than using the SMT 2.0 front-end, but much simpler than using 161 | the Z3 C API. It consists of two phases. 162 | First, we have to declare the new datatype, its constructors and accessors. 163 | The function Datatype('List') declares a "placeholder" that will 164 | contain the constructors and accessors declarations. The method 165 | declare(cname, (aname, sort)+) declares a constructor named 166 | cname with the given accessors. Each accessor has an associated sort 167 | or a reference to the datatypes being declared. 168 | For example, declare('cons', ('car', IntSort()), ('cdr', List)) 169 | declares the constructor named cons that builds a new List 170 | using an integer and a List. It also declares the accessors car and 171 | cdr. The accessor car extracts the integer of a cons 172 | cell, and cdr the list of a cons cell. 173 | After all constructors were declared, we use the method create() to 174 | create the actual datatype in Z3. Z3Py makes the new Z3 declarations and constants 175 | available as slots of the new object. 176 |

177 | 178 |
179 | 
180 | 

181 | The following example demonstrates how to define a Python function that 182 | given a sort creates a list of the given sort. 183 |

184 | 185 |
186 | 
187 | 

The example above demonstrates that Z3 supports operator overloading. 188 | There are several functions named cons, but they are different since they receive and/or 189 | return values of different sorts. 190 | Note that it is not necessary to use a different sort name for each instance of the sort 191 | list. That is, the expression 'List_of_%s' % sort.name() is not necessary, we 192 | use it just to provide more meaningful names. 193 |

194 | 195 |

196 | As described above enumeration types are a special case of algebraic datatypes. 197 | The following example declares an enumeration type consisting of three values: 198 | red, green and blue. 199 |

200 | 201 |
202 | 
203 | 

204 | Z3Py also provides the following shorthand for declaring enumeration sorts. 205 |

206 | 207 |
208 | 
209 | 

210 | Mutually recursive datatypes can also be declared. The only difference is that we use 211 | the function CreateDatatypes instead of the method create() to create 212 | the mutually recursive datatypes. 213 |

214 | 215 |
216 | 
217 | 

Uninterpreted Sorts

218 | 219 |

220 | Function and constant symbols in pure first-order logic are uninterpreted or free, 221 | which means that no a priori interpretation is attached. 222 | This is in contrast to arithmetic operators such as + and - 223 | that have a fixed standard interpretation. 224 | Uninterpreted functions and constants are maximally flexible; 225 | they allow any interpretation that is consistent with the constraints over the function or constant. 226 |

227 | 228 |

229 | To illustrate uninterpreted functions and constants let us introduce an (uninterpreted) sort A, 230 | and the constants x, y ranging over A. 231 | Finally let f be an uninterpreted function that takes one 232 | argument of sort A and results in a value of sort A. 233 | The example illustrates how one can force an interpretation where f applied twice to x results in x again, 234 | but f applied once to x is different from x. 235 |

236 | 237 |
238 | 
239 | 

240 | The resulting model introduces abstract values for the elements in A, 241 | because the sort A is uninterpreted. The interpretation for f in the 242 | model toggles between the two values for x and y, which are different. 243 | The expression m[A] returns the interpretation (universe) for the uninterpreted sort A 244 | in the model m. 245 |

246 | 247 |

Quantifiers

248 | 249 |

250 | Z3 is can solve quantifier-free problems containing arithmetic, bit-vector, Booleans, 251 | arrays, functions and datatypes. Z3 also accepts and can work with formulas 252 | that use quantifiers. It is no longer a decision procedure for 253 | such formulas in general (and for good reasons, as there can be 254 | no decision procedure for first-order logic). 255 |

256 | 257 |
258 | 
259 | 

260 | Nevertheless, Z3 is often able to handle formulas involving 261 | quantifiers. It uses several approaches to handle quantifiers. 262 | The most prolific approach is using pattern-based quantifier 263 | instantiation. This approach allows instantiating quantified formulas 264 | with ground terms that appear in the current search context based 265 | on pattern annotations on quantifiers. 266 | Z3 also contains a model-based quantifier instantiation 267 | component that uses a model construction to find good terms to instantiate 268 | quantifiers with; and Z3 also handles many decidable fragments. 269 |

270 | 271 |

Note that in the previous example the constants x 272 | and y were used to create quantified formulas. 273 | This is a "trick" for simplifying the construction of quantified 274 | formulas in Z3Py. Internally, these constants are replaced by 275 | bounded variables. The next example demonstrates that. The method 276 | body() retrives the quantified expression. 277 | In the resultant formula the bounded variables are free. 278 | The function Var(index, sort) creates a bounded/free variable 279 | with the given index and sort. 280 |

281 | 282 |
283 | 
284 | 

Modeling with Quantifiers

285 | 286 |

287 | Suppose we want to model an object oriented type system with single inheritance. 288 | We would need a predicate for sub-typing. Sub-typing should be a partial order, 289 | and respect single inheritance. For some built-in type constructors, 290 | such as for array_of, sub-typing should be monotone. 291 |

292 | 293 |
294 | 
295 | 

Patterns

296 | 297 |

298 | The Stanford Pascal verifier and the subsequent Simplify theorem prover pioneered 299 | the use of pattern-based quantifier instantiation. 300 | The basic idea behind pattern-based quantifier instantiation is in a sense straight-forward: 301 | Annotate a quantified formula using a pattern that contains all the bound variables. 302 | So a pattern is an expression (that does not contain binding operations, such as quantifiers) 303 | that contains variables bound by a quantifier. Then instantiate the quantifier whenever a term 304 | that matches the pattern is created during search. This is a conceptually easy starting point, 305 | but there are several subtleties that are important. 306 |

307 | 308 |

309 | In the following example, the first two options make sure that Model-based quantifier instantiation engine is disabled. 310 | We also annotate the quantified formula with the pattern f(g(x)). 311 | Since there is no ground instance of this pattern, the quantifier is not instantiated, and 312 | Z3 fails to show that the formula is unsatisfiable. 313 |

314 | 315 |
316 | 
317 | 

When the more permissive pattern g(x) is used. Z3 proves the formula 318 | to be unsatisfiable. More restrive patterns minimize the number of 319 | instantiations (and potentially improve performance), but they may 320 | also make Z3 "less complete". 321 |

322 | 323 |
324 | 
325 | 

326 | Some patterns may also create long instantiation chains. Consider the following assertion. 327 |

328 | 329 |
330 | ForAll([x, y], Implies(subtype(x, y),
331 |                        subtype(array_of(x), array_of(y))),
332 |        patterns=[subtype(x, y)])
333 | 
334 | 335 |

336 | The axiom gets instantiated whenever there is some ground term of the 337 | form subtype(s, t). The instantiation causes a fresh ground term 338 | subtype(array_of(s), array_of(t)), which enables a new 339 | instantiation. This undesirable situation is called a matching 340 | loop. Z3 uses many heuristics to break matching loops. 341 |

342 | 343 |

344 | Before elaborating on the subtleties, we should address an important 345 | first question. What defines the terms that are created during search? 346 | In the context of most SMT solvers, and of the Simplify theorem 347 | prover, terms exist as part of the input formula, they are of course 348 | also created by instantiating quantifiers, but terms are also 349 | implicitly created when equalities are asserted. The last point means 350 | that terms are considered up to congruence and pattern matching takes 351 | place modulo ground equalities. We call the matching problem 352 | E-matching. For example, if we have the following equalities: 353 |

354 | 355 |
356 | 
357 | 

358 | The terms f(a) and f(g(b)) are equal modulo the 359 | equalities. The pattern f(g(x)) can be matched and x bound to b 360 | and the equality f(g(b)) == b is deduced. 361 |

362 | 363 |

364 | While E-matching is an NP-complete problem, the main sources of overhead in larger verification 365 | problems comes from matching thousands of patterns in the context of an evolving set of terms and 366 | equalities. Z3 integrates an efficient E-matching engine using term indexing techniques. 367 |

368 | 369 |

Multi-patterns

370 | 371 |

372 | In some cases, there is no pattern that contains all bound variables 373 | and does not contain interpreted symbols. In these cases, we use 374 | multi-patterns. In the following example, the quantified formula 375 | states that f is injective. This quantified formula is annotated with 376 | the multi-pattern MultiPattern(f(x), f(y)). 377 |

378 | 379 |
380 | 
381 | 

382 | The quantified formula is instantiated for every pair of occurrences 383 | of f. A simple trick allows formulating injectivity of f in such a way 384 | that only a linear number of instantiations is required. The trick is 385 | to realize that f is injective if and only if it has a partial 386 | inverse. 387 |

388 | 389 |
390 | 
391 | 

Other attributes

392 | 393 |

394 | In Z3Py, the following additional attributes are supported: qid (quantifier identifier 395 | for debugging), weight (hint to the quantifier instantiation module: "more weight equals less instances"), 396 | no_patterns (expressions that should not be used as patterns, skid (identifier 397 | prefix used to create skolem constants/functions. 398 |

399 | 400 |

Multiple Solvers

401 | 402 |

In Z3Py and Z3 4.0 multiple solvers can be simultaneously used. 403 | It is also very easy to copy assertions/formulas from one solver to another. 404 |

405 | 406 |
407 | 
408 | 

Unsat Cores and Soft Constraints

409 | 410 |

Z3Py also supports unsat core extraction. The basic idea is to use 411 | assumptions, that is, auxiliary propositional variables that we want to track. 412 | Assumptions are also available in the Z3 SMT 2.0 frontend, and in other Z3 front-ends. 413 | They are used to extract unsatisfiable cores. They may be also used to "retract" 414 | constraints. Note that, assumptions are not really soft constraints, but they can be used to implement them. 415 |

416 | 417 |
418 | 
419 | 

The example above also shows that a Boolean variable (p1) can be used to track 420 | more than one constraint. Note that Z3 does not guarantee that the unsat cores are minimal. 421 |

422 | 423 |

Formatter

424 | 425 |

426 | Z3Py uses a formatter (aka pretty printer) for displaying formulas, expressions, solvers, and other 427 | Z3 objects. The formatter supports many configuration options. 428 | The command set_option(html_mode=False) makes all formulas and expressions to be 429 | displayed in Z3Py notation. 430 |

431 | 432 |
433 | 
434 | 

By default, Z3Py will truncate the output if the object being displayed is too big. 435 | Z3Py uses … to denote the output is truncated. 436 | The following configuration options can be set to control the behavior of Z3Py's formatter: 437 |

438 | 439 |
    440 |
  • max_depth Maximal expression depth. Deep expressions are replaced with ….
  • 441 |
  • max_args Maximal number of arguments to display per node.
  • 442 |
  • rational_to_decimal Display rationals as decimals if True.
  • 443 |
  • precision Maximal number of decimal places for numbers being displayed in decimal notation.
  • 444 |
  • max_lines Maximal number of lines to be displayed.
  • 445 |
  • max_width Maximal line width (this is a suggestion to Z3Py).
  • 446 |
  • max_indent Maximal indentation.
  • 447 |
448 | 449 |
450 | 
451 | 
452 | 
453 | 


--------------------------------------------------------------------------------
/examples/arith.1.py:
--------------------------------------------------------------------------------
1 | x = Real('x')
2 | y = Int('y')
3 | a, b, c = Reals('a b c')
4 | s, r = Ints('s r')
5 | print x + y + 1 + (a + s)
6 | print ToReal(y) + c
7 | 


--------------------------------------------------------------------------------
/examples/arith.2.py:
--------------------------------------------------------------------------------
1 | a, b, c = Ints('a b c')
2 | d, e = Reals('d e')
3 | solve(a > b + 2,
4 |       a == 2*c + 10,
5 |       c + b <= 1000,
6 |       d >= e)
7 | 


--------------------------------------------------------------------------------
/examples/arith.3.py:
--------------------------------------------------------------------------------
 1 | x, y = Reals('x y')
 2 | # Put expression in sum-of-monomials form
 3 | t = simplify((x + y)**3, som=True)
 4 | print t
 5 | # Use power operator
 6 | t = simplify(t, mul_to_power=True)
 7 | print t
 8 | 
 9 | 
10 | 


--------------------------------------------------------------------------------
/examples/arith.4.py:
--------------------------------------------------------------------------------
 1 | x, y = Reals('x y')
 2 | # Using Z3 native option names
 3 | print simplify(x == y + 2, ':arith-lhs', True)
 4 | # Using Z3Py option names
 5 | print simplify(x == y + 2, arith_lhs=True)
 6 | 
 7 | print "\nAll available options:"
 8 | help_simplify()
 9 | 
10 | 


--------------------------------------------------------------------------------
/examples/arith.5.py:
--------------------------------------------------------------------------------
1 | x, y = Reals('x y')
2 | solve(x + 10000000000000000000000 == y, y > 20000000000000000)
3 | 
4 | print Sqrt(2) + Sqrt(3)
5 | print simplify(Sqrt(2) + Sqrt(3))
6 | print simplify(Sqrt(2) + Sqrt(3)).sexpr()
7 | # The sexpr() method is available for any Z3 expression
8 | print (x + Sqrt(y) * 2).sexpr()
9 | 


--------------------------------------------------------------------------------
/examples/array.1.py:
--------------------------------------------------------------------------------
 1 | # Use I as an alias for IntSort()
 2 | I = IntSort()
 3 | # A is an array from integer to integer
 4 | A = Array('A', I, I)
 5 | x = Int('x')
 6 | print A[x]
 7 | print Select(A, x)
 8 | print Store(A, x, 10)
 9 | print simplify(Select(Store(A, 2, x+1), 2))
10 | 
11 | 


--------------------------------------------------------------------------------
/examples/array.2.py:
--------------------------------------------------------------------------------
 1 | # We want an array with 3 elements.
 2 | # 1. Bad solution
 3 | X = Array('x', IntSort(), IntSort())
 4 | # Example using the array
 5 | print X[0] + X[1] + X[2] >=0
 6 | 
 7 | # 2. More efficient solution
 8 | X = IntVector('x', 3)
 9 | print X[0] + X[1] + X[2] >= 0
10 | print Sum(X) >= 0
11 | 


--------------------------------------------------------------------------------
/examples/array.3.py:
--------------------------------------------------------------------------------
1 | A = Array('A', IntSort(), IntSort())
2 | x, y = Ints('x y')
3 | solve(A[x] == x, Store(A, x, y) == A)
4 | 
5 | 


--------------------------------------------------------------------------------
/examples/array.4.py:
--------------------------------------------------------------------------------
1 | A = Array('A', IntSort(), IntSort())
2 | x, y = Ints('x y')
3 | solve(A[x] == x, Store(A, x, y) == A, x != y)
4 | 
5 | 


--------------------------------------------------------------------------------
/examples/array.5.py:
--------------------------------------------------------------------------------
1 | AllOne = K(IntSort(), 1)
2 | a, i = Ints('a i')
3 | solve(a == AllOne[i])
4 | # The following constraints do not have a solution
5 | solve(a == AllOne[i], a != 1)
6 | 


--------------------------------------------------------------------------------
/examples/array.py:
--------------------------------------------------------------------------------
 1 | from z3 import *
 2 | 
 3 | # Create a new solver.
 4 | s = Solver()
 5 | 
 6 | # Create the variables.
 7 | a = Array('a', IntSort(), IntSort())
 8 | i1, i2, j, v1, v2 = Ints('i1 i2 j v1 v2')
 9 | 
10 | # Add assertions.
11 | s.add(i1 == j,
12 |       i1 != i2,
13 |       Select(a, j) == v1,
14 |       Select(Store(Store(a, i1, v1), i2, v2), j) != a[j])
15 | 
16 | # Check satisfiability.
17 | print s.check()
18 | 


--------------------------------------------------------------------------------
/examples/bintree.py:
--------------------------------------------------------------------------------
 1 | from z3 import *
 2 | 
 3 | # Create a solver.
 4 | s = Solver()
 5 | 
 6 | # Create the binary tree datatype.
 7 | BinaryTree = Datatype('BinaryTree')
 8 | BinaryTree.declare('leaf', ('value', IntSort()))
 9 | BinaryTree.declare('node', ('value', IntSort()), ('left', BinaryTree), ('right', BinaryTree))
10 | BinaryTree = BinaryTree.create()
11 | 
12 | # Shorthands.
13 | leaf = BinaryTree.leaf
14 | node = BinaryTree.node
15 | value = BinaryTree.value
16 | left = BinaryTree.left
17 | right = BinaryTree.right
18 | 
19 | # Create an instance of a binary tree.
20 | t = node (2, (leaf(0)), (leaf(1)))
21 | 
22 | print 'Values:'
23 | print simplify(value(t))
24 | print simplify(value(left(t)))
25 | print ''
26 | 
27 | ## print 'Constructors:'
28 | ## print BinaryTree.constructor(0)
29 | ## print BinaryTree.constructor(1)
30 | ## print ''
31 | 
32 | ## print 'Accessors:'
33 | ## print BinaryTree.accessor(0, 0)
34 | ## print BinaryTree.accessor(1, 0)
35 | ## print BinaryTree.accessor(1, 1)
36 | ## print BinaryTree.accessor(1, 2)
37 | ## print ''
38 | 
39 | ## lv = BinaryTree.accessor(0, 0)
40 | ## nv = BinaryTree.accessor(1, 0)
41 | 
42 | ## def value(t):
43 | ##    if is_true(simplify(BinaryTree.is_leaf(t))):
44 | ##        return lv(t)
45 | ##    else:
46 | ##        return nv(t)
47 | 
48 | ## print 'Values:'
49 | ## print simplify(value(t))
50 | ## print simplify(value(left(t)))
51 | ## print ''
52 | 
53 | ## value = lambda t: If(is_true(simplify(BinaryTree.is_leaf(t))), lv(t), nv(t))
54 | 
55 | ## print 'Values:'
56 | ## print simplify(value(t))
57 | ## print simplify(value(left(t)))
58 | ## print ''
59 | 


--------------------------------------------------------------------------------
/examples/bit.1.py:
--------------------------------------------------------------------------------
 1 | x      = BitVec('x', 32)
 2 | powers = [ 2**i for i in range(32) ]
 3 | fast   = And(x != 0, x & (x - 1) == 0)
 4 | slow   = Or([ x == p for p in powers ])
 5 | print fast
 6 | prove(fast == slow)
 7 | 
 8 | print "trying to prove buggy version..."
 9 | fast   = x & (x - 1) == 0
10 | prove(fast == slow)
11 | 


--------------------------------------------------------------------------------
/examples/bit.2.py:
--------------------------------------------------------------------------------
 1 | x      = BitVec('x', 32)
 2 | y      = BitVec('y', 32)
 3 | 
 4 | # Claim: (x ^ y) < 0 iff x and y have opposite signs
 5 | trick  = (x ^ y) < 0
 6 | 
 7 | # Naive way to check if x and y have opposite signs
 8 | opposite = Or(And(x < 0, y >= 0),
 9 |               And(x >= 0, y < 0))
10 | 
11 | prove(trick == opposite)
12 | 


--------------------------------------------------------------------------------
/examples/bitvec.1.py:
--------------------------------------------------------------------------------
 1 | x = BitVec('x', 16)
 2 | y = BitVec('y', 16)
 3 | print x + 2
 4 | # Internal representation
 5 | print (x + 2).sexpr()
 6 | 
 7 | # -1 is equal to 65535 for 16-bit integers 
 8 | print simplify(x + y - 1)
 9 | 
10 | # Creating bit-vector constants
11 | a = BitVecVal(-1, 16)
12 | b = BitVecVal(65535, 16)
13 | print simplify(a == b)
14 | 
15 | a = BitVecVal(-1, 32)
16 | b = BitVecVal(65535, 32)
17 | # -1 is not equal to 65535 for 32-bit integers 
18 | print simplify(a == b)
19 | 
20 | 


--------------------------------------------------------------------------------
/examples/bitvec.2.py:
--------------------------------------------------------------------------------
 1 | # Create to bit-vectors of size 32
 2 | x, y = BitVecs('x y', 32)
 3 | 
 4 | solve(x + y == 2, x > 0, y > 0)
 5 | 
 6 | # Bit-wise operators
 7 | # & bit-wise and
 8 | # | bit-wise or
 9 | # ~ bit-wise not
10 | solve(x & y == ~y)
11 | 
12 | solve(x < 0)
13 | 
14 | # using unsigned version of < 
15 | solve(ULT(x, 0))
16 | 


--------------------------------------------------------------------------------
/examples/bitvec.3.py:
--------------------------------------------------------------------------------
1 | # Create to bit-vectors of size 32
2 | x, y = BitVecs('x y', 32)
3 | 
4 | solve(x >> 2 == 3)
5 | 
6 | solve(x << 2 == 3)
7 | 
8 | solve(x << 2 == 24)
9 | 


--------------------------------------------------------------------------------
/examples/circuit.py:
--------------------------------------------------------------------------------
 1 | from z3 import *
 2 | 
 3 | s = Solver()
 4 | 
 5 | i = BitVec('in', 32)
 6 | 
 7 | F = Function('F', BitVecSort(32), BitVecSort(32))
 8 | G = Function('G', BitVecSort(32), BitVecSort(32))
 9 | H = Function('H', BitVecSort(32), BitVecSort(32))
10 | K = Function('K', BitVecSort(32), BitVecSort(32))
11 | C = Function('C', BitVecSort(32), BoolSort())
12 | D = Function('D', BitVecSort(32), BitVecSort(32))
13 | L1, L2, L3, L4, L5 = Consts('L1 L2 L3 L4 L5', BitVecSort(32))
14 | L1p, L3p, L5p = Consts('L1p L3p L5p', BitVecSort(32))
15 | L2p = Const('L2p', BoolSort())
16 | 
17 | s.add(L1 == F(i),
18 |       L2 == L1,
19 |       L3 == K(G(L1)),
20 |       L4 == H(L1),
21 |       L5 == If(C(L2), L3, D(L4)))
22 | s.add(L1p == F(i),
23 |       L2p == C(L1p),
24 |       L3p == If(C(L1p), G(L1p), H(L1p)),
25 |       L5p == If(L2p, K(L3p), D(L3p)))
26 | s.add(L5 != L5p)
27 | 
28 | print s.check()
29 | 


--------------------------------------------------------------------------------
/examples/comment.py:
--------------------------------------------------------------------------------
1 | # This is a comment
2 | x = Real('x') # comment: creating x
3 | print x**2 + 2*x + 2  # comment: printing polynomial
4 | 


--------------------------------------------------------------------------------
/examples/datatype.1.py:
--------------------------------------------------------------------------------
 1 | # Declare a List of integers
 2 | List = Datatype('List')
 3 | # Constructor cons: (Int, List) -> List
 4 | List.declare('cons', ('car', IntSort()), ('cdr', List))
 5 | # Constructor nil: List
 6 | List.declare('nil')
 7 | # Create the datatype
 8 | List = List.create()
 9 | print is_sort(List)
10 | cons = List.cons
11 | car  = List.car
12 | cdr  = List.cdr
13 | nil  = List.nil
14 | # cons, car and cdr are function declarations, and nil a constant
15 | print is_func_decl(cons)
16 | print is_expr(nil)
17 | 
18 | l1 = cons(10, cons(20, nil))
19 | print l1
20 | print simplify(cdr(l1))
21 | print simplify(car(l1))
22 | print simplify(l1 == nil)
23 | 


--------------------------------------------------------------------------------
/examples/datatype.2.py:
--------------------------------------------------------------------------------
 1 | def DeclareList(sort):
 2 |     List = Datatype('List_of_%s' % sort.name())
 3 |     List.declare('cons', ('car', sort), ('cdr', List))
 4 |     List.declare('nil')
 5 |     return List.create()
 6 | 
 7 | IntList     = DeclareList(IntSort())
 8 | RealList    = DeclareList(RealSort())
 9 | IntListList = DeclareList(IntList)
10 | 
11 | l1 = IntList.cons(10, IntList.nil)
12 | print l1
13 | print IntListList.cons(l1, IntListList.cons(l1, IntListList.nil))
14 | print RealList.cons("1/3", RealList.nil)
15 | 
16 | print l1.sort()
17 | 


--------------------------------------------------------------------------------
/examples/datatype.3.py:
--------------------------------------------------------------------------------
 1 | Color = Datatype('Color')
 2 | Color.declare('red')
 3 | Color.declare('green')
 4 | Color.declare('blue')
 5 | Color = Color.create()
 6 | 
 7 | print is_expr(Color.green)
 8 | print Color.green == Color.blue
 9 | print simplify(Color.green == Color.blue)
10 | 
11 | # Let c be a constant of sort Color
12 | c = Const('c', Color)
13 | # Then, c must be red, green or blue
14 | prove(Or(c == Color.green, 
15 |          c == Color.blue,
16 |          c == Color.red))
17 | 


--------------------------------------------------------------------------------
/examples/datatype.4.py:
--------------------------------------------------------------------------------
1 | Color, (red, green, blue) = EnumSort('Color', ('red', 'green', 'blue'))
2 | 
3 | print green == blue
4 | print simplify(green == blue)
5 | 
6 | c = Const('c', Color)
7 | solve(c != green, c != blue)
8 | 


--------------------------------------------------------------------------------
/examples/datatype.5.py:
--------------------------------------------------------------------------------
 1 | TreeList = Datatype('TreeList')
 2 | Tree     = Datatype('Tree')
 3 | Tree.declare('leaf', ('val', IntSort()))
 4 | Tree.declare('node', ('left', TreeList), ('right', TreeList))
 5 | TreeList.declare('nil')
 6 | TreeList.declare('cons', ('car', Tree), ('cdr', TreeList))
 7 | 
 8 | Tree, TreeList = CreateDatatypes(Tree, TreeList)
 9 | 
10 | t1  = Tree.leaf(10)
11 | tl1 = TreeList.cons(t1, TreeList.nil)
12 | t2  = Tree.node(tl1, TreeList.nil)
13 | print t2
14 | print simplify(Tree.val(t1))
15 | 
16 | t1, t2, t3 = Consts('t1 t2 t3', TreeList)
17 | 
18 | solve(Distinct(t1, t2, t3))
19 | 


--------------------------------------------------------------------------------
/examples/euf1.py:
--------------------------------------------------------------------------------
 1 | from z3 import *
 2 | 
 3 | # Create a new solver.
 4 | s = Solver()
 5 | 
 6 | # Define the uninterpreted function f and constants x and y.
 7 | f = Function('f', IntSort(), IntSort())
 8 | x, y = Ints('x y')
 9 | 
10 | # Add assertions.
11 | s.add(f(x) == f(y), x != y)
12 | 
13 | # Check satisfiability.
14 | print s.check()
15 | 


--------------------------------------------------------------------------------
/examples/euf2.py:
--------------------------------------------------------------------------------
 1 | from z3 import *
 2 | 
 3 | # Create a new solver.
 4 | s = Solver()
 5 | 
 6 | # Define the uninterpreted function f and constant a.
 7 | f = Function('f', IntSort(), IntSort())
 8 | a = Int('a')
 9 | 
10 | # Add assertions.
11 | s.add(f(f(f(a))) == a, f(f(f(f(f(a))))) == a, f(a) != a)
12 | 
13 | # Check satisfiability.
14 | print s.check()
15 | 


--------------------------------------------------------------------------------
/examples/euf3.py:
--------------------------------------------------------------------------------
 1 | from z3 import *
 2 | 
 3 | # Create a new solver.
 4 | s = Solver()
 5 | 
 6 | # Create an uninterpreted sort.
 7 | A = DeclareSort('A')
 8 | 
 9 | # Define the uninterpreted function f and constants a and b.
10 | f = Function('f', A, A, A)
11 | a, b = Consts('a b', A)
12 | 
13 | # Add assertions.
14 | s.add(f(a, b) == a, f(f(a, b), b) != a)
15 | 
16 | # Check satisfiability.
17 | print s.check()
18 | 


--------------------------------------------------------------------------------
/examples/expr.1.py:
--------------------------------------------------------------------------------
1 | x = Int('x')
2 | y = Real('y')
3 | print (x + 1).sort()
4 | print (y + 1).sort()
5 | print (x >= 2).sort()
6 | 


--------------------------------------------------------------------------------
/examples/expr.2.py:
--------------------------------------------------------------------------------
 1 | x, y = Ints('x y')
 2 | print eq(x + y, x + y)
 3 | print eq(x + y, y + x)
 4 | n = x + y
 5 | print eq(n, x + y)
 6 | # x2 is eq to x
 7 | x2 = Int('x') 
 8 | print eq(x, x2)
 9 | # the integer variable x is not equal to 
10 | # the real variable x
11 | print eq(Int('x'), Real('x'))
12 | 


--------------------------------------------------------------------------------
/examples/expr.3.py:
--------------------------------------------------------------------------------
1 | x = Int('x')
2 | print (x + 1).hash()
3 | print (1 + x).hash()
4 | print x.sort().hash()
5 | 


--------------------------------------------------------------------------------
/examples/expr.4.py:
--------------------------------------------------------------------------------
1 | x = Int('x')
2 | print "is expression: ", is_expr(x)
3 | n = x + 1
4 | print "is application:", is_app(n)
5 | print "decl:          ", n.decl()
6 | print "num args:      ", n.num_args()
7 | for i in range(n.num_args()):
8 |     print "arg(", i, ") ->", n.arg(i)
9 | 


--------------------------------------------------------------------------------
/examples/expr.5.py:
--------------------------------------------------------------------------------
 1 | x   = Int('x')
 2 | x_d = x.decl()
 3 | print "is_expr(x_d):     ", is_expr(x_d)
 4 | print "is_func_decl(x_d):", is_func_decl(x_d)
 5 | print "x_d.name():       ", x_d.name()
 6 | print "x_d.range():      ", x_d.range()
 7 | print "x_d.arity():      ", x_d.arity()
 8 | # x_d() creates an application with 0 arguments using x_d.
 9 | print "eq(x_d(), x):     ", eq(x_d(), x)
10 | print "\n"
11 | # f is a function from (Int, Real) to Bool
12 | f   = Function('f', IntSort(), RealSort(), BoolSort())
13 | print "f.name():         ", f.name()
14 | print "f.range():        ", f.range()
15 | print "f.arity():        ", f.arity()
16 | for i in range(f.arity()):
17 |     print "domain(", i, "): ", f.domain(i)
18 | # f(x, x) creates an application with 2 arguments using f.
19 | print f(x, x)
20 | print eq(f(x, x).decl(), f)
21 | 


--------------------------------------------------------------------------------
/examples/expr.6.py:
--------------------------------------------------------------------------------
1 | x, y = Ints('x y')
2 | print (x + y).decl().kind() == Z3_OP_ADD
3 | print (x + y).decl().kind() == Z3_OP_SUB
4 | 


--------------------------------------------------------------------------------
/examples/expr.7.py:
--------------------------------------------------------------------------------
1 | x, y = Ints('x y')
2 | f    = Function('f', IntSort(), IntSort(), IntSort())
3 | g    = Function('g', IntSort(), IntSort())
4 | n    = f(f(g(x), g(g(x))), g(g(y)))
5 | print n
6 | # substitute g(g(x)) with y and g(y) with x + 1
7 | print substitute(n, (g(g(x)), y), (g(y), x + 1))
8 | 


--------------------------------------------------------------------------------
/examples/expr.8.py:
--------------------------------------------------------------------------------
1 | x = Const('x', IntSort())
2 | print eq(x, Int('x'))
3 | 
4 | a, b = Consts('a b', BoolSort())
5 | print And(a, b)
6 | 


--------------------------------------------------------------------------------
/examples/fixedpoint.1.py:
--------------------------------------------------------------------------------
 1 | fp = Fixedpoint()
 2 | 
 3 | a, b, c = Bools('a b c')
 4 | 
 5 | fp.register_relation(a.decl(), b.decl(), c.decl())
 6 | fp.rule(a,b)
 7 | fp.rule(b,c)
 8 | fp.set(engine='datalog')
 9 | 
10 | print "current set of rules\n", fp
11 | print fp.query(a)
12 | 
13 | fp.fact(c)
14 | print "updated set of rules\n", fp
15 | print fp.query(a)
16 | print fp.get_answer()
17 | 


--------------------------------------------------------------------------------
/examples/fixedpoint.10.py:
--------------------------------------------------------------------------------
 1 | 
 2 | # let max max2 x y z = max2 (max2 x y) z
 3 | # let f x y = if x > y then x else y
 4 | # assert (f (max f x y z) x) = (max f x y z)
 5 | 
 6 | 
 7 | Expr = Datatype('Expr')
 8 | Expr.declare('Max')
 9 | Expr.declare('f')
10 | Expr.declare('I', ('i', IntSort()))
11 | Expr.declare('App', ('fn',Expr),('arg',Expr))
12 | Expr = Expr.create()
13 | Max  = Expr.Max
14 | I    = Expr.I
15 | App  = Expr.App
16 | f    = Expr.f
17 | Eval = Function('Eval',Expr,Expr,Expr,BoolSort())
18 | 
19 | x   = Const('x',Expr)
20 | y   = Const('y',Expr)
21 | z   = Const('z',Expr)
22 | r1  = Const('r1',Expr)
23 | r2  = Const('r2',Expr)
24 | max = Const('max',Expr)
25 | xi  = Const('xi',IntSort())
26 | yi  = Const('yi',IntSort())
27 | 
28 | fp = Fixedpoint()
29 | fp.register_relation(Eval)
30 | fp.declare_var(x,y,z,r1,r2,max,xi,yi)
31 | 
32 | # Max max x y z = max (max x y) z
33 | fp.rule(Eval(App(App(App(Max,max),x),y), z, r2),
34 | 	[Eval(App(max,x),y,r1),
35 | 	 Eval(App(max,r1),z,r2)])
36 | 
37 | # f x y = x if x >= y
38 | # f x y = y if x < y
39 | fp.rule(Eval(App(f,I(xi)),I(yi),I(xi)),xi >= yi)
40 | fp.rule(Eval(App(f,I(xi)),I(yi),I(yi)),xi < yi)
41 | 
42 | print fp.query(And(Eval(App(App(App(Max,f),x),y),z,r1),
43 | 		   Eval(App(f,x),r1,r2),
44 | 		   r1 != r2))
45 | 
46 | print fp.get_answer()
47 | 


--------------------------------------------------------------------------------
/examples/fixedpoint.2.py:
--------------------------------------------------------------------------------
 1 | 
 2 | fp = Fixedpoint()
 3 | 
 4 | a, b, c = Bools('a b c')
 5 | 
 6 | fp.register_relation(a.decl(), b.decl(), c.decl())
 7 | fp.rule(a,b)
 8 | fp.rule(b,c)
 9 | fp.fact(c)
10 | fp.set(generate_explanations=True, engine='datalog')
11 | print fp.query(a)
12 | print fp.get_answer()
13 | 
14 | 


--------------------------------------------------------------------------------
/examples/fixedpoint.3.py:
--------------------------------------------------------------------------------
 1 | fp = Fixedpoint()
 2 | fp.set(engine='datalog')
 3 | 
 4 | s = BitVecSort(3)
 5 | edge = Function('edge', s, s, BoolSort())
 6 | path = Function('path', s, s, BoolSort())
 7 | a = Const('a',s)
 8 | b = Const('b',s)
 9 | c = Const('c',s)
10 | 
11 | fp.register_relation(path,edge)
12 | fp.declare_var(a,b,c)
13 | fp.rule(path(a,b), edge(a,b))
14 | fp.rule(path(a,c), [edge(a,b),path(b,c)])
15 | 
16 | v1 = BitVecVal(1,s)
17 | v2 = BitVecVal(2,s)
18 | v3 = BitVecVal(3,s)
19 | v4 = BitVecVal(4,s)
20 | 
21 | fp.fact(edge(v1,v2))
22 | fp.fact(edge(v1,v3))
23 | fp.fact(edge(v2,v4))
24 | 
25 | print "current set of rules", fp
26 | 
27 | 
28 | print fp.query(path(v1,v4)), "yes we can reach v4 from v1"
29 | 
30 | print fp.query(path(v3,v4)), "no we cannot reach v4 from v3"
31 | 
32 | 


--------------------------------------------------------------------------------
/examples/fixedpoint.4.py:
--------------------------------------------------------------------------------
  1 | 
  2 | class Car():
  3 |     def __init__(self, is_vertical, base_pos, length, start, color):
  4 | 	self.is_vertical = is_vertical
  5 | 	self.base = base_pos
  6 | 	self.length = length
  7 | 	self.start = start
  8 | 	self.color = color
  9 | 
 10 |     def __eq__(self, other):
 11 | 	return self.color == other.color
 12 | 
 13 |     def __ne__(self, other):
 14 | 	return self.color != other.color
 15 | 
 16 | dimension = 6
 17 | 
 18 | red_car = Car(False, 2, 2, 3, "red")
 19 | cars = [
 20 |     Car(True, 0, 3, 0, 'yellow'),
 21 |     Car(False, 3, 3, 0, 'blue'),
 22 |     Car(False, 5, 2, 0, "brown"),
 23 |     Car(False, 0, 2, 1, "lgreen"),
 24 |     Car(True,  1, 2, 1, "light blue"),
 25 |     Car(True,  2, 2, 1, "pink"),
 26 |     Car(True,  2, 2, 4, "dark green"),
 27 |     red_car,
 28 |     Car(True,  3, 2, 3, "purple"),
 29 |     Car(False, 5, 2, 3, "light yellow"),
 30 |     Car(True,  4, 2, 0, "orange"),
 31 |     Car(False, 4, 2, 4, "black"),
 32 |     Car(True,  5, 3, 1, "light purple")
 33 |     ]
 34 | 
 35 | num_cars = len(cars)
 36 | B = BoolSort()
 37 | bv3 = BitVecSort(3)
 38 | 
 39 | 
 40 | state = Function('state', [ bv3 for c in cars] + [B])
 41 | 
 42 | def num(i):
 43 |     return BitVecVal(i,bv3)
 44 | 
 45 | def bound(i):
 46 |     return Const(cars[i].color, bv3)
 47 | 
 48 | fp = Fixedpoint()
 49 | fp.set(generate_explanations=True)
 50 | fp.declare_var([bound(i) for i in range(num_cars)])
 51 | fp.register_relation(state)
 52 | 
 53 | def mk_state(car, value):
 54 |     return state([ (num(value) if (cars[i] == car) else bound(i))
 55 | 		   for i in range(num_cars)])
 56 | 
 57 | def mk_transition(row, col, i0, j, car0):
 58 |     body = [mk_state(car0, i0)]
 59 |     for index in range(num_cars):
 60 | 	car = cars[index]
 61 | 	if car0 != car:
 62 | 	    if car.is_vertical and car.base == col:
 63 | 		for i in range(dimension):
 64 | 		    if i <= row and row < i + car.length and i + car.length <= dimension:
 65 | 			   body += [bound(index) != num(i)]
 66 | 	    if car.base == row and not car.is_vertical:
 67 | 		for i in range(dimension):
 68 | 		    if i <= col and col < i + car.length and i + car.length <= dimension:
 69 | 			   body += [bound(index) != num(i)]
 70 | 
 71 |     s = "%s %d->%d" % (car0.color, i0, j)
 72 | 			
 73 |     fp.rule(mk_state(car0, j), body, s)
 74 |     
 75 | 
 76 | def move_down(i, car):
 77 |     free_row = i + car.length
 78 |     if free_row < dimension:
 79 | 	mk_transition(free_row, car.base, i, i + 1, car)
 80 |             
 81 | 
 82 | def move_up(i, car):
 83 |     free_row = i  - 1
 84 |     if 0 <= free_row and i + car.length <= dimension:
 85 | 	mk_transition(free_row, car.base, i, i - 1, car)
 86 | 
 87 | def move_left(i, car):
 88 |     free_col = i - 1;
 89 |     if 0 <= free_col and i + car.length <= dimension:
 90 | 	mk_transition(car.base, free_col, i, i - 1, car)
 91 | 	
 92 | 
 93 | def move_right(i, car):
 94 |     free_col = car.length + i
 95 |     if free_col < dimension:
 96 | 	mk_transition(car.base, free_col, i, i + 1, car)
 97 | 	
 98 | 
 99 | # Initial state:
100 | fp.fact(state([num(cars[i].start) for i in range(num_cars)]))
101 | 
102 | # Transitions:
103 | for car in cars:
104 |     for i in range(dimension):
105 | 	if car.is_vertical:
106 | 	    move_down(i, car)
107 | 	    move_up(i, car)
108 | 	else:
109 | 	    move_left(i, car)
110 | 	    move_right(i, car)
111 |     
112 | 
113 | def get_instructions(ans):
114 |     lastAnd = ans.arg(0).children()[-1]
115 |     trace = lastAnd.children()[1]
116 |     while trace.num_args() > 0:
117 | 	print trace.decl()
118 | 	trace = trace.children()[-1]
119 | 
120 | print fp
121 | 
122 | goal = state([ (num(4) if cars[i] == red_car else bound(i))
123 | 	       for i in range(num_cars)])
124 | fp.query(goal)
125 | 
126 | get_instructions(fp.get_answer())
127 |     
128 | 
129 | 


--------------------------------------------------------------------------------
/examples/fixedpoint.5.py:
--------------------------------------------------------------------------------
 1 | 
 2 | I  = IntSort()
 3 | B  = BoolSort()
 4 | l0 = Function('l0',I,I,B)
 5 | l1 = Function('l1',I,I,B)
 6 | 
 7 | s = Fixedpoint()
 8 | s.set(engine='datalog',compile_with_widening=True,
 9 |       unbound_compressor=False)
10 | 
11 | s.register_relation(l0,l1)
12 | s.set_predicate_representation(l0, 'interval_relation', 'bound_relation')
13 | s.set_predicate_representation(l1, 'interval_relation', 'bound_relation')
14 | 
15 | m, x, y = Ints('m x y')
16 | 
17 | s.declare_var(m, x, y)
18 | s.rule(l0(0,m),   0 < m)
19 | s.rule(l0(x+1,m), [l0(x,m), x < m])
20 | s.rule(l1(x,m),   [l0(x,m), m <= x])
21 | 
22 | print "At l0 we learn that x, y are non-negative:"
23 | print s.query(l0(x,y))
24 | print s.get_answer()
25 | 
26 | print "At l1 we learn that x <= y and both x and y are bigger than 0:"
27 | print s.query(l1(x,y))
28 | print s.get_answer()
29 | 
30 | 
31 | print "The state where x < y is not reachable"
32 | print s.query(And(l1(x,y), x < y))
33 | 


--------------------------------------------------------------------------------
/examples/fixedpoint.8.py:
--------------------------------------------------------------------------------
 1 | 
 2 | mc = Function('mc', IntSort(), IntSort(), BoolSort())
 3 | n, m, p = Ints('n m p')
 4 | 
 5 | fp = Fixedpoint()
 6 | 
 7 | fp.declare_var(n,m)
 8 | fp.register_relation(mc)
 9 | 
10 | fp.rule(mc(m, m-10), m > 100)
11 | fp.rule(mc(m, n), [m <= 100, mc(m+11,p),mc(p,n)])
12 |     
13 | print fp.query(And(mc(m,n),n < 90))
14 | print fp.get_answer()
15 | 
16 | print fp.query(And(mc(m,n),n < 91))
17 | print fp.get_answer()
18 | 
19 | print fp.query(And(mc(m,n),n < 92))
20 | print fp.get_answer()
21 | 


--------------------------------------------------------------------------------
/examples/fixedpoint.9.py:
--------------------------------------------------------------------------------
  1 | set_option(relevancy=0,verbose=1)
  2 | 
  3 | def flatten(l):
  4 |     return [s for t in l for s in t]
  5 | 
  6 | 
  7 | class TransitionSystem():
  8 |     def __init__(self, initial, transitions, vars1):
  9 | 	self.fp = Fixedpoint()        
 10 | 	self.initial     = initial
 11 | 	self.transitions = transitions
 12 | 	self.vars1 = vars1
 13 | 
 14 |     def declare_rels(self):
 15 | 	B = BoolSort()
 16 | 	var_sorts   = [ v.sort() for v in self.vars1 ]
 17 | 	state_sorts = var_sorts
 18 | 	self.state_vals = [ v for v in self.vars1 ]
 19 | 	self.state_sorts  = state_sorts
 20 | 	self.var_sorts = var_sorts
 21 | 	self.state  = Function('state', state_sorts + [ B ])
 22 | 	self.step   = Function('step',  state_sorts + state_sorts + [ B ])
 23 | 	self.fp.register_relation(self.state)
 24 | 	self.fp.register_relation(self.step)
 25 | 
 26 | # Set of reachable states are transitive closure of step.
 27 | 
 28 |     def state0(self):
 29 | 	idx = range(len(self.state_sorts))
 30 | 	return self.state([Var(i,self.state_sorts[i]) for i in idx])
 31 | 	
 32 |     def state1(self):
 33 | 	n = len(self.state_sorts)
 34 | 	return self.state([Var(i+n, self.state_sorts[i]) for i in range(n)])
 35 | 
 36 |     def rho(self):
 37 | 	n = len(self.state_sorts)
 38 | 	args1 = [ Var(i,self.state_sorts[i]) for i in range(n) ]
 39 | 	args2 = [ Var(i+n,self.state_sorts[i]) for i in range(n) ]
 40 | 	args = args1 + args2 
 41 | 	return self.step(args)
 42 | 
 43 |     def declare_reachability(self):
 44 | 	self.fp.rule(self.state1(), [self.state0(), self.rho()])
 45 | 
 46 | 
 47 | # Define transition relation
 48 | 
 49 |     def abstract(self, e):
 50 | 	n = len(self.state_sorts)
 51 | 	sub = [(self.state_vals[i], Var(i,self.state_sorts[i])) for i in range(n)]
 52 | 	return substitute(e, sub)
 53 | 	
 54 |     def declare_transition(self, tr):
 55 | 	len_s  = len(self.state_sorts)
 56 | 	effect = tr["effect"]
 57 | 	vars1  = [Var(i,self.state_sorts[i]) for i in range(len_s)] + effect
 58 | 	rho1  = self.abstract(self.step(vars1))
 59 | 	guard = self.abstract(tr["guard"])
 60 | 	self.fp.rule(rho1, guard)
 61 | 	
 62 |     def declare_transitions(self):
 63 | 	for t in self.transitions:
 64 | 	    self.declare_transition(t)
 65 | 
 66 |     def declare_initial(self):
 67 | 	self.fp.rule(self.state0(),[self.abstract(self.initial)])
 68 | 	
 69 |     def query(self, query):
 70 | 	self.declare_rels()
 71 | 	self.declare_initial()
 72 | 	self.declare_reachability()
 73 | 	self.declare_transitions()
 74 | 	query = And(self.state0(), self.abstract(query))
 75 | 	print self.fp
 76 | 	print query
 77 | 	print self.fp.query(query)
 78 | 	print self.fp.get_answer()
 79 | #	print self.fp.statistics()
 80 | 
 81 | 
 82 | L = Datatype('L')
 83 | L.declare('L0')
 84 | L.declare('L1')
 85 | L.declare('L2')
 86 | L = L.create()
 87 | L0 = L.L0
 88 | L1 = L.L1
 89 | L2 = L.L2
 90 | 
 91 | 
 92 | y0 = Int('y0')
 93 | y1 = Int('y1')
 94 | l  = Const('l', L)
 95 | m  = Const('m', L)
 96 | 
 97 | 
 98 | t1 = { "guard" : l == L0,
 99 |        "effect" : [ L1, y1 + 1, m, y1 ] }
100 | t2 = { "guard" : And(l == L1, Or([y0 <= y1, y1 == 0])),
101 |        "effect" : [ L2, y0,     m, y1 ] }
102 | t3 = { "guard" : l == L2,
103 |        "effect" : [ L0, IntVal(0), m, y1 ]}
104 | s1 = { "guard" : m == L0,
105 |        "effect" : [ l,  y0, L1, y0 + 1 ] }
106 | s2 = { "guard" : And(m == L1, Or([y1 <= y0, y0 == 0])),
107 |        "effect" : [ l,  y0, L2, y1 ] }
108 | s3 = { "guard" : m == L2,
109 |        "effect" : [ l,  y0, L0, IntVal(0) ]}
110 | 
111 | 
112 | ptr = TransitionSystem( And(l == L0, y0 == 0, m == L0, y1 == 0),
113 | 			[t1, t2, t3, s1, s2, s3],
114 | 			[l, y0, m, y1])
115 | 
116 | ptr.query(And([l == L2, m == L2 ]))
117 | 
118 | 


--------------------------------------------------------------------------------
/examples/fixedpoints.htm:
--------------------------------------------------------------------------------
  1 | 
  2 | 
  3 | Z3Py Fixedpoints
  4 | 
  5 | 
  6 | 
  7 | 
  8 | 

Fixedpoints

9 | 10 |

11 |

12 | 13 |

14 | This tutorial illustrates uses of Z3's fixedpoint engine. 15 | The following papers 16 | 17 | μZ - An Efficient Engine for Fixed-Points with Constraints. 18 | (CAV 2011) and 19 | 20 | Generalized Property Directed Reachability (SAT 2012) 21 | describe some of the main features of the engine. 22 |

23 | 24 |

25 | Please send feedback, comments and/or corrections to 26 | nbjorner@microsoft.com. 27 |

28 | 29 |

Introduction

30 | 31 | 32 |

33 | This tutorial covers some of the fixedpoint utilities available with Z3. 34 | The main features are a basic Datalog engine, an engine with relational 35 | algebra and an engine based on a generalization of the Property 36 | Directed Reachability algorithm. 37 |

38 | 39 | 40 |

Basic Datalog

41 | 42 |

The default fixed-point engine is a bottom-up Datalog engine. 43 | It works with finite relations and uses finite table representations 44 | as hash tables as the default way to represent finite relations. 45 |

46 | 47 |

Relations, rules and queries

48 | 49 | The first example illustrates how to declare relations, rules and 50 | how to pose queries. 51 | 52 |
 53 | 
 54 | The example illustrates some of the basic constructs.
 55 | 
 56 |   fp = Fixedpoint()
 57 | 
58 | creates a context for fixed-point computation. 59 |
 60 |  fp.register_relation(a.decl(), b.decl(), c.decl())
 61 | 
62 | Register the relations a, b, c as recursively defined. 63 |
 64 |  fp.rule(a,b)
 65 | 
66 | Create the rule that a follows from b. 67 | In general you can create a rule with multiple premises and a name using 68 | the format 69 |
 70 |  fp.rule(head,[body1,...,bodyN],name)
 71 | 
72 | The name is optional. It is used for tracking the rule in derivation proofs. 73 | 74 | Continuing with the example, a is false unless b is established. 75 |
 76 |  fp.query(a)
 77 | 
78 | Asks if a can be derived. The rules so far say that a 79 | follows if b is established and that b follows if c 80 | is established. But nothing establishes c and b is also not 81 | established, so a cannot be derived. 82 |
 83 |  fp.fact(c)
 84 | 
85 | Add a fact (shorthand for fp.rule(c,True)). 86 | Now it is the case that a can be derived. 87 | 88 |

Explanations

89 |

90 | It is also possible to get an explanation for a derived query. 91 | For the finite Datalog engine, an explanation is a trace that 92 | provides information of how a fact was derived. The explanation 93 | is an expression whose function symbols are Horn rules and facts used 94 | in the derivation. 95 |

96 |
 97 | 
 98 | 

Relations with arguments

99 |

100 | Relations can take arguments. We illustrate relations with arguments 101 | using edges and paths in a graph. 102 |

103 |
104 | 
105 | The example uses the declaration
106 | 
107 |  fp.declare_var(a,b,c)
108 | 
109 | to instrument the fixed-point engine that a, b, c 110 | should be treated as variables 111 | when they appear in rules. Think of the convention as they way bound variables are 112 | passed to quantifiers in Z3Py. 113 | 114 |

Rush Hour

115 |

116 | A more entertaining example of using the basic fixed point engine 117 | is to solve the Rush Hour puzzle. The puzzle is about moving 118 | a red car out of a gridlock. We have encoded a configuration 119 | and compiled a set of rules that encode the legal moves of the cars 120 | given the configuration. Other configurations can be tested by 121 | changing the parameters passed to the constructor for Car. 122 | We have encoded the configuration from 123 | 124 | an online puzzle you can solve manually, or cheat on by asking Z3. 125 |

126 |
127 | 
128 | 
129 | 

Abstract Domains

130 | The underlying engine uses table operations 131 | that are based on relational algebra. Representations are 132 | opaque to the underlying engine. 133 | Relational algebra operations are well defined for arbitrary relations. 134 | They don't depend on whether the relations denote a finite or an 135 | infinite set of values. 136 | Z3 contains two built-in tables for infinite domains. 137 | The first is for intervals of integers and reals. 138 | The second is for bound constraints between two integers or reals. 139 | A bound constraint is of the form x < y or x <= y. 140 | When used in conjunction, they form 141 | an abstract domain that is called the 142 | 143 | Pentagon abstract 144 | domain. Z3 implements reduced products 145 | of abstract domains that enables sharing constraints between 146 | the interval and bounds domains. 147 | 148 |

149 | Below we give a simple example that illustrates a loop at location l0. 150 | The loop is incremented as long as the loop counter does not exceed an upper 151 | bound. Using the combination of bound and interval domains 152 | we can collect derived invariants from the loop and we can also establish 153 | that the state after the loop does not exceed the bound. 154 |

155 | 156 | 157 |
158 | 
159 | The example uses the option
160 | 
161 |    set_option(dl_compile_with_widening=True)
162 | 
163 | to instrument Z3 to apply abstract interpretation widening on loop boundaries. 164 | 165 | 166 |

Engine for Property Directed Reachability

167 | 168 | A different underlying engine for fixed-points is based on 169 | an algorithm for Property Directed Reachability (PDR). 170 | The PDR engine is enabled using the instruction 171 |
172 |   set_option(dl_engine=1)
173 | 
174 | The version in Z3 applies to Horn clauses with arithmetic and 175 | Boolean domains. When using arithmetic you should enable 176 | the main abstraction engine used in Z3 for arithmetic in PDR. 177 |
178 |  set_option(dl_pdr_use_farkas=True)
179 | 
180 | The engine also works with domains using algebraic 181 | data-types and bit-vectors, although it is currently not 182 | overly tuned for either. 183 | The PDR engine is targeted at applications from symbolic model 184 | checking of software. The systems may be infinite state. 185 | The following examples also serve a purpose of showing 186 | how software model checking problems (of safety properties) 187 | can be embedded into Horn clauses and solved using PDR. 188 | 189 |

Procedure Calls

190 |

191 | McCarthy's 91 function illustrates a procedure that calls itself recursively 192 | twice. The Horn clauses below encode the recursive function: 193 | 194 |

195 |   mc(x) = if x > 100 then x - 10 else mc(mc(x+11))
196 | 
197 | 198 | The general scheme for encoding recursive procedures is by creating a predicate 199 | for each procedure and adding an additional output variable to the predicate. 200 | Nested calls to procedures within a body can be encoded as a conjunction 201 | of relations. 202 |

203 | 204 |
205 | 
206 | The first two queries are unsatisfiable. The PDR engine produces the same proof of unsatisfiability.
207 | The proof is an inductive invariant for each recursive predicate. The PDR engine introduces a
208 | special query predicate for the query.
209 | 
210 | 

Bakery

211 | 212 |

213 | We can also prove invariants of reactive systems. It is convenient to encode reactive systems 214 | as guarded transition systems. It is perhaps for some not as convenient to directly encode 215 | guarded transitions as recursive Horn clauses. But it is fairly easy to write a translator 216 | from guarded transition systems to recursive Horn clauses. We illustrate a translator 217 | and Lamport's two process Bakery algorithm in the next example. 218 |

219 | 220 |
221 | The rather verbose (and in no way minimal) inductive invariants are produced as answers.
222 | 
223 | 

Functional Programs

224 | We can also verify some properties of functional programs using Z3's 225 | generalized PDR. Let us here consider an example from 226 | 227 | Predicate Abstraction and CEGAR for Higher-Order Model 228 | Checking, Kobayashi et.al. PLDI 2011. 229 | We encode functional programs by taking a suitable operational 230 | semantics and encoding an evaluator that is specialized to 231 | the program being verified (we don't encode a general purpose 232 | evaluator, you should partial evaluate it to help verification). 233 | We use algebraic data-types to encode the current closure that is 234 | being evaluated. 235 | 236 |
237 | 
238 | 
239 | 
240 | 
241 | 


--------------------------------------------------------------------------------
/examples/format.py:
--------------------------------------------------------------------------------
 1 | x = IntVector('x', 20)
 2 | y = IntVector('y', 20)
 3 | f = And(Sum(x) >= 0, Sum(y) >= 0)
 4 | 
 5 | set_option(max_args=5)
 6 | print "\ntest 1:"
 7 | print f
 8 | 
 9 | print "\ntest 2:"
10 | set_option(max_args=100, max_lines=10)
11 | print f
12 | 
13 | print "\ntest 3:"
14 | set_option(max_width=300)
15 | print f
16 | 
17 | 


--------------------------------------------------------------------------------
/examples/guide.htm:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ericpony/z3py-tutorial/de86c5e47c7ded29853c6d69ca6ac5c8b9b6c4aa/examples/guide.htm


--------------------------------------------------------------------------------
/examples/install.1.py:
--------------------------------------------------------------------------------
 1 | def DependsOn(pack, deps):
 2 |     return And([ Implies(pack, dep) for dep in deps ])
 3 | 
 4 | def Conflict(p1, p2):
 5 |     return Or(Not(p1), Not(p2))
 6 | 
 7 | a, b, c, d, e, f, g, z = Bools('a b c d e f g z')
 8 | 
 9 | solve(DependsOn(a, [b, c, z]),
10 |       DependsOn(b, [d]),
11 |       DependsOn(c, [Or(d, e), Or(f, g)]),
12 |       Conflict(d, e),
13 |       a, z)
14 | 


--------------------------------------------------------------------------------
/examples/install.2.py:
--------------------------------------------------------------------------------
 1 | def DependsOn(pack, deps):
 2 |     if is_expr(deps):
 3 |         return Implies(pack, deps)
 4 |     else:
 5 |         return And([ Implies(pack, dep) for dep in deps ])
 6 | 
 7 | def Conflict(*packs):
 8 |     return Or([ Not(pack) for pack in packs ])
 9 | 
10 | a, b, c, d, e, f, g, z = Bools('a b c d e f g z')
11 | 
12 | def install_check(*problem):
13 |     s = Solver()
14 |     s.add(*problem)
15 |     if s.check() == sat:
16 |         m = s.model()
17 |         r = []
18 |         for x in m:
19 |             if is_true(m[x]):
20 |                 # x is a Z3 declaration
21 |                 # x() returns the Z3 expression
22 |                 # x.name() returns a string
23 |                 r.append(x())
24 |         print r
25 |     else:
26 |         print "invalid installation profile"
27 | 
28 | print "Check 1"
29 | install_check(DependsOn(a, [b, c, z]),
30 |               DependsOn(b, d),
31 |               DependsOn(c, [Or(d, e), Or(f, g)]),
32 |               Conflict(d, e),
33 |               Conflict(d, g),
34 |               a, z)
35 | 
36 | print "Check 2"
37 | install_check(DependsOn(a, [b, c, z]),
38 |               DependsOn(b, d),
39 |               DependsOn(c, [Or(d, e), Or(f, g)]),
40 |               Conflict(d, e),
41 |               Conflict(d, g),
42 |               a, z, g)
43 | 


--------------------------------------------------------------------------------
/examples/k.1.py:
--------------------------------------------------------------------------------
 1 | d, a, t, v_i, v_f = Reals('d a t v__i v__f')
 2 | 
 3 | equations = [
 4 |    d == v_i * t + (a*t**2)/2,
 5 |    v_f == v_i + a*t,
 6 | ]
 7 | print "Kinematic equations:"
 8 | print equations
 9 | 
10 | # Given v_i, v_f and a, find d
11 | problem = [
12 |     v_i == 30,
13 |     v_f == 0,
14 |     a   == -8
15 | ]
16 | print "Problem:"
17 | print problem 
18 | 
19 | print "Solution:"
20 | solve(equations + problem)
21 | 


--------------------------------------------------------------------------------
/examples/k.2.py:
--------------------------------------------------------------------------------
 1 | d, a, t, v_i, v_f = Reals('d a t v__i v__f')
 2 | 
 3 | equations = [
 4 |    d == v_i * t + (a*t**2)/2,
 5 |    v_f == v_i + a*t,
 6 | ]
 7 | 
 8 | # Given v_i, t and a, find d
 9 | problem = [
10 |     v_i == 0,
11 |     t   == 4.10,
12 |     a   == 6
13 | ]
14 | 
15 | solve(equations + problem)
16 | 
17 | # Display rationals in decimal notation
18 | set_option(rational_to_decimal=True)
19 | 
20 | solve(equations + problem)
21 | 


--------------------------------------------------------------------------------
/examples/list.1.py:
--------------------------------------------------------------------------------
 1 | # Create list [1, ..., 5] 
 2 | print [ x + 1 for x in range(5) ]
 3 | 
 4 | # Create two lists containg 5 integer variables
 5 | X = [ Int('x%s' % i) for i in range(5) ]
 6 | Y = [ Int('y%s' % i) for i in range(5) ]
 7 | print X
 8 | 
 9 | # Create a list containing X[i]+Y[i]
10 | X_plus_Y = [ X[i] + Y[i] for i in range(5) ]
11 | print X_plus_Y
12 | 
13 | # Create a list containing X[i] > Y[i]
14 | X_gt_Y = [ X[i] > Y[i] for i in range(5) ]
15 | print X_gt_Y
16 | 
17 | print And(X_gt_Y)
18 | 
19 | # Create a 3x3 "matrix" (list of lists) of integer variables
20 | X = [ [ Int("x_%s_%s" % (i+1, j+1)) for j in range(3) ] 
21 |       for i in range(3) ]
22 | pp(X)
23 | 
24 | 


--------------------------------------------------------------------------------
/examples/list.2.py:
--------------------------------------------------------------------------------
1 | X = IntVector('x', 5)
2 | Y = RealVector('y', 5)
3 | P = BoolVector('p', 5)
4 | print X
5 | print Y
6 | print P
7 | print [ y**2 for y in Y ]
8 | print Sum([ y**2 for y in Y ])
9 | 


--------------------------------------------------------------------------------
/examples/list1.py:
--------------------------------------------------------------------------------
 1 | from z3 import *
 2 | 
 3 | # Create a solver.
 4 | s = Solver()
 5 | 
 6 | List = Datatype('List')
 7 | 
 8 | # Declare constructors.
 9 | List.declare('cons', ('car', IntSort()), ('cdr', List))
10 | List.declare('nil')
11 | 
12 | # Create the datatype.
13 | List = List.create()
14 | 
15 | # Create shorthands.
16 | cons = List.cons
17 | car = List.car
18 | cdr = List.cdr
19 | nil = List.nil
20 | 
21 | # Create a list.
22 | l = cons(2, cons(1, cons(0, nil)))
23 | 
24 | print 'simplify(l):'
25 | print simplify(l)
26 | print ''
27 | 
28 | print 'simplify(car(l)):'
29 | print simplify(car(l))
30 | print ''
31 | 
32 | print 'simplify(car(cdr(l))):'
33 | print simplify(car(cdr(l)))
34 | print ''
35 | 


--------------------------------------------------------------------------------
/examples/list2.py:
--------------------------------------------------------------------------------
 1 | from z3 import *
 2 | 
 3 | # Create a solver.
 4 | s = Solver()
 5 | 
 6 | List = Datatype('List')
 7 | 
 8 | # Declare constructors.
 9 | List.declare('cons', ('car', IntSort()), ('cdr', List))
10 | List.declare('nil')
11 | 
12 | # Create the datatype.
13 | List = List.create()
14 | 
15 | # Create shorthands.
16 | cons = List.cons
17 | car = List.car
18 | cdr = List.cdr
19 | nil = List.nil
20 | 
21 | # Create an uninterpreted function 'atom'.
22 | atom = Function('atom', List, BoolSort())
23 | 
24 | # Assert axioms for atom.
25 | x = Const('x', List)
26 | s.add(ForAll([x], Implies(Not(atom(x)), cons(car(x), cdr(x)) == x)))
27 | 
28 | x = Int('x')
29 | y = Const('x', List)
30 | s.add(ForAll([x, y], Not(atom(cons(x, y)))))
31 | 
32 | # Construct the example formula.
33 | x = Const('x', List)
34 | y = Const('y', List)
35 | f = Function('f', List, List)
36 | 
37 | # Add assertions.
38 | s.add(car(x) == car(y),
39 |       cdr(x) == cdr(y),
40 |       f(x) != f(y),
41 |       Not(atom(x)),
42 |       Not(atom(y)))
43 | 
44 | # Check satisfiability.
45 | print s.check()
46 | 


--------------------------------------------------------------------------------
/examples/msolver.1.py:
--------------------------------------------------------------------------------
 1 | x, y = Ints('x y')
 2 | s1 = Solver()
 3 | s1.add(x > 10, y > 10)
 4 | s2 = Solver()
 5 | # solver s2 is empty
 6 | print s2
 7 | # copy assertions from s1 to s2
 8 | s2.add(s1.assertions())
 9 | print s2
10 | 


--------------------------------------------------------------------------------
/examples/nqueens.py:
--------------------------------------------------------------------------------
 1 | """template.py
 2 | This is a template"""
 3 | 
 4 | def toStrConj(List):
 5 |     assert List != []
 6 |     clauseStr = '('
 7 |     for lit in List:
 8 |         clauseStr += lit
 9 |         clauseStr += ' and '
10 |     clauseStr += ' (TRUE or -TRUE))'
11 |     return clauseStr
12 | 
13 | def toStrDisj(List):
14 |     assert List != []
15 |     clauseStr = '('
16 |     for lit in List:
17 |         clauseStr += lit
18 |         clauseStr += ' or '
19 |     clauseStr += '(TRUE and -TRUE) )'
20 | 
21 |     return clauseStr
22 | 
23 |     
24 | def toStrCNF(ListList):
25 |     """Convert a formula in CNF represented as a list of list to
26 |     string representation."""
27 |     assert ListList != []
28 |     # Convert each clause into str
29 |     ListStr = [ toStrDisj(disj) for disj in ListList ]
30 |     # Convert the conjunction of things into str
31 |     StrStr = toStrConj(ListStr)
32 | 
33 |     return StrStr
34 | 
35 | def main():
36 |     # Specify your value n
37 |     n = 8
38 | 
39 |     # Preprocessing
40 |     n += 1 # because of Python end range
41 | 
42 |     # Construct first constraint
43 |     C1a = [[ 'p' + str(i) + 'd' + str(j) for j in range(1,n) ] for i in \
44 |             range(1,n)]
45 |     strC1a = toStrCNF(C1a)
46 | 
47 |     C1b = [ '(p'+str(i)+'d'+str(j)+' => -p'+str(i)+'d'+str(k)+')' for i in \
48 |             range(1,n) for j in range(1,n) for k in range(1,n) if k != j ]
49 |     strC1b = toStrConj(C1b)
50 | 
51 |     # Construct second constraint
52 |     C2a = [[ 'p' + str(i) + 'd' + str(j) for i in range(1,n) ] for j in \
53 |             range(1,n)]
54 |     strC2a = toStrCNF(C2a)
55 | 
56 |     C2b = [ '(p'+str(i)+'d'+str(j)+' => -p'+str(k)+'d'+str(j)+')' for i in \
57 |             range(1,n) for j in range(1,n) for k in range(1,n) if k != i ]
58 |     strC2b = toStrConj(C2b)
59 | 
60 |     # Construct third constraint
61 |     # -45-deg diag constraint
62 |     C3a = [ '(p'+str(i)+'d'+str(j)+' => -p'+str(i+k)+'d'+str(j+k)+')' for i in\
63 |             range(1,n) for j in range(1,n) for k in range(1,n) \
64 |             if 1 <= (i+k) and (i+k) < n and 1 <= (j+k) and (j+k) < n ]
65 |     strC3a = toStrConj(C3a)
66 | 
67 |     C3b = [ '(p'+str(i)+'d'+str(j)+' => -p'+str(i-k)+'d'+str(j-k)+')' for i in\
68 |             range(1,n) for j in range(1,n) for k in range(1,n) \
69 |             if 1 <= (i-k) and (i-k) < n and 1 <= (j-k) and (j-k) < n ]
70 |     strC3b = toStrConj(C3b)
71 | 
72 |     # Construct fourth constraint
73 |     # 45-deg diag constraint
74 |     C4a = [ '(p'+str(i)+'d'+str(j)+' => -p'+str(i+k)+'d'+str(j-k)+')' for i in\
75 |             range(1,n) for j in range(1,n) for k in range(1,n) \
76 |             if 1 <= (i+k) and (i+k) < n and 1 <= (j-k) and (j-k) < n ]
77 |     strC4a = toStrConj(C4a)
78 | 
79 |     C4b = [ '(p'+str(i)+'d'+str(j)+' => -p'+str(i-k)+'d'+str(j+k)+')' for i in\
80 |             range(1,n) for j in range(1,n) for k in range(1,n) \
81 |             if 1 <= (i-k) and (i-k) < n and 1 <= (j+k) and (j+k) < n ]
82 |     strC4b = toStrConj(C4b)
83 | 
84 |     #C2 = [[ 'p' + str(i) + 'd' + str(j) for j in range(1,n) ] for i in \
85 |             #range(1,n)]
86 |     # ListStrC1 = [ toStrDisj(disj) for disj in ListListC1 ]
87 |     # StrStrC1 = toStrConj(ListStrC1)
88 |     print toStrConj([strC1a,strC1b,strC2a,strC2b,strC3a,strC3b,strC4a,strC4b])
89 | 
90 | if __name__ == '__main__':
91 |     main()
92 | 


--------------------------------------------------------------------------------
/examples/printer.py:
--------------------------------------------------------------------------------
1 | x = Int('x')
2 | y = Int('y')
3 | print x**2 + y**2 >= 1
4 | set_option(html_mode=False)
5 | print x**2 + y**2 >= 1
6 | 
7 | 


--------------------------------------------------------------------------------
/examples/probe.1.py:
--------------------------------------------------------------------------------
1 | describe_probes()
2 | 


--------------------------------------------------------------------------------
/examples/probe.1.ty:
--------------------------------------------------------------------------------
1 | print probes()
2 | 


--------------------------------------------------------------------------------
/examples/probe.2.py:
--------------------------------------------------------------------------------
 1 | x, y, z = Reals('x y z')
 2 | g = Goal()
 3 | g.add(x + y + z > 0)
 4 | 
 5 | p = Probe('num-consts')
 6 | print "num-consts:", p(g)
 7 | 
 8 | t = FailIf(p > 2)
 9 | try:
10 |     t(g)
11 | except Z3Exception:
12 |     print "tactic failed"
13 | 
14 | print "trying again..."
15 | g = Goal()
16 | g.add(x + y > 0)
17 | print t(g)
18 | 
19 | 


--------------------------------------------------------------------------------
/examples/probe.3.py:
--------------------------------------------------------------------------------
 1 | x, y, z = Reals('x y z')
 2 | g = Goal()
 3 | g.add(x**2 - y**2 >= 0)
 4 | 
 5 | p = Probe('num-consts')
 6 | t = If(p > 2, 'simplify', 'factor')
 7 | 
 8 | print t(g)
 9 | 
10 | g = Goal()
11 | g.add(x + x + y + z >= 0, x**2 - y**2 >= 0)
12 | 
13 | print t(g)
14 | 


--------------------------------------------------------------------------------
/examples/puzzle.1.py:
--------------------------------------------------------------------------------
 1 | # Create 3 integer variables
 2 | dog, cat, mouse = Ints('dog cat mouse')
 3 | solve(dog >= 1,   # at least one dog
 4 |       cat >= 1,   # at least one cat
 5 |       mouse >= 1, # at least one mouse
 6 |       # we want to buy 100 animals
 7 |       dog + cat + mouse == 100,  
 8 |       # We have 100 dollars (10000 cents):
 9 |       #   dogs cost 15 dollars (1500 cents), 
10 |       #   cats cost 1 dollar (100 cents), and 
11 |       #   mice cost 25 cents 
12 |       1500 * dog + 100 * cat + 25 * mouse == 10000)
13 | 


--------------------------------------------------------------------------------
/examples/puzzle.2.py:
--------------------------------------------------------------------------------
 1 | # 9x9 matrix of integer variables
 2 | X = [ [ Int("x_%s_%s" % (i+1, j+1)) for j in range(9) ] 
 3 |       for i in range(9) ]
 4 | 
 5 | # each cell contains a value in {1, ..., 9}
 6 | cells_c  = [ And(1 <= X[i][j], X[i][j] <= 9) 
 7 |              for i in range(9) for j in range(9) ]
 8 | 
 9 | # each row contains a digit at most once
10 | rows_c   = [ Distinct(X[i]) for i in range(9) ]
11 | 
12 | # each column contains a digit at most once
13 | cols_c   = [ Distinct([ X[i][j] for i in range(9) ]) 
14 |              for j in range(9) ]
15 | 
16 | # each 3x3 square contains a digit at most once
17 | sq_c     = [ Distinct([ X[3*i0 + i][3*j0 + j] 
18 |                         for i in range(3) for j in range(3) ]) 
19 |              for i0 in range(3) for j0 in range(3) ]
20 | 
21 | sudoku_c = cells_c + rows_c + cols_c + sq_c
22 | 
23 | # sudoku instance, we use '0' for empty cells
24 | instance = ((0,0,0,0,9,4,0,3,0),
25 |             (0,0,0,5,1,0,0,0,7),
26 |             (0,8,9,0,0,0,0,4,0),
27 |             (0,0,0,0,0,0,2,0,8),
28 |             (0,6,0,2,0,1,0,5,0),
29 |             (1,0,2,0,0,0,0,0,0),
30 |             (0,7,0,0,0,0,5,2,0),
31 |             (9,0,0,0,6,5,0,0,0),
32 |             (0,4,0,9,7,0,0,0,0))
33 | 
34 | instance_c = [ If(instance[i][j] == 0, 
35 |                   True, 
36 |                   X[i][j] == instance[i][j]) 
37 |                for i in range(9) for j in range(9) ]
38 | 
39 | s = Solver()
40 | s.add(sudoku_c + instance_c)
41 | if s.check() == sat:
42 |     m = s.model()
43 |     r = [ [ m.evaluate(X[i][j]) for j in range(9) ] 
44 |           for i in range(9) ]
45 |     print_matrix(r)
46 | else:
47 |     print "failed to solve"
48 | 
49 | 


--------------------------------------------------------------------------------
/examples/puzzle.3.py:
--------------------------------------------------------------------------------
 1 | # We know each queen must be in a different row.
 2 | # So, we represent each queen by a single integer: the column position
 3 | Q = [ Int('Q_%i' % (i + 1)) for i in range(8) ]
 4 | 
 5 | # Each queen is in a column {1, ... 8 }
 6 | val_c = [ And(1 <= Q[i], Q[i] <= 8) for i in range(8) ]
 7 | 
 8 | # At most one queen per column
 9 | col_c = [ Distinct(Q) ]
10 | 
11 | # Diagonal constraint
12 | diag_c = [ If(i == j, 
13 |               True, 
14 |               And(Q[i] - Q[j] != i - j, Q[i] - Q[j] != j - i)) 
15 |            for i in range(8) for j in range(i) ]
16 | 
17 | solve(val_c + col_c + diag_c)
18 | 


--------------------------------------------------------------------------------
/examples/quant.1.py:
--------------------------------------------------------------------------------
1 | f = Function('f', IntSort(), IntSort(), IntSort())
2 | x, y = Ints('x y')
3 | print ForAll([x, y], f(x, y) == 0)
4 | print Exists(x, f(x, x) >= 0)
5 | 
6 | a, b = Ints('a b')
7 | solve(ForAll(x, f(x, x) == 0), f(a, b) == 1)
8 | 


--------------------------------------------------------------------------------
/examples/quant.2.py:
--------------------------------------------------------------------------------
1 | f = Function('f', IntSort(), IntSort(), IntSort())
2 | x, y = Ints('x y')
3 | f = ForAll([x, y], f(x, y) == 0)
4 | print f.body()
5 | v1 = f.body().arg(0).arg(0)
6 | print v1
7 | print eq(v1, Var(1, IntSort()))
8 | 


--------------------------------------------------------------------------------
/examples/quant.3.py:
--------------------------------------------------------------------------------
 1 | Type     = DeclareSort('Type')
 2 | subtype  = Function('subtype', Type, Type, BoolSort())
 3 | array_of = Function('array_of', Type, Type)
 4 | root     = Const('root', Type)
 5 | 
 6 | x, y, z  = Consts('x y z', Type)
 7 | 
 8 | axioms = [ ForAll(x, subtype(x, x)),
 9 |            ForAll([x, y, z], Implies(And(subtype(x, y), subtype(y, z)),
10 |                                      subtype(x, z))),
11 |            ForAll([x, y], Implies(And(subtype(x, y), subtype(y, x)),
12 |                                   x == y)),
13 |            ForAll([x, y, z], Implies(And(subtype(x, y), subtype(x, z)),
14 |                                      Or(subtype(y, z), subtype(z, y)))),
15 |            ForAll([x, y], Implies(subtype(x, y),
16 |                                   subtype(array_of(x), array_of(y)))),
17 |            
18 |            ForAll(x, subtype(root, x))
19 |            ]
20 | s = Solver()
21 | s.add(axioms)
22 | print s
23 | print s.check()
24 | print "Interpretation for Type:"
25 | print s.model()[Type]
26 | print "Model:"
27 | print s.model()
28 | 
29 | 


--------------------------------------------------------------------------------
/examples/quant.4.py:
--------------------------------------------------------------------------------
 1 | f = Function('f', IntSort(), IntSort())
 2 | g = Function('g', IntSort(), IntSort())
 3 | a, b, c = Ints('a b c')
 4 | x = Int('x')
 5 | 
 6 | s = Solver()
 7 | s.set(auto_config=False, mbqi=False)
 8 | 
 9 | s.add( ForAll(x, f(g(x)) == x, patterns = [f(g(x))]),
10 |        g(a) == c,
11 |        g(b) == c,
12 |        a != b )
13 | 
14 | # Display solver state using internal format
15 | print s.sexpr()
16 | print s.check()
17 | 


--------------------------------------------------------------------------------
/examples/quant.5.py:
--------------------------------------------------------------------------------
 1 | f = Function('f', IntSort(), IntSort())
 2 | g = Function('g', IntSort(), IntSort())
 3 | a, b, c = Ints('a b c')
 4 | x = Int('x')
 5 | 
 6 | s = Solver()
 7 | s.set(auto_config=False, mbqi=False)
 8 | 
 9 | s.add( ForAll(x, f(g(x)) == x, patterns = [g(x)]),
10 |        g(a) == c,
11 |        g(b) == c,
12 |        a != b )
13 | 
14 | # Display solver state using internal format
15 | print s.sexpr()
16 | print s.check()
17 | 


--------------------------------------------------------------------------------
/examples/quant.6.py:
--------------------------------------------------------------------------------
 1 | f = Function('f', IntSort(), IntSort())
 2 | g = Function('g', IntSort(), IntSort())
 3 | a, b, c = Ints('a b c')
 4 | x = Int('x')
 5 | 
 6 | s = Solver()
 7 | s.set(auto_config=False, mbqi=False)
 8 | 
 9 | s.add( ForAll(x, f(g(x)) == x, patterns = [f(g(x))]),
10 |        a == g(b),
11 |        b == c,
12 |        f(a) != c )
13 | 
14 | print s.check()
15 | 


--------------------------------------------------------------------------------
/examples/quant.7.py:
--------------------------------------------------------------------------------
 1 | A = DeclareSort('A')
 2 | B = DeclareSort('B')
 3 | f = Function('f', A, B)
 4 | a1, a2 = Consts('a1 a2', A)
 5 | b      = Const('b', B)
 6 | x,  y  = Consts('x y', A)
 7 | 
 8 | s = Solver()
 9 | s.add(a1 != a2,
10 |       f(a1) == b,
11 |       f(a2) == b,
12 |       ForAll([x, y], Implies(f(x) == f(y), x == y),
13 |              patterns=[MultiPattern(f(x), f(y))])
14 |       )
15 | print s.check()
16 | 


--------------------------------------------------------------------------------
/examples/quant.8.py:
--------------------------------------------------------------------------------
 1 | A = DeclareSort('A')
 2 | B = DeclareSort('B')
 3 | f = Function('f', A, B)
 4 | finv = Function('finv', B, A)
 5 | a1, a2 = Consts('a1 a2', A)
 6 | b      = Const('b', B)
 7 | x,  y  = Consts('x y', A)
 8 | 
 9 | s = Solver()
10 | s.add(a1 != a2,
11 |       f(a1) == b,
12 |       f(a2) == b,
13 |       ForAll(x, finv(f(x)) == x)
14 |       )
15 | print s.check()
16 | 


--------------------------------------------------------------------------------
/examples/queens.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ericpony/z3py-tutorial/de86c5e47c7ded29853c6d69ca6ac5c8b9b6c4aa/examples/queens.png


--------------------------------------------------------------------------------
/examples/strategies.htm:
--------------------------------------------------------------------------------
  1 | 
  2 | 
  3 | Z3Py Strategies
  4 | 
  5 | 
  6 | 
  7 | 
  8 | 

Strategies

9 | 10 |

11 | High-performance solvers, such as Z3, contain many tightly integrated, handcrafted heuristic 12 | combinations of algorithmic proof methods. While these heuristic 13 | combinations tend to be highly tuned for known classes of problems, 14 | they may easily perform very badly on new classes of problems. 15 | This issue is becoming increasingly pressing 16 | as solvers begin to gain the attention of practitioners in diverse areas of science and engineering. 17 | In many cases, changes to the solver heuristics can make a 18 | tremendous difference. 19 |

20 | 21 |

22 | In this tutorial we show how to create custom strategies using the basic building blocks 23 | available in Z3. Z3Py and Z3 4.0 implement the ideas proposed in this article. 24 |

25 | 26 |

27 | Please send feedback, comments and/or corrections to leonardo@microsoft.com. 28 | Your comments are very valuable. 29 |

30 | 31 |

Introduction

32 | 33 |

34 | Z3 implements a methodology for orchestrating reasoning 35 | engines where "big" symbolic reasoning steps are represented as 36 | functions known as tactics, and tactics are composed using 37 | combinators known as tacticals. Tactics process sets of 38 | formulas called Goals. 39 |

40 | 41 |

42 | When a tactic is applied to some goal G, four different outcomes 43 | are possible. The tactic succeeds in showing G to be satisfiable (i.e., feasible); 44 | succeeds in showing G to be unsatisfiable (i.e., infeasible); produces a sequence of subgoals; or fails. 45 | When reducing a goal G to a sequence of subgoals G1, ..., 46 | Gn, we face the problem of model conversion. 47 | A model converter construct a model for G 48 | using a model for some subgoal Gi. 49 |

50 | 51 |

In the following example, we create a goal g consisting of three formulas, and a tactic t 52 | composed of two built-in tactics: simplify and solve-eqs. The tactic simplify 53 | apply transformations equivalent to the ones found in the command simplify. The tactic solver-eqs 54 | eliminate variables using Gaussian elimination. Actually, solve-eqs is not restricted only to linear arithmetic. 55 | It can also eliminate arbitrary variables. Then, combinator Then applies simplify to the input goal 56 | and solve-eqs to each subgoal produced by simplify. In this example, only one subgoal is produced. 57 |

58 | 59 |
 60 | 
 61 | 

In the example above, variable x is eliminated, and is not present the resultant goal. 62 |

63 | 64 |

In Z3, we say a clause is any constraint of the form Or(f_1, ..., f_n). 65 | The tactic split-clause will select a clause Or(f_1, ..., f_n) in the input goal, and split it 66 | n subgoals. One for each subformula f_i. 67 |

68 | 69 |
 70 | 
 71 | 

Tactics

72 | 73 |

Z3 comes equipped with many built-in tactics. 74 | The command describe_tactics() provides a short description of all built-in tactics. 75 |

76 | 77 |
 78 | 
 79 | 

Z3Py comes equipped with the following tactic combinators (aka tacticals): 80 |

81 | 82 |
    83 |
  • Then(t, s) 84 | applies t to the input goal and s 85 | to every subgoal produced by t. 86 |
  • 87 |
  • OrElse(t, s) 88 | first applies t to the given goal, 89 | if it fails then returns the result of s applied to the given goal. 90 |
  • 91 |
  • Repeat(t) Keep applying the given tactic until no subgoal is modified by it. 92 |
  • 93 |
  • Repeat(t, n) Keep applying the given tactic until no subgoal is modified by it, or 94 | the number of iterations is greater than n. 95 |
  • 96 |
  • TryFor(t, ms) Apply tactic t to the input goal, if it does not return in 97 | ms millisenconds, it fails. 98 |
  • 99 |
  • With(t, params) Apply the given tactic using the given parameters. 100 |
  • 101 |
102 | 103 |

The following example demonstrate how to use these combinators.

104 | 105 |
106 | 
107 | 

In the tactic split_solver, the tactic solve-eqs discharges all but one goal. 108 | Note that, this tactic generates one goal: the empty goal which is trivially satisfiable (i.e., feasible)

109 | 110 |

The list of subgoals can be easily traversed using the Python for statement.

111 | 112 |
113 | 
114 | 

A tactic can be converted into a solver object using the method solver(). 115 | If the tactic produces the empty goal, then the associated solver returns sat. 116 | If the tactic produces a single goal containing False, then the solver returns unsat. 117 | Otherwise, it returns unknown. 118 |

119 | 120 |
121 | 
122 | 

In the example above, the tactic bv_solver implements a basic bit-vector solver using equation solving, 123 | bit-blasting, and a propositional SAT solver. Note that, the command Tactic is suppressed. 124 | All Z3Py combinators automatically invoke Tactic command if the argument is a string. 125 | Finally, the command solve_using is a variant of the solve command where the first 126 | argument specifies the solver to be used. 127 |

128 | 129 |

In the following example, we use the solver API directly instead of the command solve_using. 130 | We use the combinator With to configure our little solver. We also include the tactic aig 131 | which tries to compress Boolean formulas using And-Inverted Graphs. 132 |

133 | 134 |
135 | 
136 | 

The tactic smt wraps the main solver in Z3 as a tactic.

137 | 138 |
139 | 
140 | 

Now, we show how to implement a solver for integer arithmetic using SAT. The solver is complete 141 | only for problems where every variable has a lower and upper bound. 142 |

143 | 144 |
145 | 
146 | 

147 | Tactics can be combined with solvers. For example, we can apply a tactic to a goal, produced a set of subgoals, 148 | then select one of the subgoals and solve it using a solver. The next example demonstrates how to do that, and how to 149 | use model converters to convert a model for a subgoal into a model for the original goal. 150 |

151 | 152 |
153 | 
154 | 

Probes

155 | 156 |

157 | Probes (aka formula measures) are evaluated over goals. 158 | Boolean expressions over them can be built using relational operators and Boolean connectives. 159 | The tactic FailIf(cond) fails if the given goal does not satisfy the condition cond. 160 | Many numeric and Boolean measures are available in Z3Py. The command describe_probes() provides the list of 161 | all built-in probes. 162 |

163 | 164 |
165 | 
166 | 

In the following example, we build a simple tactic using FailIf. It also shows that a probe can be applied directly 167 | to a goal.

168 | 169 |
170 | 
171 | 

Z3Py also provides the combinator (tactical) If(p, t1, t2) which is a shorthand for:

172 | 173 |
OrElse(Then(FailIf(Not(p)), t1), t2)
174 | 175 |

The combinator When(p, t) is a shorthand for:

176 | 177 |
If(p, t, 'skip')
178 | 179 |

The tactic skip just returns the input goal. 180 | The following example demonstrates how to use the If combinator.

181 | 182 |
183 | 
184 | 
185 | 
186 | 


--------------------------------------------------------------------------------
/examples/sudoku.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ericpony/z3py-tutorial/de86c5e47c7ded29853c6d69ca6ac5c8b9b6c4aa/examples/sudoku.png


--------------------------------------------------------------------------------
/examples/sudoku.py:
--------------------------------------------------------------------------------
 1 | 
 2 | """Please Fill the Input by following methods
 3 | 
 4 | If the (x, y) cell is filled with 'n' value,
 5 | then put 'pxyn' into the Input list
 6 | 
 7 | E.g. Consider following sudoku
 8 |   
 9 |   ------------------
10 | 4 |   | 4 ||   |   |
11 |   --------||--------
12 | 3 |   |   || 4 |   |
13 |   ==================
14 | 2 |   | 2 ||   |   |
15 |   --------||--------
16 | 1 |   |   || 1 |   |
17 | y ------------------
18 |   x 1   2    3   4
19 | 
20 | (3, 1) cell is filled with 1
21 | Hence 'p311' is in Input list
22 | """
23 | 
24 | Input = ['p222', 'p244', 'p311', 'p334']
25 | 
26 | 
27 | """ Below is the flow to generate formaula """
28 | I = ['1','2','3','4']
29 | Is = [['1','2'], ['3','4']]
30 | 
31 | """ Check input integrity """
32 | SI = set(I)
33 | for p in Input:
34 |     if not len(p) == 4 or p[0] != 'p' or not p[1] in SI or not p[2] in SI or not p[3] in SI:
35 |         print('Error:' + p + 'is not a valid input.')
36 | 
37 | cls = [] """cls: the list of all conjucted clause"""
38 | cls.extend(Input)
39 | for i in I:
40 |     for j in I:
41 |         l = []
42 |         for n in I:
43 |             l.append('p'+i+j+n)
44 |         cls.append( '(' + ('|'.join(l)) + ')' )
45 | 
46 | for i in I:
47 |     for j in I:
48 |         for n in I:
49 |             for m in I:
50 |                  if m != n:
51 |                     cls.append('(p'+i+j+n+'->~'+'p'+i+j+m+')')
52 | for n in I:
53 |     for i in I:
54 |         l = []
55 |         for j in I:
56 |             l.append('p'+i+j+n)
57 |         cls.append('(' + ('|'.join(l)) +')')
58 | 
59 | for n in I:
60 |     for j in I:
61 |         l = []
62 |         for i in I:
63 |             l.append('p'+i+j+n)
64 |         cls.append('(' + ('|'.join(l)) +')')
65 | 
66 | for k1 in Is:
67 |     for k2 in Is:
68 |         for n in I:
69 |             l = []
70 |             for i in k1:
71 |                 for j in k2:
72 |                     l.append('p'+i+j+n)
73 |             cls.append('(' + ('|'.join(l)) +')')
74 | 
75 | print('&'.join(cls))
76 | 


--------------------------------------------------------------------------------
/examples/tactic.1.py:
--------------------------------------------------------------------------------
 1 | x, y = Reals('x y')
 2 | g  = Goal()
 3 | g.add(x > 0, y > 0, x == y + 2)
 4 | print g
 5 | 
 6 | t1 = Tactic('simplify')
 7 | t2 = Tactic('solve-eqs')
 8 | t  = Then(t1, t2)
 9 | print t(g)
10 | 


--------------------------------------------------------------------------------
/examples/tactic.10.py:
--------------------------------------------------------------------------------
 1 | t = Then('simplify', 
 2 |          'normalize-bounds', 
 3 |          'solve-eqs')
 4 | 
 5 | x, y, z = Ints('x y z')
 6 | g = Goal()
 7 | g.add(x > 10, y == x + 3, z > y)
 8 | 
 9 | r = t(g)
10 | # r contains only one subgoal
11 | print r
12 | 
13 | s = Solver()
14 | s.add(r[0])
15 | print s.check()
16 | # Model for the subgoal
17 | print s.model()
18 | # Model for the original goal
19 | print r.convert_model(s.model())
20 | 


--------------------------------------------------------------------------------
/examples/tactic.2.py:
--------------------------------------------------------------------------------
1 | x, y = Reals('x y')
2 | g  = Goal()
3 | g.add(Or(x < 0, x > 0), x == y + 1, y < 0)
4 | 
5 | t = Tactic('split-clause')
6 | r = t(g)
7 | for g in r: 
8 |     print g
9 | 


--------------------------------------------------------------------------------
/examples/tactic.3.py:
--------------------------------------------------------------------------------
1 | describe_tactics()
2 | 


--------------------------------------------------------------------------------
/examples/tactic.4.py:
--------------------------------------------------------------------------------
 1 | x, y, z = Reals('x y z')
 2 | g = Goal()
 3 | g.add(Or(x == 0, x == 1), 
 4 |       Or(y == 0, y == 1), 
 5 |       Or(z == 0, z == 1),
 6 |       x + y + z > 2)
 7 | 
 8 | # Split all clauses"
 9 | split_all = Repeat(OrElse(Tactic('split-clause'),
10 |                           Tactic('skip')))
11 | print split_all(g)
12 | 
13 | split_at_most_2 = Repeat(OrElse(Tactic('split-clause'),
14 |                           Tactic('skip')),
15 |                          1)
16 | print split_at_most_2(g)
17 | 
18 | # Split all clauses and solve equations
19 | split_solve = Then(Repeat(OrElse(Tactic('split-clause'),
20 |                                  Tactic('skip'))),
21 |                    Tactic('solve-eqs'))
22 | 
23 | print split_solve(g)
24 | 


--------------------------------------------------------------------------------
/examples/tactic.5.py:
--------------------------------------------------------------------------------
 1 | x, y, z = Reals('x y z')
 2 | g = Goal()
 3 | g.add(Or(x == 0, x == 1), 
 4 |       Or(y == 0, y == 1), 
 5 |       Or(z == 0, z == 1),
 6 |       x + y + z > 2)
 7 | 
 8 | # Split all clauses"
 9 | split_all = Repeat(OrElse(Tactic('split-clause'),
10 |                           Tactic('skip')))
11 | for s in split_all(g):
12 |     print s
13 | 


--------------------------------------------------------------------------------
/examples/tactic.6.py:
--------------------------------------------------------------------------------
1 | bv_solver = Then('simplify', 
2 |                  'solve-eqs', 
3 |                  'bit-blast', 
4 |                  'sat').solver()
5 | 
6 | x, y = BitVecs('x y', 16)
7 | solve_using(bv_solver, x | y == 13, x > y)
8 | 


--------------------------------------------------------------------------------
/examples/tactic.7.py:
--------------------------------------------------------------------------------
 1 | bv_solver = Then(With('simplify', mul2concat=True),
 2 |                  'solve-eqs', 
 3 |                  'bit-blast', 
 4 |                  'aig',
 5 |                  'sat').solver()
 6 | x, y = BitVecs('x y', 16)
 7 | bv_solver.add(x*32 + y == 13, x & y < 10, y > -100)
 8 | print bv_solver.check()
 9 | m = bv_solver.model()
10 | print m
11 | print x*32 + y, "==", m.evaluate(x*32 + y)
12 | print x & y, "==", m.evaluate(x & y)
13 | 
14 | 


--------------------------------------------------------------------------------
/examples/tactic.8.py:
--------------------------------------------------------------------------------
1 | x, y = Ints('x y')
2 | s = Tactic('smt').solver()
3 | s.add(x > y + 1)
4 | print s.check()
5 | print s.model()
6 | 


--------------------------------------------------------------------------------
/examples/tactic.9.py:
--------------------------------------------------------------------------------
 1 | s = Then(With('simplify', arith_lhs=True, som=True),
 2 |          'normalize-bounds', 'lia2pb', 'pb2bv', 
 3 |          'bit-blast', 'sat').solver()
 4 | x, y, z = Ints('x y z')
 5 | solve_using(s, 
 6 |             x > 0, x < 10, 
 7 |             y > 0, y < 10, 
 8 |             z > 0, z < 10,
 9 |             3*y + 2*x == z)
10 | # It fails on the next example (it is unbounded)
11 | s.reset()
12 | solve_using(s, 3*y + 2*x == z)
13 | 


--------------------------------------------------------------------------------
/examples/tree.py:
--------------------------------------------------------------------------------
 1 | from z3 import *
 2 | 
 3 | # Create the tree datatype.
 4 | Tree = Datatype('Tree')
 5 | TreeList = Datatype('TreeList')
 6 | Tree.declare('leaf', ('value', IntSort()))
 7 | Tree.declare('node', ('children', TreeList))
 8 | TreeList.declare('nil')
 9 | TreeList.declare('cons', ('car', Tree), ('cdr', TreeList))
10 | 
11 | Tree, TreeList = CreateDatatypes(Tree, TreeList)
12 | 
13 | print 'Tree.value(Tree.leaf(10)):'
14 | print Tree.value(Tree.leaf(10))
15 | print ''
16 | 
17 | print 'simplify(Tree.value(Tree.leaf(10))):'
18 | print simplify(Tree.value(Tree.leaf(10)))
19 | print ''
20 | 
21 | n1 = Tree.node(TreeList.cons(Tree.leaf(10), TreeList.cons(Tree.leaf(20), TreeList.nil)))
22 | n2 = Tree.node(TreeList.cons(n1, TreeList.nil))
23 | print 'n1 = Tree.node(TreeList.cons(Tree.leaf(10), TreeList.cons(Tree.leaf(20), TreeList.nil)))'
24 | print 'n2 = Tree.node(TreeList.cons(n1, TreeList.nil))'
25 | print ''
26 | 
27 | print 'simplify(n2 == n1):'
28 | print simplify(n2 == n1)
29 | print ''
30 | 
31 | print 'simplify(TreeList.car(Tree.children(n2)) == n1):'
32 | print simplify(TreeList.car(Tree.children(n2)) == n1)
33 | print ''
34 | 


--------------------------------------------------------------------------------
/examples/uninterp.1.py:
--------------------------------------------------------------------------------
 1 | A    = DeclareSort('A')
 2 | x, y = Consts('x y', A)
 3 | f    = Function('f', A, A)
 4 | 
 5 | s    = Solver()
 6 | s.add(f(f(x)) == x, f(x) == y, x != y)
 7 | 
 8 | print s.check()
 9 | m = s.model()
10 | print m
11 | print "interpretation assigned to A:"
12 | print m[A]
13 | 


--------------------------------------------------------------------------------
/examples/unsatcore.1.py:
--------------------------------------------------------------------------------
 1 | p1, p2, p3 = Bools('p1 p2 p3')
 2 | x, y = Ints('x y')
 3 | # We assert Implies(p, C) to track constraint C using p
 4 | s = Solver()
 5 | s.add(Implies(p1, x > 10),
 6 |       Implies(p1, y > x),
 7 |       Implies(p2, y < 5),
 8 |       Implies(p3, y > 0))
 9 | print s
10 | # Check satisfiability assuming p1, p2, p3 are true
11 | print s.check(p1, p2, p3)
12 | print s.unsat_core()
13 | 
14 | # Try again retracting p2
15 | print s.check(p1, p3)
16 | print s.model()
17 | 


--------------------------------------------------------------------------------
/examples/z3py.1.py:
--------------------------------------------------------------------------------
1 | x = Int('x')
2 | y = Int('y')
3 | solve(x > 2, y < 10, x + 2*y == 7)
4 | 


--------------------------------------------------------------------------------
/examples/z3py.10.py:
--------------------------------------------------------------------------------
 1 | x = Int('x')
 2 | y = Int('y')
 3 | 
 4 | s = Solver()
 5 | print s
 6 | 
 7 | s.add(x > 10, y == x + 2)
 8 | print s
 9 | print "Solving constraints in the solver s ..."
10 | print s.check()
11 | 
12 | print "Create a new scope..."
13 | s.push()
14 | s.add(y < 11)
15 | print s
16 | print "Solving updated set of constraints..."
17 | print s.check()
18 | 
19 | print "Restoring state..."
20 | s.pop()
21 | print s
22 | print "Solving restored set of constraints..."
23 | print s.check()
24 | 
25 | 
26 | 


--------------------------------------------------------------------------------
/examples/z3py.11.py:
--------------------------------------------------------------------------------
1 | x = Real('x')
2 | s = Solver()
3 | s.add(2**x == 3)
4 | print s.check()
5 | 


--------------------------------------------------------------------------------
/examples/z3py.12.py:
--------------------------------------------------------------------------------
 1 | x = Real('x')
 2 | y = Real('y')
 3 | s = Solver()
 4 | s.add(x > 1, y > 1, Or(x + y > 3, x - y < 2))
 5 | print "asserted constraints..."
 6 | for c in s.assertions():
 7 |     print c
 8 | 
 9 | print s.check()
10 | print "statistics for the last check method..."
11 | print s.statistics()
12 | # Traversing statistics
13 | for k, v in s.statistics():
14 |     print "%s : %s" % (k, v)
15 | 
16 | 


--------------------------------------------------------------------------------
/examples/z3py.13.py:
--------------------------------------------------------------------------------
 1 | x, y, z = Reals('x y z')
 2 | s = Solver()
 3 | s.add(x > 1, y > 1, x + y > 3, z - x < 10)
 4 | print s.check()
 5 | 
 6 | m = s.model()
 7 | print "x = %s" % m[x]
 8 | 
 9 | print "traversing model..."
10 | for d in m.decls():
11 |     print "%s = %s" % (d.name(), m[d])
12 | 
13 | 
14 | 


--------------------------------------------------------------------------------
/examples/z3py.14.py:
--------------------------------------------------------------------------------
1 | x = Int('x')
2 | y = Int('y')
3 | f = Function('f', IntSort(), IntSort())
4 | solve(f(f(x)) == x, f(x) == y, x != y)
5 | 


--------------------------------------------------------------------------------
/examples/z3py.15.py:
--------------------------------------------------------------------------------
 1 | x = Int('x')
 2 | y = Int('y')
 3 | f = Function('f', IntSort(), IntSort())
 4 | s = Solver()
 5 | s.add(f(f(x)) == x, f(x) == y, x != y)
 6 | print s.check()
 7 | m = s.model()
 8 | print "f(f(x)) =", m.evaluate(f(f(x)))
 9 | print "f(x)    =", m.evaluate(f(x))
10 | 
11 | 
12 | 


--------------------------------------------------------------------------------
/examples/z3py.16.py:
--------------------------------------------------------------------------------
 1 | p, q = Bools('p q')
 2 | demorgan = And(p, q) == Not(Or(Not(p), Not(q)))
 3 | print demorgan
 4 | 
 5 | def prove(f):
 6 |     s = Solver()
 7 |     s.add(Not(f))
 8 |     if s.check() == unsat:
 9 |         print "proved"
10 |     else:
11 |         print "failed to prove"
12 | 
13 | print "Proving demorgan..."
14 | prove(demorgan)
15 | 


--------------------------------------------------------------------------------
/examples/z3py.2.py:
--------------------------------------------------------------------------------
1 | x = Int('x')
2 | y = Int('y')
3 | print simplify(x + y + 2*x + 3)
4 | print simplify(x < y + x + 2)
5 | print simplify(And(x + 1 >= 3, x**2 + x**2 + y**2 + 2 >= 5))
6 | 


--------------------------------------------------------------------------------
/examples/z3py.3.py:
--------------------------------------------------------------------------------
 1 | x = Int('x')
 2 | y = Int('y')
 3 | n = x + y >= 3
 4 | print "num args: ", n.num_args()
 5 | print "children: ", n.children()
 6 | print "1st child:", n.arg(0)
 7 | print "2nd child:", n.arg(1)
 8 | print "operator: ", n.decl()
 9 | print "op name:  ", n.decl().name()
10 | 


--------------------------------------------------------------------------------
/examples/z3py.4.py:
--------------------------------------------------------------------------------
1 | x = Real('x')
2 | y = Real('y')
3 | solve(x**2 + y**2 > 3, x**3 + y < 5)
4 | 


--------------------------------------------------------------------------------
/examples/z3py.5.py:
--------------------------------------------------------------------------------
1 | x = Real('x')
2 | y = Real('y')
3 | solve(x**2 + y**2 == 3, x**3 == 2)
4 | 
5 | set_option(precision=30)
6 | print "Solving, and displaying result with 30 decimal places"
7 | solve(x**2 + y**2 == 3, x**3 == 2)
8 | 
9 | 


--------------------------------------------------------------------------------
/examples/z3py.6.py:
--------------------------------------------------------------------------------
 1 | print 1/3
 2 | print RealVal(1)/3
 3 | print Q(1,3)
 4 | 
 5 | x = Real('x')
 6 | print x + 1/3
 7 | print x + Q(1,3)
 8 | print x + "1/3"
 9 | print x + 0.25
10 | 


--------------------------------------------------------------------------------
/examples/z3py.6a.py:
--------------------------------------------------------------------------------
1 | x = Real('x')
2 | solve(x > 4, x < 0)
3 | 


--------------------------------------------------------------------------------
/examples/z3py.6aa.py:
--------------------------------------------------------------------------------
1 | x = Real('x')
2 | solve(3*x == 1)
3 | 
4 | set_option(rational_to_decimal=True)
5 | solve(3*x == 1)
6 | 
7 | set_option(precision=30)
8 | solve(3*x == 1)
9 | 


--------------------------------------------------------------------------------
/examples/z3py.7.py:
--------------------------------------------------------------------------------
1 | p = Bool('p')
2 | q = Bool('q')
3 | r = Bool('r')
4 | solve(Implies(p, q), r == Not(q), Or(Not(p), r))
5 |       
6 | 


--------------------------------------------------------------------------------
/examples/z3py.8.py:
--------------------------------------------------------------------------------
1 | p = Bool('p')
2 | q = Bool('q')
3 | print And(p, q, True)
4 | print simplify(And(p, q, True))
5 | print simplify(And(p, False))
6 | 


--------------------------------------------------------------------------------
/examples/z3py.9.py:
--------------------------------------------------------------------------------
1 | p = Bool('p')
2 | x = Real('x')
3 | solve(Or(x < 5, x > 10), Or(p, x**2 == 2), Not(p))
4 | 


--------------------------------------------------------------------------------
/fixpoint-examples.htm:
--------------------------------------------------------------------------------
  1 | 
  2 | 
  3 | Z3Py Fixedpoints
  4 | 
  5 | 
  6 | 
  7 | 

10 | 11 |

Fixedpoints

12 | 13 |

14 | This tutorial illustrates uses of Z3's fixedpoint engine. 15 | The following papers 16 | 17 | μZ - An Efficient Engine for Fixed-Points with Constraints. 18 | (CAV 2011) and 19 | 20 | Generalized Property Directed Reachability (SAT 2012) 21 | describe some of the main features of the engine. 22 |

23 | 24 |

25 | Please send feedback, comments and/or corrections to 26 | nbjorner@microsoft.com. 27 |

28 | 29 |

Introduction

30 | 31 | 32 |

33 | This tutorial covers some of the fixedpoint utilities available with Z3. 34 | The main features are a basic Datalog engine, an engine with relational 35 | algebra and an engine based on a generalization of the Property 36 | Directed Reachability algorithm. 37 |

38 | 39 | 40 |

Basic Datalog

41 | 42 |

The default fixed-point engine is a bottom-up Datalog engine. 43 | It works with finite relations and uses finite table representations 44 | as hash tables as the default way to represent finite relations. 45 |

46 | 47 |

Relations, rules and queries

48 | 49 | The first example illustrates how to declare relations, rules and 50 | how to pose queries. 51 | 52 | 53 |
fp = Fixedpoint()
 54 | 
 55 | a, b, c = Bools('a b c')
 56 | 
 57 | fp.register_relation(a.decl(), b.decl(), c.decl())
 58 | fp.rule(a,b)
 59 | fp.rule(b,c)
 60 | fp.set(engine='datalog')
 61 | 
 62 | print ("current set of rules\n", fp)
 63 | print (fp.query(a))
 64 | 
 65 | fp.fact(c)
 66 | print ("updated set of rules\n", fp)
 67 | print (fp.query(a))
 68 | print (fp.get_answer())
 69 | 
70 |
71 | 72 | The example illustrates some of the basic constructs. 73 |
 74 |   fp = Fixedpoint()
 75 | 
76 | creates a context for fixed-point computation. 77 |
 78 |  fp.register_relation(a.decl(), b.decl(), c.decl())
 79 | 
80 | Register the relations a, b, c as recursively defined. 81 |
 82 |  fp.rule(a,b)
 83 | 
84 | Create the rule that a follows from b. 85 | In general you can create a rule with multiple premises and a name using 86 | the format 87 |
 88 |  fp.rule(head,[body1,...,bodyN],name)
 89 | 
90 | The name is optional. It is used for tracking the rule in derivation proofs. 91 | 92 | Continuing with the example, a is false unless b is established. 93 |
 94 |  fp.query(a)
 95 | 
96 | Asks if a can be derived. The rules so far say that a 97 | follows if b is established and that b follows if c 98 | is established. But nothing establishes c and b is also not 99 | established, so a cannot be derived. 100 |
101 |  fp.fact(c)
102 | 
103 | Add a fact (shorthand for fp.rule(c,True)). 104 | Now it is the case that a can be derived. 105 | 106 |

Explanations

107 |

108 | It is also possible to get an explanation for a derived query. 109 | For the finite Datalog engine, an explanation is a trace that 110 | provides information of how a fact was derived. The explanation 111 | is an expression whose function symbols are Horn rules and facts used 112 | in the derivation. 113 |

114 | 115 |
fp = Fixedpoint()
116 | 
117 | a, b, c = Bools('a b c')
118 | 
119 | fp.register_relation(a.decl(), b.decl(), c.decl())
120 | fp.rule(a,b)
121 | fp.rule(b,c)
122 | fp.fact(c)
123 | fp.set(generate_explanations=True, engine='datalog')
124 | print (fp.query(a))
125 | print (fp.get_answer())
126 | 
127 |
128 | 129 |

Relations with arguments

130 |

131 | Relations can take arguments. We illustrate relations with arguments 132 | using edges and paths in a graph. 133 |

134 | 135 |
fp = Fixedpoint()
136 | fp.set(engine='datalog')
137 | 
138 | s = BitVecSort(3)
139 | edge = Function('edge', s, s, BoolSort())
140 | path = Function('path', s, s, BoolSort())
141 | a = Const('a',s)
142 | b = Const('b',s)
143 | c = Const('c',s)
144 | 
145 | fp.register_relation(path,edge)
146 | fp.declare_var(a,b,c)
147 | fp.rule(path(a,b), edge(a,b))
148 | fp.rule(path(a,c), [edge(a,b),path(b,c)])
149 | 
150 | v1 = BitVecVal(1,s)
151 | v2 = BitVecVal(2,s)
152 | v3 = BitVecVal(3,s)
153 | v4 = BitVecVal(4,s)
154 | 
155 | fp.fact(edge(v1,v2))
156 | fp.fact(edge(v1,v3))
157 | fp.fact(edge(v2,v4))
158 | 
159 | print ("current set of rules", fp)
160 | 
161 | 
162 | print (fp.query(path(v1,v4)), "yes we can reach v4 from v1")
163 | 
164 | print (fp.query(path(v3,v4)), "no we cannot reach v4 from v3")
165 | 
166 |
167 | 168 | The example uses the declaration 169 |
170 |  fp.declare_var(a,b,c)
171 | 
172 | to instrument the fixed-point engine that a, b, c 173 | should be treated as variables 174 | when they appear in rules. Think of the convention as they way bound variables are 175 | passed to quantifiers in Z3Py. 176 | 177 |

Rush Hour

178 |

179 | A more entertaining example of using the basic fixed point engine 180 | is to solve the Rush Hour puzzle. The puzzle is about moving 181 | a red car out of a gridlock. We have encoded a configuration 182 | and compiled a set of rules that encode the legal moves of the cars 183 | given the configuration. Other configurations can be tested by 184 | changing the parameters passed to the constructor for Car. 185 | We have encoded the configuration from 186 | 187 | an online puzzle you can solve manually, or cheat on by asking Z3. 188 |

189 | 190 |
class Car():
191 |     def __init__(self, is_vertical, base_pos, length, start, color):
192 | 	self.is_vertical = is_vertical
193 | 	self.base = base_pos
194 | 	self.length = length
195 | 	self.start = start
196 | 	self.color = color
197 | 
198 |     def __eq__(self, other):
199 | 	return self.color == other.color
200 | 
201 |     def __ne__(self, other):
202 | 	return self.color != other.color
203 | 
204 | dimension = 6
205 | 
206 | red_car = Car(False, 2, 2, 3, "red")
207 | cars = [
208 |     Car(True, 0, 3, 0, 'yellow'),
209 |     Car(False, 3, 3, 0, 'blue'),
210 |     Car(False, 5, 2, 0, "brown"),
211 |     Car(False, 0, 2, 1, "lgreen"),
212 |     Car(True,  1, 2, 1, "light blue"),
213 |     Car(True,  2, 2, 1, "pink"),
214 |     Car(True,  2, 2, 4, "dark green"),
215 |     red_car,
216 |     Car(True,  3, 2, 3, "purple"),
217 |     Car(False, 5, 2, 3, "light yellow"),
218 |     Car(True,  4, 2, 0, "orange"),
219 |     Car(False, 4, 2, 4, "black"),
220 |     Car(True,  5, 3, 1, "light purple")
221 |     ]
222 | 
223 | num_cars = len(cars)
224 | B = BoolSort()
225 | bv3 = BitVecSort(3)
226 | 
227 | 
228 | state = Function('state', [ bv3 for c in cars] + [B])
229 | 
230 | def num(i):
231 |     return BitVecVal(i,bv3)
232 | 
233 | def bound(i):
234 |     return Const(cars[i].color, bv3)
235 | 
236 | fp = Fixedpoint()
237 | fp.set(generate_explanations=True)
238 | fp.declare_var([bound(i) for i in range(num_cars)])
239 | fp.register_relation(state)
240 | 
241 | def mk_state(car, value):
242 |     return state([ (num(value) if (cars[i] == car) else bound(i))
243 | 		   for i in range(num_cars)])
244 | 
245 | def mk_transition(row, col, i0, j, car0):
246 |     body = [mk_state(car0, i0)]
247 |     for index in range(num_cars):
248 | 	car = cars[index]
249 | 	if car0 != car:
250 | 	    if car.is_vertical and car.base == col:
251 | 		for i in range(dimension):
252 | 		    if i <= row and row < i + car.length and i + car.length <= dimension:
253 | 			   body += [bound(index) != num(i)]
254 | 	    if car.base == row and not car.is_vertical:
255 | 		for i in range(dimension):
256 | 		    if i <= col and col < i + car.length and i + car.length <= dimension:
257 | 			   body += [bound(index) != num(i)]
258 | 
259 |     s = "%s %d->%d" % (car0.color, i0, j)
260 | 			
261 |     fp.rule(mk_state(car0, j), body, s)
262 |     
263 | 
264 | def move_down(i, car):
265 |     free_row = i + car.length
266 |     if free_row < dimension:
267 | 	mk_transition(free_row, car.base, i, i + 1, car)
268 |             
269 | 
270 | def move_up(i, car):
271 |     free_row = i  - 1
272 |     if 0 <= free_row and i + car.length <= dimension:
273 | 	mk_transition(free_row, car.base, i, i - 1, car)
274 | 
275 | def move_left(i, car):
276 |     free_col = i - 1;
277 |     if 0 <= free_col and i + car.length <= dimension:
278 | 	mk_transition(car.base, free_col, i, i - 1, car)
279 | 	
280 | 
281 | def move_right(i, car):
282 |     free_col = car.length + i
283 |     if free_col < dimension:
284 | 	mk_transition(car.base, free_col, i, i + 1, car)
285 | 	
286 | 
287 | # Initial state:
288 | fp.fact(state([num(cars[i].start) for i in range(num_cars)]))
289 | 
290 | # Transitions:
291 | for car in cars:
292 |     for i in range(dimension):
293 | 	if car.is_vertical:
294 | 	    move_down(i, car)
295 | 	    move_up(i, car)
296 | 	else:
297 | 	    move_left(i, car)
298 | 	    move_right(i, car)
299 |     
300 | 
301 | def get_instructions(ans):
302 |     lastAnd = ans.arg(0).children()[-1]
303 |     trace = lastAnd.children()[1]
304 |     while trace.num_args() > 0:
305 | 	print (trace.decl())
306 | 	trace = trace.children()[-1]
307 | 
308 | print (fp)
309 | 
310 | goal = state([ (num(4) if cars[i] == red_car else bound(i))
311 | 	       for i in range(num_cars)])
312 | fp.query(goal)
313 | 
314 | get_instructions(fp.get_answer())
315 |     
316 | 
317 |
318 | 319 | 320 |

Abstract Domains

321 | The underlying engine uses table operations 322 | that are based on relational algebra. Representations are 323 | opaque to the underlying engine. 324 | Relational algebra operations are well defined for arbitrary relations. 325 | They don't depend on whether the relations denote a finite or an 326 | infinite set of values. 327 | Z3 contains two built-in tables for infinite domains. 328 | The first is for intervals of integers and reals. 329 | The second is for bound constraints between two integers or reals. 330 | A bound constraint is of the form x or x . 331 | When used in conjunction, they form 332 | an abstract domain that is called the 333 | 334 | Pentagon abstract 335 | domain. Z3 implements reduced products 336 | of abstract domains that enables sharing constraints between 337 | the interval and bounds domains. 338 | 339 |

340 | Below we give a simple example that illustrates a loop at location l0. 341 | The loop is incremented as long as the loop counter does not exceed an upper 342 | bound. Using the combination of bound and interval domains 343 | we can collect derived invariants from the loop and we can also establish 344 | that the state after the loop does not exceed the bound. 345 |

346 | 347 | 348 | 349 |
I  = IntSort()
350 | B  = BoolSort()
351 | l0 = Function('l0',I,I,B)
352 | l1 = Function('l1',I,I,B)
353 | 
354 | s = Fixedpoint()
355 | s.set(engine='datalog',compile_with_widening=True,
356 |       unbound_compressor=False)
357 | 
358 | s.register_relation(l0,l1)
359 | s.set_predicate_representation(l0, 'interval_relation', 'bound_relation')
360 | s.set_predicate_representation(l1, 'interval_relation', 'bound_relation')
361 | 
362 | m, x, y = Ints('m x y')
363 | 
364 | s.declare_var(m, x, y)
365 | s.rule(l0(0,m),   0 < m)
366 | s.rule(l0(x+1,m), [l0(x,m), x < m])
367 | s.rule(l1(x,m),   [l0(x,m), m <= x])
368 | 
369 | print ("At l0 we learn that x, y are non-negative:")
370 | print (s.query(l0(x,y)))
371 | print (s.get_answer())
372 | 
373 | print ("At l1 we learn that x <= y and both x and y are bigger than 0:")
374 | print (s.query(l1(x,y)))
375 | print (s.get_answer())
376 | 
377 | 
378 | print ("The state where x < y is not reachable")
379 | print (s.query(And(l1(x,y), x < y)))
380 | 
381 |
382 | 383 | The example uses the option 384 |
385 |    set_option(dl_compile_with_widening=True)
386 | 
387 | to instrument Z3 to apply abstract interpretation widening on loop boundaries. 388 | 389 | 390 |

Engine for Property Directed Reachability

391 | 392 | A different underlying engine for fixed-points is based on 393 | an algorithm for Property Directed Reachability (PDR). 394 | The PDR engine is enabled using the instruction 395 |
396 |   set_option(dl_engine=1)
397 | 
398 | The version in Z3 applies to Horn clauses with arithmetic and 399 | Boolean domains. When using arithmetic you should enable 400 | the main abstraction engine used in Z3 for arithmetic in PDR. 401 |
402 |  set_option(dl_pdr_use_farkas=True)
403 | 
404 | The engine also works with domains using algebraic 405 | data-types and bit-vectors, although it is currently not 406 | overly tuned for either. 407 | The PDR engine is targeted at applications from symbolic model 408 | checking of software. The systems may be infinite state. 409 | The following examples also serve a purpose of showing 410 | how software model checking problems (of safety properties) 411 | can be embedded into Horn clauses and solved using PDR. 412 | 413 |

Procedure Calls

414 |

415 | McCarthy's 91 function illustrates a procedure that calls itself recursively 416 | twice. The Horn clauses below encode the recursive function: 417 | 418 |

419 |
420 |   mc(x) = if x > 100 then x - 10 else mc(mc(x+11))
421 | 
422 | 423 | The general scheme for encoding recursive procedures is by creating a predicate 424 | for each procedure and adding an additional output variable to the predicate. 425 | Nested calls to procedures within a body can be encoded as a conjunction 426 | of relations. 427 | 428 | 429 | 430 |
mc = Function('mc', IntSort(), IntSort(), BoolSort())
431 | n, m, p = Ints('n m p')
432 | 
433 | fp = Fixedpoint()
434 | 
435 | fp.declare_var(n,m)
436 | fp.register_relation(mc)
437 | 
438 | fp.rule(mc(m, m-10), m > 100)
439 | fp.rule(mc(m, n), [m <= 100, mc(m+11,p),mc(p,n)])
440 |     
441 | print (fp.query(And(mc(m,n),n < 90)))
442 | print (fp.get_answer())
443 | 
444 | print (fp.query(And(mc(m,n),n < 91)))
445 | print (fp.get_answer())
446 | 
447 | print (fp.query(And(mc(m,n),n < 92)))
448 | print (fp.get_answer())
449 | 
450 |
451 | 452 | The first two queries are unsatisfiable. The PDR engine produces the same proof of unsatisfiability. 453 | The proof is an inductive invariant for each recursive predicate. The PDR engine introduces a 454 | special query predicate for the query. 455 | 456 |

Bakery

457 | 458 |

459 | We can also prove invariants of reactive systems. It is convenient to encode reactive systems 460 | as guarded transition systems. It is perhaps for some not as convenient to directly encode 461 | guarded transitions as recursive Horn clauses. But it is fairly easy to write a translator 462 | from guarded transition systems to recursive Horn clauses. We illustrate a translator 463 | and Lamport's two process Bakery algorithm in the next example. 464 |

465 | 466 | 467 |
set_option(relevancy=0,verbose=1)
468 | 
469 | def flatten(l):
470 |     return [s for t in l for s in t]
471 | 
472 | 
473 | class TransitionSystem():
474 |     def __init__(self, initial, transitions, vars1):
475 | 	self.fp = Fixedpoint()        
476 | 	self.initial     = initial
477 | 	self.transitions = transitions
478 | 	self.vars1 = vars1
479 | 
480 |     def declare_rels(self):
481 | 	B = BoolSort()
482 | 	var_sorts   = [ v.sort() for v in self.vars1 ]
483 | 	state_sorts = var_sorts
484 | 	self.state_vals = [ v for v in self.vars1 ]
485 | 	self.state_sorts  = state_sorts
486 | 	self.var_sorts = var_sorts
487 | 	self.state  = Function('state', state_sorts + [ B ])
488 | 	self.step   = Function('step',  state_sorts + state_sorts + [ B ])
489 | 	self.fp.register_relation(self.state)
490 | 	self.fp.register_relation(self.step)
491 | 
492 | # Set of reachable states are transitive closure of step.
493 | 
494 |     def state0(self):
495 | 	idx = range(len(self.state_sorts))
496 | 	return self.state([Var(i,self.state_sorts[i]) for i in idx])
497 | 	
498 |     def state1(self):
499 | 	n = len(self.state_sorts)
500 | 	return self.state([Var(i+n, self.state_sorts[i]) for i in range(n)])
501 | 
502 |     def rho(self):
503 | 	n = len(self.state_sorts)
504 | 	args1 = [ Var(i,self.state_sorts[i]) for i in range(n) ]
505 | 	args2 = [ Var(i+n,self.state_sorts[i]) for i in range(n) ]
506 | 	args = args1 + args2 
507 | 	return self.step(args)
508 | 
509 |     def declare_reachability(self):
510 | 	self.fp.rule(self.state1(), [self.state0(), self.rho()])
511 | 
512 | 
513 | # Define transition relation
514 | 
515 |     def abstract(self, e):
516 | 	n = len(self.state_sorts)
517 | 	sub = [(self.state_vals[i], Var(i,self.state_sorts[i])) for i in range(n)]
518 | 	return substitute(e, sub)
519 | 	
520 |     def declare_transition(self, tr):
521 | 	len_s  = len(self.state_sorts)
522 | 	effect = tr["effect"]
523 | 	vars1  = [Var(i,self.state_sorts[i]) for i in range(len_s)] + effect
524 | 	rho1  = self.abstract(self.step(vars1))
525 | 	guard = self.abstract(tr["guard"])
526 | 	self.fp.rule(rho1, guard)
527 | 	
528 |     def declare_transitions(self):
529 | 	for t in self.transitions:
530 | 	    self.declare_transition(t)
531 | 
532 |     def declare_initial(self):
533 | 	self.fp.rule(self.state0(),[self.abstract(self.initial)])
534 | 	
535 |     def query(self, query):
536 | 	self.declare_rels()
537 | 	self.declare_initial()
538 | 	self.declare_reachability()
539 | 	self.declare_transitions()
540 | 	query = And(self.state0(), self.abstract(query))
541 | 	print (self.fp)
542 | 	print (query)
543 | 	print (self.fp.query(query))
544 | 	print (self.fp.get_answer())
545 | #	print self.fp.statistics()
546 | 
547 | 
548 | L = Datatype('L')
549 | L.declare('L0')
550 | L.declare('L1')
551 | L.declare('L2')
552 | L = L.create()
553 | L0 = L.L0
554 | L1 = L.L1
555 | L2 = L.L2
556 | 
557 | 
558 | y0 = Int('y0')
559 | y1 = Int('y1')
560 | l  = Const('l', L)
561 | m  = Const('m', L)
562 | 
563 | 
564 | t1 = { "guard" : l == L0,
565 |        "effect" : [ L1, y1 + 1, m, y1 ] }
566 | t2 = { "guard" : And(l == L1, Or([y0 <= y1, y1 == 0])),
567 |        "effect" : [ L2, y0,     m, y1 ] }
568 | t3 = { "guard" : l == L2,
569 |        "effect" : [ L0, IntVal(0), m, y1 ]}
570 | s1 = { "guard" : m == L0,
571 |        "effect" : [ l,  y0, L1, y0 + 1 ] }
572 | s2 = { "guard" : And(m == L1, Or([y1 <= y0, y0 == 0])),
573 |        "effect" : [ l,  y0, L2, y1 ] }
574 | s3 = { "guard" : m == L2,
575 |        "effect" : [ l,  y0, L0, IntVal(0) ]}
576 | 
577 | 
578 | ptr = TransitionSystem( And(l == L0, y0 == 0, m == L0, y1 == 0),
579 | 			[t1, t2, t3, s1, s2, s3],
580 | 			[l, y0, m, y1])
581 | 
582 | ptr.query(And([l == L2, m == L2 ]))
583 | 
584 |
585 | The rather verbose (and in no way minimal) inductive invariants are produced as answers. 586 | 587 |

Functional Programs

588 | We can also verify some properties of functional programs using Z3's 589 | generalized PDR. Let us here consider an example from 590 | 591 | Predicate Abstraction and CEGAR for Higher-Order Model 592 | Checking, Kobayashi et.al. PLDI 2011. 593 | We encode functional programs by taking a suitable operational 594 | semantics and encoding an evaluator that is specialized to 595 | the program being verified (we don't encode a general purpose 596 | evaluator, you should partial evaluate it to help verification). 597 | We use algebraic data-types to encode the current closure that is 598 | being evaluated. 599 | 600 | 601 |
# let max max2 x y z = max2 (max2 x y) z
602 | # let f x y = if x > y then x else y
603 | # assert (f (max f x y z) x) = (max f x y z)
604 | 
605 | 
606 | Expr = Datatype('Expr')
607 | Expr.declare('Max')
608 | Expr.declare('f')
609 | Expr.declare('I', ('i', IntSort()))
610 | Expr.declare('App', ('fn',Expr),('arg',Expr))
611 | Expr = Expr.create()
612 | Max  = Expr.Max
613 | I    = Expr.I
614 | App  = Expr.App
615 | f    = Expr.f
616 | Eval = Function('Eval',Expr,Expr,Expr,BoolSort())
617 | 
618 | x   = Const('x',Expr)
619 | y   = Const('y',Expr)
620 | z   = Const('z',Expr)
621 | r1  = Const('r1',Expr)
622 | r2  = Const('r2',Expr)
623 | max = Const('max',Expr)
624 | xi  = Const('xi',IntSort())
625 | yi  = Const('yi',IntSort())
626 | 
627 | fp = Fixedpoint()
628 | fp.register_relation(Eval)
629 | fp.declare_var(x,y,z,r1,r2,max,xi,yi)
630 | 
631 | # Max max x y z = max (max x y) z
632 | fp.rule(Eval(App(App(App(Max,max),x),y), z, r2),
633 | 	[Eval(App(max,x),y,r1),
634 | 	 Eval(App(max,r1),z,r2)])
635 | 
636 | # f x y = x if x >= y
637 | # f x y = y if x < y
638 | fp.rule(Eval(App(f,I(xi)),I(yi),I(xi)),xi >= yi)
639 | fp.rule(Eval(App(f,I(xi)),I(yi),I(yi)),xi < yi)
640 | 
641 | print (fp.query(And(Eval(App(App(App(Max,f),x),y),z,r1),)
642 | 		   Eval(App(f,x),r1,r2),
643 | 		   r1 != r2))
644 | 
645 | print (fp.get_answer())
646 | 
647 |
648 | 649 | 650 | 651 | 652 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /installation-guide.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ericpony/z3py-tutorial/de86c5e47c7ded29853c6d69ca6ac5c8b9b6c4aa/installation-guide.pdf -------------------------------------------------------------------------------- /strategies-examples.htm: -------------------------------------------------------------------------------- 1 | 2 | 3 | Z3Py Strategies 4 | 5 | 6 | 7 |

10 | 11 |

Strategies

12 | 13 |

14 | High-performance solvers, such as Z3, contain many tightly integrated, handcrafted heuristic 15 | combinations of algorithmic proof methods. While these heuristic 16 | combinations tend to be highly tuned for known classes of problems, 17 | they may easily perform very badly on new classes of problems. 18 | This issue is becoming increasingly pressing 19 | as solvers begin to gain the attention of practitioners in diverse areas of science and engineering. 20 | In many cases, changes to the solver heuristics can make a 21 | tremendous difference. 22 |

23 | 24 |

25 | In this tutorial we show how to create custom strategies using the basic building blocks 26 | available in Z3. Z3Py and Z3 4.0 implement the ideas proposed in this article. 27 |

28 | 29 |

30 | Please send feedback, comments and/or corrections to leonardo@microsoft.com. 31 | Your comments are very valuable. 32 |

33 | 34 |

Introduction

35 | 36 |

37 | Z3 implements a methodology for orchestrating reasoning 38 | engines where "big" symbolic reasoning steps are represented as 39 | functions known as tactics, and tactics are composed using 40 | combinators known as tacticals. Tactics process sets of 41 | formulas called Goals. 42 |

43 | 44 |

45 | When a tactic is applied to some goal G, four different outcomes 46 | are possible. The tactic succeeds in showing G to be satisfiable (i.e., feasible); 47 | succeeds in showing G to be unsatisfiable (i.e., infeasible); produces a sequence of subgoals; or fails. 48 | When reducing a goal G to a sequence of subgoals G1, ..., 49 | Gn, we face the problem of model conversion. 50 | A model converter construct a model for G 51 | using a model for some subgoal Gi. 52 |

53 | 54 |

In the following example, we create a goal g consisting of three formulas, and a tactic t 55 | composed of two built-in tactics: simplify and solve-eqs. The tactic simplify 56 | apply transformations equivalent to the ones found in the command simplify. The tactic solver-eqs 57 | eliminate variables using Gaussian elimination. Actually, solve-eqs is not restricted only to linear arithmetic. 58 | It can also eliminate arbitrary variables. Then, combinator Then applies simplify to the input goal 59 | and solve-eqs to each subgoal produced by simplify. In this example, only one subgoal is produced. 60 |

61 | 62 | 63 |
x, y = Reals('x y')
 64 | g  = Goal()
 65 | g.add(x > 0, y > 0, x == y + 2)
 66 | print (g)
 67 | 
 68 | t1 = Tactic('simplify')
 69 | t2 = Tactic('solve-eqs')
 70 | t  = Then(t1, t2)
 71 | print (t(g))
 72 | 
73 |
74 | 75 |

In the example above, variable x is eliminated, and is not present the resultant goal. 76 |

77 | 78 |

In Z3, we say a clause is any constraint of the form Or(f_1, ..., f_n). 79 | The tactic split-clause will select a clause Or(f_1, ..., f_n) in the input goal, and split it 80 | n subgoals. One for each subformula f_i. 81 |

82 | 83 | 84 |
x, y = Reals('x y')
 85 | g  = Goal()
 86 | g.add(Or(x < 0, x > 0), x == y + 1, y < 0)
 87 | 
 88 | t = Tactic('split-clause')
 89 | r = t(g)
 90 | for g in r: 
 91 |     print (g)
 92 | 
93 |
94 | 95 |

Tactics

96 | 97 |

Z3 comes equipped with many built-in tactics. 98 | The command describe_tactics() provides a short description of all built-in tactics. 99 |

100 | 101 | 102 |
describe_tactics()
103 | 
104 |
105 | 106 |

Z3Py comes equipped with the following tactic combinators (aka tacticals): 107 |

108 | 109 |
    110 |
  • Then(t, s) 111 | applies t to the input goal and s 112 | to every subgoal produced by t. 113 |
  • 114 |
  • OrElse(t, s) 115 | first applies t to the given goal, 116 | if it fails then returns the result of s applied to the given goal. 117 |
  • 118 |
  • Repeat(t) Keep applying the given tactic until no subgoal is modified by it. 119 |
  • 120 |
  • Repeat(t, n) Keep applying the given tactic until no subgoal is modified by it, or 121 | the number of iterations is greater than n. 122 |
  • 123 |
  • TryFor(t, ms) Apply tactic t to the input goal, if it does not return in 124 | ms millisenconds, it fails. 125 |
  • 126 |
  • With(t, params) Apply the given tactic using the given parameters. 127 |
  • 128 |
129 | 130 |

The following example demonstrate how to use these combinators.

131 | 132 | 133 |
x, y, z = Reals('x y z')
134 | g = Goal()
135 | g.add(Or(x == 0, x == 1), 
136 |       Or(y == 0, y == 1), 
137 |       Or(z == 0, z == 1),
138 |       x + y + z > 2)
139 | 
140 | # Split all clauses"
141 | split_all = Repeat(OrElse(Tactic('split-clause'),
142 |                           Tactic('skip')))
143 | print (split_all(g))
144 | 
145 | split_at_most_2 = Repeat(OrElse(Tactic('split-clause'),
146 |                           Tactic('skip')),
147 |                          1)
148 | print (split_at_most_2(g))
149 | 
150 | # Split all clauses and solve equations
151 | split_solve = Then(Repeat(OrElse(Tactic('split-clause'),
152 |                                  Tactic('skip'))),
153 |                    Tactic('solve-eqs'))
154 | 
155 | print (split_solve(g))
156 | 
157 |
158 | 159 |

In the tactic split_solver, the tactic solve-eqs discharges all but one goal. 160 | Note that, this tactic generates one goal: the empty goal which is trivially satisfiable (i.e., feasible)

161 | 162 |

The list of subgoals can be easily traversed using the Python for statement.

163 | 164 | 165 |
x, y, z = Reals('x y z')
166 | g = Goal()
167 | g.add(Or(x == 0, x == 1), 
168 |       Or(y == 0, y == 1), 
169 |       Or(z == 0, z == 1),
170 |       x + y + z > 2)
171 | 
172 | # Split all clauses"
173 | split_all = Repeat(OrElse(Tactic('split-clause'),
174 |                           Tactic('skip')))
175 | for s in split_all(g):
176 |     print (s)
177 | 
178 |
179 | 180 |

A tactic can be converted into a solver object using the method solver(). 181 | If the tactic produces the empty goal, then the associated solver returns sat. 182 | If the tactic produces a single goal containing False, then the solver returns unsat. 183 | Otherwise, it returns unknown. 184 |

185 | 186 | 187 |
bv_solver = Then('simplify', 
188 |                  'solve-eqs', 
189 |                  'bit-blast', 
190 |                  'sat').solver()
191 | 
192 | x, y = BitVecs('x y', 16)
193 | solve_using(bv_solver, x | y == 13, x > y)
194 | 
195 |
196 | 197 |

In the example above, the tactic bv_solver implements a basic bit-vector solver using equation solving, 198 | bit-blasting, and a propositional SAT solver. Note that, the command Tactic is suppressed. 199 | All Z3Py combinators automatically invoke Tactic command if the argument is a string. 200 | Finally, the command solve_using is a variant of the solve command where the first 201 | argument specifies the solver to be used. 202 |

203 | 204 |

In the following example, we use the solver API directly instead of the command solve_using. 205 | We use the combinator With to configure our little solver. We also include the tactic aig 206 | which tries to compress Boolean formulas using And-Inverted Graphs. 207 |

208 | 209 | 210 |
bv_solver = Then(With('simplify', mul2concat=True),
211 |                  'solve-eqs', 
212 |                  'bit-blast', 
213 |                  'aig',
214 |                  'sat').solver()
215 | x, y = BitVecs('x y', 16)
216 | bv_solver.add(x*32 + y == 13, x & y < 10, y > -100)
217 | print (bv_solver.check())
218 | m = bv_solver.model()
219 | print (m)
220 | print (x*32 + y, "==", m.evaluate(x*32 + y))
221 | print (x & y, "==", m.evaluate(x & y))
222 | 
223 |
224 | 225 |

The tactic smt wraps the main solver in Z3 as a tactic.

226 | 227 | 228 |
x, y = Ints('x y')
229 | s = Tactic('smt').solver()
230 | s.add(x > y + 1)
231 | print (s.check())
232 | print (s.model())
233 | 
234 |
235 | 236 |

Now, we show how to implement a solver for integer arithmetic using SAT. The solver is complete 237 | only for problems where every variable has a lower and upper bound. 238 |

239 | 240 | 241 |
s = Then(With('simplify', arith_lhs=True, som=True),
242 |          'normalize-bounds', 'lia2pb', 'pb2bv', 
243 |          'bit-blast', 'sat').solver()
244 | x, y, z = Ints('x y z')
245 | solve_using(s, 
246 |             x > 0, x < 10, 
247 |             y > 0, y < 10, 
248 |             z > 0, z < 10,
249 |             3*y + 2*x == z)
250 | # It fails on the next example (it is unbounded)
251 | s.reset()
252 | solve_using(s, 3*y + 2*x == z)
253 | 
254 |
255 | 256 |

257 | Tactics can be combined with solvers. For example, we can apply a tactic to a goal, produced a set of subgoals, 258 | then select one of the subgoals and solve it using a solver. The next example demonstrates how to do that, and how to 259 | use model converters to convert a model for a subgoal into a model for the original goal. 260 |

261 | 262 | 263 |
t = Then('simplify', 
264 |          'normalize-bounds', 
265 |          'solve-eqs')
266 | 
267 | x, y, z = Ints('x y z')
268 | g = Goal()
269 | g.add(x > 10, y == x + 3, z > y)
270 | 
271 | r = t(g)
272 | # r contains only one subgoal
273 | print (r)
274 | 
275 | s = Solver()
276 | s.add(r[0])
277 | print (s.check())
278 | # Model for the subgoal
279 | print (s.model())
280 | # Model for the original goal
281 | print (r.convert_model(s.model()))
282 | 
283 |
284 | 285 |

Probes

286 | 287 |

288 | Probes (aka formula measures) are evaluated over goals. 289 | Boolean expressions over them can be built using relational operators and Boolean connectives. 290 | The tactic FailIf(cond) fails if the given goal does not satisfy the condition cond. 291 | Many numeric and Boolean measures are available in Z3Py. The command describe_probes() provides the list of 292 | all built-in probes. 293 |

294 | 295 | 296 |
describe_probes()
297 | 
298 |
299 | 300 |

In the following example, we build a simple tactic using FailIf. It also shows that a probe can be applied directly 301 | to a goal.

302 | 303 | 304 |
x, y, z = Reals('x y z')
305 | g = Goal()
306 | g.add(x + y + z > 0)
307 | 
308 | p = Probe('num-consts')
309 | print ("num-consts:", p(g))
310 | 
311 | t = FailIf(p > 2)
312 | try:
313 |     t(g)
314 | except Z3Exception:
315 |     print ("tactic failed")
316 | 
317 | print ("trying again...")
318 | g = Goal()
319 | g.add(x + y > 0)
320 | print (t(g))
321 | 
322 |
323 | 324 |

Z3Py also provides the combinator (tactical) If(p, t1, t2) which is a shorthand for:

325 | 326 |
OrElse(Then(FailIf(Not(p)), t1), t2)
327 | 328 |

The combinator When(p, t) is a shorthand for:

329 | 330 |
If(p, t, 'skip')
331 | 332 |

The tactic skip just returns the input goal. 333 | The following example demonstrates how to use the If combinator.

334 | 335 | 336 |
x, y, z = Reals('x y z')
337 | g = Goal()
338 | g.add(x**2 - y**2 >= 0)
339 | 
340 | p = Probe('num-consts')
341 | t = If(p > 2, 'simplify', 'factor')
342 | 
343 | print (t(g))
344 | 
345 | g = Goal()
346 | g.add(x + x + y + z >= 0, x**2 - y**2 >= 0)
347 | 
348 | print (t(g))
349 | 
350 |
351 | 352 | 353 | 354 | -------------------------------------------------------------------------------- /style.css: -------------------------------------------------------------------------------- 1 | body { margin: 4em; margin-top: 2em } 2 | h1,h2,h3 { margin-left: -1em } 3 | .hll { background-color: #ffffcc } 4 | .c { color: #408080; font-style: italic } /* Comment */ 5 | .err { border: 1px solid #FF0000 } /* Error */ 6 | .k { color: #008000; font-weight: bold } /* Keyword */ 7 | .o { color: #666666 } /* Operator */ 8 | .cm { color: #408080; font-style: italic } /* Comment.Multiline */ 9 | .cp { color: #BC7A00 } /* Comment.Preproc */ 10 | .c1 { color: #408080; font-style: italic } /* Comment.Single */ 11 | .cs { color: #408080; font-style: italic } /* Comment.Special */ 12 | .gd { color: #A00000 } /* Generic.Deleted */ 13 | .ge { font-style: italic } /* Generic.Emph */ 14 | .gr { color: #FF0000 } /* Generic.Error */ 15 | .gh { color: #000080; font-weight: bold } /* Generic.Heading */ 16 | .gi { color: #00A000 } /* Generic.Inserted */ 17 | .go { color: #888888 } /* Generic.Output */ 18 | .gp { color: #000080; font-weight: bold } /* Generic.Prompt */ 19 | .gs { font-weight: bold } /* Generic.Strong */ 20 | .gu { color: #800080; font-weight: bold } /* Generic.Subheading */ 21 | .gt { color: #0044DD } /* Generic.Traceback */ 22 | .kc { color: #008000; font-weight: bold } /* Keyword.Constant */ 23 | .kd { color: #008000; font-weight: bold } /* Keyword.Declaration */ 24 | .kn { color: #008000; font-weight: bold } /* Keyword.Namespace */ 25 | .kp { color: #008000 } /* Keyword.Pseudo */ 26 | .kr { color: #008000; font-weight: bold } /* Keyword.Reserved */ 27 | .kt { color: #B00040 } /* Keyword.Type */ 28 | .m { color: #666666 } /* Literal.Number */ 29 | .s { color: #BA2121 } /* Literal.String */ 30 | .na { color: #7D9029 } /* Name.Attribute */ 31 | .nb { color: #008000 } /* Name.Builtin */ 32 | .nc { color: #0000FF; font-weight: bold } /* Name.Class */ 33 | .no { color: #880000 } /* Name.Constant */ 34 | .nd { color: #AA22FF } /* Name.Decorator */ 35 | .ni { color: #999999; font-weight: bold } /* Name.Entity */ 36 | .ne { color: #D2413A; font-weight: bold } /* Name.Exception */ 37 | .nf { color: #0000FF } /* Name.Function */ 38 | .nl { color: #A0A000 } /* Name.Label */ 39 | .nn { color: #0000FF; font-weight: bold } /* Name.Namespace */ 40 | .nt { color: #008000; font-weight: bold } /* Name.Tag */ 41 | .nv { color: #19177C } /* Name.Variable */ 42 | .ow { color: #AA22FF; font-weight: bold } /* Operator.Word */ 43 | .w { color: #bbbbbb } /* Text.Whitespace */ 44 | .mf { color: #666666 } /* Literal.Number.Float */ 45 | .mh { color: #666666 } /* Literal.Number.Hex */ 46 | .mi { color: #666666 } /* Literal.Number.Integer */ 47 | .mo { color: #666666 } /* Literal.Number.Oct */ 48 | .sb { color: #BA2121 } /* Literal.String.Backtick */ 49 | .sc { color: #BA2121 } /* Literal.String.Char */ 50 | .sd { color: #BA2121; font-style: italic } /* Literal.String.Doc */ 51 | .s2 { color: #BA2121 } /* Literal.String.Double */ 52 | .se { color: #BB6622; font-weight: bold } /* Literal.String.Escape */ 53 | .sh { color: #BA2121 } /* Literal.String.Heredoc */ 54 | .si { color: #BB6688; font-weight: bold } /* Literal.String.Interpol */ 55 | .sx { color: #008000 } /* Literal.String.Other */ 56 | .sr { color: #BB6688 } /* Literal.String.Regex */ 57 | .s1 { color: #BA2121 } /* Literal.String.Single */ 58 | .ss { color: #19177C } /* Literal.String.Symbol */ 59 | .bp { color: #008000 } /* Name.Builtin.Pseudo */ 60 | .vc { color: #19177C } /* Name.Variable.Class */ 61 | .vg { color: #19177C } /* Name.Variable.Global */ 62 | .vi { color: #19177C } /* Name.Variable.Instance */ 63 | .il { color: #666666 } /* Literal.Number.Integer.Long */ 64 | --------------------------------------------------------------------------------