mirror of
				https://github.com/Z3Prover/z3
				synced 2025-10-31 03:32:28 +00:00 
			
		
		
		
	html pages for z3 python tutorial
Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com>
This commit is contained in:
		
							parent
							
								
									165c0ef3e1
								
							
						
					
					
						commit
						e0a49dd556
					
				
					 5 changed files with 2964 additions and 0 deletions
				
			
		
							
								
								
									
										861
									
								
								examples/python/tutorial/html/advanced-examples.htm
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										861
									
								
								examples/python/tutorial/html/advanced-examples.htm
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,861 @@ | |||
| <html> | ||||
| <head> | ||||
| <title>Z3Py Advanced</title> | ||||
| <link rel="StyleSheet" href="style.css" type="text/css"> | ||||
| </head> | ||||
| <body> | ||||
| 
 | ||||
| <h1>Advanced Topics</h1> | ||||
| 
 | ||||
| <p> | ||||
| Please send feedback, comments and/or corrections to <a href="mailto:leonardo@microsoft.com">leonardo@microsoft.com</a>. | ||||
| Your comments are very valuable. | ||||
| </p> | ||||
| 
 | ||||
| <h2>Expressions, Sorts and Declarations</h2> | ||||
| 
 | ||||
| <p>In Z3, expressions, sorts and declarations are called <i>ASTs</i>. | ||||
| ASTs are directed acyclic graphs. Every expression has a sort (aka type). | ||||
| The method <tt>sort()</tt> retrieves the sort of an expression. | ||||
| </p> | ||||
| 
 | ||||
| <example pref="expr.1"><html><body> | ||||
| <div class="highlight"><pre><span class="n">x</span> <span class="o">=</span> <span class="n">Int</span><span class="p">(</span><span class="s">'x'</span><span class="p">)</span> | ||||
| <span class="n">y</span> <span class="o">=</span> <span class="n">Real</span><span class="p">(</span><span class="s">'y'</span><span class="p">)</span> | ||||
| <span class="k">print</span> <span class="p">(</span><span class="n">x</span> <span class="o">+</span> <span class="mi">1</span><span class="p">)</span><span class="o">.</span><span class="n">sort</span><span class="p">()</span> | ||||
| <span class="k">print</span> <span class="p">(</span><span class="n">y</span> <span class="o">+</span> <span class="mi">1</span><span class="p">)</span><span class="o">.</span><span class="n">sort</span><span class="p">()</span> | ||||
| <span class="k">print</span> <span class="p">(</span><span class="n">x</span> <span class="o">>=</span> <span class="mi">2</span><span class="p">)</span><span class="o">.</span><span class="n">sort</span><span class="p">()</span> | ||||
| </pre></div> | ||||
| </body></html></example> | ||||
| 
 | ||||
| <p>The function <tt>eq(n1, n2)</tt> returns <tt>True</tt> if <tt>n1</tt> | ||||
| and <tt>n2</tt> are the same AST. This is a structural test.  | ||||
| </p> | ||||
| 
 | ||||
| <example pref="expr.2"><html><body> | ||||
| <div class="highlight"><pre><span class="n">x</span><span class="p">,</span> <span class="n">y</span> <span class="o">=</span> <span class="n">Ints</span><span class="p">(</span><span class="s">'x y'</span><span class="p">)</span> | ||||
| <span class="k">print</span> <span class="n">eq</span><span class="p">(</span><span class="n">x</span> <span class="o">+</span> <span class="n">y</span><span class="p">,</span> <span class="n">x</span> <span class="o">+</span> <span class="n">y</span><span class="p">)</span> | ||||
| <span class="k">print</span> <span class="n">eq</span><span class="p">(</span><span class="n">x</span> <span class="o">+</span> <span class="n">y</span><span class="p">,</span> <span class="n">y</span> <span class="o">+</span> <span class="n">x</span><span class="p">)</span> | ||||
| <span class="n">n</span> <span class="o">=</span> <span class="n">x</span> <span class="o">+</span> <span class="n">y</span> | ||||
| <span class="k">print</span> <span class="n">eq</span><span class="p">(</span><span class="n">n</span><span class="p">,</span> <span class="n">x</span> <span class="o">+</span> <span class="n">y</span><span class="p">)</span> | ||||
| <span class="c"># x2 is eq to x</span> | ||||
| <span class="n">x2</span> <span class="o">=</span> <span class="n">Int</span><span class="p">(</span><span class="s">'x'</span><span class="p">)</span>  | ||||
| <span class="k">print</span> <span class="n">eq</span><span class="p">(</span><span class="n">x</span><span class="p">,</span> <span class="n">x2</span><span class="p">)</span> | ||||
| <span class="c"># the integer variable x is not equal to </span> | ||||
| <span class="c"># the real variable x</span> | ||||
| <span class="k">print</span> <span class="n">eq</span><span class="p">(</span><span class="n">Int</span><span class="p">(</span><span class="s">'x'</span><span class="p">),</span> <span class="n">Real</span><span class="p">(</span><span class="s">'x'</span><span class="p">))</span> | ||||
| </pre></div> | ||||
| </body></html></example> | ||||
| 
 | ||||
| <p>The method <tt>hash()</tt> returns a hashcode for an AST node. | ||||
| If <tt>eq(n1, n2)</tt> returns <tt>True</tt>, then <tt>n1.hash()</tt> | ||||
| is equal to <tt>n2.hash()</tt>.  | ||||
| </p> | ||||
| 
 | ||||
| <example pref="expr.3"><html><body> | ||||
| <div class="highlight"><pre><span class="n">x</span> <span class="o">=</span> <span class="n">Int</span><span class="p">(</span><span class="s">'x'</span><span class="p">)</span> | ||||
| <span class="k">print</span> <span class="p">(</span><span class="n">x</span> <span class="o">+</span> <span class="mi">1</span><span class="p">)</span><span class="o">.</span><span class="n">hash</span><span class="p">()</span> | ||||
| <span class="k">print</span> <span class="p">(</span><span class="mi">1</span> <span class="o">+</span> <span class="n">x</span><span class="p">)</span><span class="o">.</span><span class="n">hash</span><span class="p">()</span> | ||||
| <span class="k">print</span> <span class="n">x</span><span class="o">.</span><span class="n">sort</span><span class="p">()</span><span class="o">.</span><span class="n">hash</span><span class="p">()</span> | ||||
| </pre></div> | ||||
| </body></html></example> | ||||
| 
 | ||||
| <p>Z3 expressions can be divided in three basic groups: <b>applications</b>, | ||||
| <b>quantifiers</b> and <b>bounded/free variables</b>. | ||||
| Applications are all you need if your problems do not contain  | ||||
| universal/existential quantifiers. Although we say <tt>Int('x')</tt> is an | ||||
| integer "variable", it is technically an integer constant, and internally | ||||
| is represented as a function application with <tt>0</tt> arguments. | ||||
| Every application is associated with a <b>declaration</b> and contains  | ||||
| <tt>0</tt> or more arguments. The method <tt>decl()</tt> returns  | ||||
| the declaration associated with an application. The method <tt>num_args()</tt> | ||||
| returns the number of arguments of an application, and <tt>arg(i)</tt> one of the arguments. | ||||
| The function <tt>is_expr(n)</tt> returns <tt>True</tt> | ||||
| if <tt>n</tt> is an expression. Similarly <tt>is_app(n)</tt> (<tt>is_func_decl(n)</tt>) | ||||
| returns <tt>True</tt> if <tt>n</tt> is an application (declaration).  | ||||
| </p> | ||||
| 
 | ||||
| <example pref="expr.4"><html><body> | ||||
| <div class="highlight"><pre><span class="n">x</span> <span class="o">=</span> <span class="n">Int</span><span class="p">(</span><span class="s">'x'</span><span class="p">)</span> | ||||
| <span class="k">print</span> <span class="s">"is expression: "</span><span class="p">,</span> <span class="n">is_expr</span><span class="p">(</span><span class="n">x</span><span class="p">)</span> | ||||
| <span class="n">n</span> <span class="o">=</span> <span class="n">x</span> <span class="o">+</span> <span class="mi">1</span> | ||||
| <span class="k">print</span> <span class="s">"is application:"</span><span class="p">,</span> <span class="n">is_app</span><span class="p">(</span><span class="n">n</span><span class="p">)</span> | ||||
| <span class="k">print</span> <span class="s">"decl:          "</span><span class="p">,</span> <span class="n">n</span><span class="o">.</span><span class="n">decl</span><span class="p">()</span> | ||||
| <span class="k">print</span> <span class="s">"num args:      "</span><span class="p">,</span> <span class="n">n</span><span class="o">.</span><span class="n">num_args</span><span class="p">()</span> | ||||
| <span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="n">n</span><span class="o">.</span><span class="n">num_args</span><span class="p">()):</span> | ||||
|     <span class="k">print</span> <span class="s">"arg("</span><span class="p">,</span> <span class="n">i</span><span class="p">,</span> <span class="s">") ->"</span><span class="p">,</span> <span class="n">n</span><span class="o">.</span><span class="n">arg</span><span class="p">(</span><span class="n">i</span><span class="p">)</span> | ||||
| </pre></div> | ||||
| </body></html></example> | ||||
| 
 | ||||
| <p>Declarations have names, they are retrieved using the method <tt>name()</tt>. | ||||
| A (function) declaration has an arity, a domain and range sorts. | ||||
| </p> | ||||
| 
 | ||||
| <example pref="expr.5"><html><body> | ||||
| <div class="highlight"><pre><span class="n">x</span>   <span class="o">=</span> <span class="n">Int</span><span class="p">(</span><span class="s">'x'</span><span class="p">)</span> | ||||
| <span class="n">x_d</span> <span class="o">=</span> <span class="n">x</span><span class="o">.</span><span class="n">decl</span><span class="p">()</span> | ||||
| <span class="k">print</span> <span class="s">"is_expr(x_d):     "</span><span class="p">,</span> <span class="n">is_expr</span><span class="p">(</span><span class="n">x_d</span><span class="p">)</span> | ||||
| <span class="k">print</span> <span class="s">"is_func_decl(x_d):"</span><span class="p">,</span> <span class="n">is_func_decl</span><span class="p">(</span><span class="n">x_d</span><span class="p">)</span> | ||||
| <span class="k">print</span> <span class="s">"x_d.name():       "</span><span class="p">,</span> <span class="n">x_d</span><span class="o">.</span><span class="n">name</span><span class="p">()</span> | ||||
| <span class="k">print</span> <span class="s">"x_d.range():      "</span><span class="p">,</span> <span class="n">x_d</span><span class="o">.</span><span class="n">range</span><span class="p">()</span> | ||||
| <span class="k">print</span> <span class="s">"x_d.arity():      "</span><span class="p">,</span> <span class="n">x_d</span><span class="o">.</span><span class="n">arity</span><span class="p">()</span> | ||||
| <span class="c"># x_d() creates an application with 0 arguments using x_d.</span> | ||||
| <span class="k">print</span> <span class="s">"eq(x_d(), x):     "</span><span class="p">,</span> <span class="n">eq</span><span class="p">(</span><span class="n">x_d</span><span class="p">(),</span> <span class="n">x</span><span class="p">)</span> | ||||
| <span class="k">print</span> <span class="s">"</span><span class="se">\n</span><span class="s">"</span> | ||||
| <span class="c"># f is a function from (Int, Real) to Bool</span> | ||||
| <span class="n">f</span>   <span class="o">=</span> <span class="n">Function</span><span class="p">(</span><span class="s">'f'</span><span class="p">,</span> <span class="n">IntSort</span><span class="p">(),</span> <span class="n">RealSort</span><span class="p">(),</span> <span class="n">BoolSort</span><span class="p">())</span> | ||||
| <span class="k">print</span> <span class="s">"f.name():         "</span><span class="p">,</span> <span class="n">f</span><span class="o">.</span><span class="n">name</span><span class="p">()</span> | ||||
| <span class="k">print</span> <span class="s">"f.range():        "</span><span class="p">,</span> <span class="n">f</span><span class="o">.</span><span class="n">range</span><span class="p">()</span> | ||||
| <span class="k">print</span> <span class="s">"f.arity():        "</span><span class="p">,</span> <span class="n">f</span><span class="o">.</span><span class="n">arity</span><span class="p">()</span> | ||||
| <span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="n">f</span><span class="o">.</span><span class="n">arity</span><span class="p">()):</span> | ||||
|     <span class="k">print</span> <span class="s">"domain("</span><span class="p">,</span> <span class="n">i</span><span class="p">,</span> <span class="s">"): "</span><span class="p">,</span> <span class="n">f</span><span class="o">.</span><span class="n">domain</span><span class="p">(</span><span class="n">i</span><span class="p">)</span> | ||||
| <span class="c"># f(x, x) creates an application with 2 arguments using f.</span> | ||||
| <span class="k">print</span> <span class="n">f</span><span class="p">(</span><span class="n">x</span><span class="p">,</span> <span class="n">x</span><span class="p">)</span> | ||||
| <span class="k">print</span> <span class="n">eq</span><span class="p">(</span><span class="n">f</span><span class="p">(</span><span class="n">x</span><span class="p">,</span> <span class="n">x</span><span class="p">)</span><span class="o">.</span><span class="n">decl</span><span class="p">(),</span> <span class="n">f</span><span class="p">)</span> | ||||
| </pre></div> | ||||
| </body></html></example> | ||||
| 
 | ||||
| <p> | ||||
| The built-in declarations are identified using their <b>kind</b>. The kind | ||||
| is retrieved using the method <tt>kind()</tt>. The complete list of built-in declarations | ||||
| can be found in the file <tt>z3consts.py</tt> (<tt>z3_api.h</tt>) in the Z3 distribution. | ||||
| </p> | ||||
| 
 | ||||
| <example pref="expr.6"><html><body> | ||||
| <div class="highlight"><pre><span class="n">x</span><span class="p">,</span> <span class="n">y</span> <span class="o">=</span> <span class="n">Ints</span><span class="p">(</span><span class="s">'x y'</span><span class="p">)</span> | ||||
| <span class="k">print</span> <span class="p">(</span><span class="n">x</span> <span class="o">+</span> <span class="n">y</span><span class="p">)</span><span class="o">.</span><span class="n">decl</span><span class="p">()</span><span class="o">.</span><span class="n">kind</span><span class="p">()</span> <span class="o">==</span> <span class="n">Z3_OP_ADD</span> | ||||
| <span class="k">print</span> <span class="p">(</span><span class="n">x</span> <span class="o">+</span> <span class="n">y</span><span class="p">)</span><span class="o">.</span><span class="n">decl</span><span class="p">()</span><span class="o">.</span><span class="n">kind</span><span class="p">()</span> <span class="o">==</span> <span class="n">Z3_OP_SUB</span> | ||||
| </pre></div> | ||||
| </body></html></example> | ||||
| 
 | ||||
| <p> | ||||
| The following example demonstrates how to substitute sub-expressions in Z3 expressions. | ||||
| </p> | ||||
| 
 | ||||
| <example pref="expr.7"><html><body> | ||||
| <div class="highlight"><pre><span class="n">x</span><span class="p">,</span> <span class="n">y</span> <span class="o">=</span> <span class="n">Ints</span><span class="p">(</span><span class="s">'x y'</span><span class="p">)</span> | ||||
| <span class="n">f</span>    <span class="o">=</span> <span class="n">Function</span><span class="p">(</span><span class="s">'f'</span><span class="p">,</span> <span class="n">IntSort</span><span class="p">(),</span> <span class="n">IntSort</span><span class="p">(),</span> <span class="n">IntSort</span><span class="p">())</span> | ||||
| <span class="n">g</span>    <span class="o">=</span> <span class="n">Function</span><span class="p">(</span><span class="s">'g'</span><span class="p">,</span> <span class="n">IntSort</span><span class="p">(),</span> <span class="n">IntSort</span><span class="p">())</span> | ||||
| <span class="n">n</span>    <span class="o">=</span> <span class="n">f</span><span class="p">(</span><span class="n">f</span><span class="p">(</span><span class="n">g</span><span class="p">(</span><span class="n">x</span><span class="p">),</span> <span class="n">g</span><span class="p">(</span><span class="n">g</span><span class="p">(</span><span class="n">x</span><span class="p">))),</span> <span class="n">g</span><span class="p">(</span><span class="n">g</span><span class="p">(</span><span class="n">y</span><span class="p">)))</span> | ||||
| <span class="k">print</span> <span class="n">n</span> | ||||
| <span class="c"># substitute g(g(x)) with y and g(y) with x + 1</span> | ||||
| <span class="k">print</span> <span class="n">substitute</span><span class="p">(</span><span class="n">n</span><span class="p">,</span> <span class="p">(</span><span class="n">g</span><span class="p">(</span><span class="n">g</span><span class="p">(</span><span class="n">x</span><span class="p">)),</span> <span class="n">y</span><span class="p">),</span> <span class="p">(</span><span class="n">g</span><span class="p">(</span><span class="n">y</span><span class="p">),</span> <span class="n">x</span> <span class="o">+</span> <span class="mi">1</span><span class="p">))</span> | ||||
| </pre></div> | ||||
| </body></html></example> | ||||
| 
 | ||||
| <p> | ||||
| The function <tt>Const(name, sort)</tt> declares a constant (aka variable) of the given sort. | ||||
| For example, the functions <tt>Int(name)</tt> and <tt>Real(name)</tt> are shorthands for | ||||
| <tt>Const(name, IntSort())</tt> and <tt>Const(name, RealSort())</tt>. | ||||
| </p> | ||||
| 
 | ||||
| <example pref="expr.8"><html><body> | ||||
| <div class="highlight"><pre><span class="n">x</span> <span class="o">=</span> <span class="n">Const</span><span class="p">(</span><span class="s">'x'</span><span class="p">,</span> <span class="n">IntSort</span><span class="p">())</span> | ||||
| <span class="k">print</span> <span class="n">eq</span><span class="p">(</span><span class="n">x</span><span class="p">,</span> <span class="n">Int</span><span class="p">(</span><span class="s">'x'</span><span class="p">))</span> | ||||
| 
 | ||||
| <span class="n">a</span><span class="p">,</span> <span class="n">b</span> <span class="o">=</span> <span class="n">Consts</span><span class="p">(</span><span class="s">'a b'</span><span class="p">,</span> <span class="n">BoolSort</span><span class="p">())</span> | ||||
| <span class="k">print</span> <span class="n">And</span><span class="p">(</span><span class="n">a</span><span class="p">,</span> <span class="n">b</span><span class="p">)</span> | ||||
| </pre></div> | ||||
| </body></html></example> | ||||
| 
 | ||||
| <h2>Arrays</h2> | ||||
| 
 | ||||
| <p>As part of formulating a programme of a mathematical theory of computation | ||||
| McCarthy proposed a <i>basic</i> theory of arrays as characterized by | ||||
| the select-store axioms. The expression <tt>Select(a, i)</tt> returns | ||||
| the value stored at position <tt>i</tt> of the array <tt>a</tt>; | ||||
| and <tt>Store(a, i, v)</tt> returns a new array identical to <tt>a</tt>, | ||||
| but on position <tt>i</tt> it contains the value <tt>v</tt>. | ||||
| In Z3Py, we can also write <tt>Select(a, i)</tt> as <tt>a[i]</tt>. | ||||
| </p> | ||||
| 
 | ||||
| <example pref="array.1"><html><body> | ||||
| <div class="highlight"><pre><span class="c"># Use I as an alias for IntSort()</span> | ||||
| <span class="n">I</span> <span class="o">=</span> <span class="n">IntSort</span><span class="p">()</span> | ||||
| <span class="c"># A is an array from integer to integer</span> | ||||
| <span class="n">A</span> <span class="o">=</span> <span class="n">Array</span><span class="p">(</span><span class="s">'A'</span><span class="p">,</span> <span class="n">I</span><span class="p">,</span> <span class="n">I</span><span class="p">)</span> | ||||
| <span class="n">x</span> <span class="o">=</span> <span class="n">Int</span><span class="p">(</span><span class="s">'x'</span><span class="p">)</span> | ||||
| <span class="k">print</span> <span class="n">A</span><span class="p">[</span><span class="n">x</span><span class="p">]</span> | ||||
| <span class="k">print</span> <span class="n">Select</span><span class="p">(</span><span class="n">A</span><span class="p">,</span> <span class="n">x</span><span class="p">)</span> | ||||
| <span class="k">print</span> <span class="n">Store</span><span class="p">(</span><span class="n">A</span><span class="p">,</span> <span class="n">x</span><span class="p">,</span> <span class="mi">10</span><span class="p">)</span> | ||||
| <span class="k">print</span> <span class="n">simplify</span><span class="p">(</span><span class="n">Select</span><span class="p">(</span><span class="n">Store</span><span class="p">(</span><span class="n">A</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="n">x</span><span class="o">+</span><span class="mi">1</span><span class="p">),</span> <span class="mi">2</span><span class="p">))</span> | ||||
| </pre></div> | ||||
| </body></html></example> | ||||
| 
 | ||||
| <p> | ||||
| By default, Z3 assumes that arrays are extensional over select.  | ||||
| In other words, Z3 also enforces that if two arrays agree on all positions,  | ||||
| then the arrays are equal. | ||||
| </p> | ||||
| 
 | ||||
| <p> | ||||
| Z3 also contains various extensions  | ||||
| for operations on arrays that remain decidable and amenable | ||||
| to efficient saturation procedures (here efficient means,  | ||||
| with an NP-complete satisfiability complexity). | ||||
| We describe these extensions in the following using a collection of examples. | ||||
| Additional background on these extensions is available in the  | ||||
| paper <a href="http://research.microsoft.com/en-us/um/people/leonardo/fmcad09.pdf" target="_blank">Generalized and Efficient Array Decision Procedures</a>. | ||||
| </p> | ||||
| 
 | ||||
| <p> | ||||
| Arrays in Z3 are used to model unbounded or very large arrays. | ||||
| Arrays should not be used to model small finite collections of values. | ||||
| It is usually much more efficient to create different variables using list comprehensions. | ||||
| </p> | ||||
| 
 | ||||
| <example pref="array.2"><html><body> | ||||
| <div class="highlight"><pre><span class="c"># We want an array with 3 elements.</span> | ||||
| <span class="c"># 1. Bad solution</span> | ||||
| <span class="n">X</span> <span class="o">=</span> <span class="n">Array</span><span class="p">(</span><span class="s">'x'</span><span class="p">,</span> <span class="n">IntSort</span><span class="p">(),</span> <span class="n">IntSort</span><span class="p">())</span> | ||||
| <span class="c"># Example using the array</span> | ||||
| <span class="k">print</span> <span class="n">X</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">+</span> <span class="n">X</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">+</span> <span class="n">X</span><span class="p">[</span><span class="mi">2</span><span class="p">]</span> <span class="o">>=</span><span class="mi">0</span> | ||||
| 
 | ||||
| <span class="c"># 2. More efficient solution</span> | ||||
| <span class="n">X</span> <span class="o">=</span> <span class="n">IntVector</span><span class="p">(</span><span class="s">'x'</span><span class="p">,</span> <span class="mi">3</span><span class="p">)</span> | ||||
| <span class="k">print</span> <span class="n">X</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">+</span> <span class="n">X</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">+</span> <span class="n">X</span><span class="p">[</span><span class="mi">2</span><span class="p">]</span> <span class="o">>=</span> <span class="mi">0</span> | ||||
| <span class="k">print</span> <span class="n">Sum</span><span class="p">(</span><span class="n">X</span><span class="p">)</span> <span class="o">>=</span> <span class="mi">0</span> | ||||
| </pre></div> | ||||
| </body></html></example> | ||||
| 
 | ||||
| <h3>Select and Store</h3> | ||||
| 
 | ||||
| 
 | ||||
| <p>Let us first check a basic property of arrays. | ||||
| Suppose <tt>A</tt> is an array of integers, then the constraints | ||||
| <tt>A[x] == x, Store(A, x, y) == A</tt> | ||||
| are satisfiable for an array that contains an index <tt>x</tt> that maps to <tt>x</tt>, | ||||
| and when <tt>x == y</tt>. | ||||
| We can solve these constraints. | ||||
| </p> | ||||
| 
 | ||||
| <example pref="array.3"><html><body> | ||||
| <div class="highlight"><pre><span class="n">A</span> <span class="o">=</span> <span class="n">Array</span><span class="p">(</span><span class="s">'A'</span><span class="p">,</span> <span class="n">IntSort</span><span class="p">(),</span> <span class="n">IntSort</span><span class="p">())</span> | ||||
| <span class="n">x</span><span class="p">,</span> <span class="n">y</span> <span class="o">=</span> <span class="n">Ints</span><span class="p">(</span><span class="s">'x y'</span><span class="p">)</span> | ||||
| <span class="n">solve</span><span class="p">(</span><span class="n">A</span><span class="p">[</span><span class="n">x</span><span class="p">]</span> <span class="o">==</span> <span class="n">x</span><span class="p">,</span> <span class="n">Store</span><span class="p">(</span><span class="n">A</span><span class="p">,</span> <span class="n">x</span><span class="p">,</span> <span class="n">y</span><span class="p">)</span> <span class="o">==</span> <span class="n">A</span><span class="p">)</span> | ||||
| </pre></div> | ||||
| </body></html></example> | ||||
| 
 | ||||
| <p>The interpretation/solution for array variables is very similar to the one used for functions.</p> | ||||
| 
 | ||||
| <p>The problem becomes unsatisfiable/infeasible if we add the constraint <tt>x != y</tt>. | ||||
| 
 | ||||
| </p> | ||||
| <example pref="array.4"><html><body> | ||||
| <div class="highlight"><pre><span class="n">A</span> <span class="o">=</span> <span class="n">Array</span><span class="p">(</span><span class="s">'A'</span><span class="p">,</span> <span class="n">IntSort</span><span class="p">(),</span> <span class="n">IntSort</span><span class="p">())</span> | ||||
| <span class="n">x</span><span class="p">,</span> <span class="n">y</span> <span class="o">=</span> <span class="n">Ints</span><span class="p">(</span><span class="s">'x y'</span><span class="p">)</span> | ||||
| <span class="n">solve</span><span class="p">(</span><span class="n">A</span><span class="p">[</span><span class="n">x</span><span class="p">]</span> <span class="o">==</span> <span class="n">x</span><span class="p">,</span> <span class="n">Store</span><span class="p">(</span><span class="n">A</span><span class="p">,</span> <span class="n">x</span><span class="p">,</span> <span class="n">y</span><span class="p">)</span> <span class="o">==</span> <span class="n">A</span><span class="p">,</span> <span class="n">x</span> <span class="o">!=</span> <span class="n">y</span><span class="p">)</span> | ||||
| </pre></div> | ||||
| </body></html></example> | ||||
| 
 | ||||
| <h3>Constant arrays</h3> | ||||
| 
 | ||||
| <p> | ||||
| The array that maps all indices to some fixed value can be specified in Z3Py using the | ||||
| <tt>K(s, v)</tt> construct where <tt>s</tt> is a sort/type and <tt>v</tt> is an expression. | ||||
| <tt>K(s, v)</tt> returns a array that maps any value of <tt>s</tt> into <tt>v</tt>. | ||||
| The following example defines a constant array containing only ones. | ||||
| </p> | ||||
| 
 | ||||
| <example pref="array.5"><html><body> | ||||
| <div class="highlight"><pre><span class="n">AllOne</span> <span class="o">=</span> <span class="n">K</span><span class="p">(</span><span class="n">IntSort</span><span class="p">(),</span> <span class="mi">1</span><span class="p">)</span> | ||||
| <span class="n">a</span><span class="p">,</span> <span class="n">i</span> <span class="o">=</span> <span class="n">Ints</span><span class="p">(</span><span class="s">'a i'</span><span class="p">)</span> | ||||
| <span class="n">solve</span><span class="p">(</span><span class="n">a</span> <span class="o">==</span> <span class="n">AllOne</span><span class="p">[</span><span class="n">i</span><span class="p">])</span> | ||||
| <span class="c"># The following constraints do not have a solution</span> | ||||
| <span class="n">solve</span><span class="p">(</span><span class="n">a</span> <span class="o">==</span> <span class="n">AllOne</span><span class="p">[</span><span class="n">i</span><span class="p">],</span> <span class="n">a</span> <span class="o">!=</span> <span class="mi">1</span><span class="p">)</span> | ||||
| </pre></div> | ||||
| </body></html></example> | ||||
| 
 | ||||
| <h2>Datatypes</h2> | ||||
| 
 | ||||
| <p>Algebraic datatypes, known from programming languages such as ML, | ||||
| offer a convenient way for specifying common data structures. Records | ||||
| and tuples are special cases of algebraic datatypes, and so are | ||||
| scalars (enumeration types). But algebraic datatypes are more | ||||
| general. They can be used to specify finite lists, trees and other | ||||
| recursive structures.</p> | ||||
| 
 | ||||
| <p> | ||||
| The following example demonstrates how to declare a List in Z3Py. It is | ||||
| more verbose than using the SMT 2.0 front-end, but much simpler than using | ||||
| the Z3 C API. It consists of two phases. | ||||
| First, we have to declare the new datatype, its constructors and accessors. | ||||
| The function <tt>Datatype('List')</tt> declares a "placeholder" that will | ||||
| contain the constructors and accessors declarations. The method | ||||
| <tt>declare(cname, (aname, sort)+)</tt> declares a constructor named | ||||
| <tt>cname</tt> with the given accessors. Each accessor has an associated <tt>sort</tt> | ||||
| or a reference to the datatypes being declared. | ||||
| For example, <tt>declare('cons', ('car', IntSort()), ('cdr', List))</tt> | ||||
| declares the constructor named <tt>cons</tt> that builds a new <tt>List</tt> | ||||
| using an integer and a <tt>List</tt>. It also declares the accessors <tt>car</tt> and | ||||
| <tt>cdr</tt>. The accessor <tt>car</tt> extracts the integer of a <tt>cons</tt> | ||||
| cell, and <tt>cdr</tt> the list of a <tt>cons</tt> cell. | ||||
| After all constructors were declared, we use the method <tt>create()</tt> to | ||||
| create the actual datatype in Z3. Z3Py makes the new Z3 declarations and constants | ||||
| available as slots of the new object.  | ||||
| </p> | ||||
| 
 | ||||
| <example pref="datatype.1"><html><body> | ||||
| <div class="highlight"><pre><span class="c"># Declare a List of integers</span> | ||||
| <span class="n">List</span> <span class="o">=</span> <span class="n">Datatype</span><span class="p">(</span><span class="s">'List'</span><span class="p">)</span> | ||||
| <span class="c"># Constructor cons: (Int, List) -> List</span> | ||||
| <span class="n">List</span><span class="o">.</span><span class="n">declare</span><span class="p">(</span><span class="s">'cons'</span><span class="p">,</span> <span class="p">(</span><span class="s">'car'</span><span class="p">,</span> <span class="n">IntSort</span><span class="p">()),</span> <span class="p">(</span><span class="s">'cdr'</span><span class="p">,</span> <span class="n">List</span><span class="p">))</span> | ||||
| <span class="c"># Constructor nil: List</span> | ||||
| <span class="n">List</span><span class="o">.</span><span class="n">declare</span><span class="p">(</span><span class="s">'nil'</span><span class="p">)</span> | ||||
| <span class="c"># Create the datatype</span> | ||||
| <span class="n">List</span> <span class="o">=</span> <span class="n">List</span><span class="o">.</span><span class="n">create</span><span class="p">()</span> | ||||
| <span class="k">print</span> <span class="n">is_sort</span><span class="p">(</span><span class="n">List</span><span class="p">)</span> | ||||
| <span class="n">cons</span> <span class="o">=</span> <span class="n">List</span><span class="o">.</span><span class="n">cons</span> | ||||
| <span class="n">car</span>  <span class="o">=</span> <span class="n">List</span><span class="o">.</span><span class="n">car</span> | ||||
| <span class="n">cdr</span>  <span class="o">=</span> <span class="n">List</span><span class="o">.</span><span class="n">cdr</span> | ||||
| <span class="n">nil</span>  <span class="o">=</span> <span class="n">List</span><span class="o">.</span><span class="n">nil</span> | ||||
| <span class="c"># cons, car and cdr are function declarations, and nil a constant</span> | ||||
| <span class="k">print</span> <span class="n">is_func_decl</span><span class="p">(</span><span class="n">cons</span><span class="p">)</span> | ||||
| <span class="k">print</span> <span class="n">is_expr</span><span class="p">(</span><span class="n">nil</span><span class="p">)</span> | ||||
| 
 | ||||
| <span class="n">l1</span> <span class="o">=</span> <span class="n">cons</span><span class="p">(</span><span class="mi">10</span><span class="p">,</span> <span class="n">cons</span><span class="p">(</span><span class="mi">20</span><span class="p">,</span> <span class="n">nil</span><span class="p">))</span> | ||||
| <span class="k">print</span> <span class="n">l1</span> | ||||
| <span class="k">print</span> <span class="n">simplify</span><span class="p">(</span><span class="n">cdr</span><span class="p">(</span><span class="n">l1</span><span class="p">))</span> | ||||
| <span class="k">print</span> <span class="n">simplify</span><span class="p">(</span><span class="n">car</span><span class="p">(</span><span class="n">l1</span><span class="p">))</span> | ||||
| <span class="k">print</span> <span class="n">simplify</span><span class="p">(</span><span class="n">l1</span> <span class="o">==</span> <span class="n">nil</span><span class="p">)</span> | ||||
| </pre></div> | ||||
| </body></html></example> | ||||
| 
 | ||||
| <p> | ||||
| The following example demonstrates how to define a Python function that  | ||||
| given a sort creates a list of the given sort.  | ||||
| </p> | ||||
| 
 | ||||
| <example pref="datatype.2"><html><body> | ||||
| <div class="highlight"><pre><span class="k">def</span> <span class="nf">DeclareList</span><span class="p">(</span><span class="n">sort</span><span class="p">):</span> | ||||
|     <span class="n">List</span> <span class="o">=</span> <span class="n">Datatype</span><span class="p">(</span><span class="s">'List_of_</span><span class="si">%s</span><span class="s">'</span> <span class="o">%</span> <span class="n">sort</span><span class="o">.</span><span class="n">name</span><span class="p">())</span> | ||||
|     <span class="n">List</span><span class="o">.</span><span class="n">declare</span><span class="p">(</span><span class="s">'cons'</span><span class="p">,</span> <span class="p">(</span><span class="s">'car'</span><span class="p">,</span> <span class="n">sort</span><span class="p">),</span> <span class="p">(</span><span class="s">'cdr'</span><span class="p">,</span> <span class="n">List</span><span class="p">))</span> | ||||
|     <span class="n">List</span><span class="o">.</span><span class="n">declare</span><span class="p">(</span><span class="s">'nil'</span><span class="p">)</span> | ||||
|     <span class="k">return</span> <span class="n">List</span><span class="o">.</span><span class="n">create</span><span class="p">()</span> | ||||
| 
 | ||||
| <span class="n">IntList</span>     <span class="o">=</span> <span class="n">DeclareList</span><span class="p">(</span><span class="n">IntSort</span><span class="p">())</span> | ||||
| <span class="n">RealList</span>    <span class="o">=</span> <span class="n">DeclareList</span><span class="p">(</span><span class="n">RealSort</span><span class="p">())</span> | ||||
| <span class="n">IntListList</span> <span class="o">=</span> <span class="n">DeclareList</span><span class="p">(</span><span class="n">IntList</span><span class="p">)</span> | ||||
| 
 | ||||
| <span class="n">l1</span> <span class="o">=</span> <span class="n">IntList</span><span class="o">.</span><span class="n">cons</span><span class="p">(</span><span class="mi">10</span><span class="p">,</span> <span class="n">IntList</span><span class="o">.</span><span class="n">nil</span><span class="p">)</span> | ||||
| <span class="k">print</span> <span class="n">l1</span> | ||||
| <span class="k">print</span> <span class="n">IntListList</span><span class="o">.</span><span class="n">cons</span><span class="p">(</span><span class="n">l1</span><span class="p">,</span> <span class="n">IntListList</span><span class="o">.</span><span class="n">cons</span><span class="p">(</span><span class="n">l1</span><span class="p">,</span> <span class="n">IntListList</span><span class="o">.</span><span class="n">nil</span><span class="p">))</span> | ||||
| <span class="k">print</span> <span class="n">RealList</span><span class="o">.</span><span class="n">cons</span><span class="p">(</span><span class="s">"1/3"</span><span class="p">,</span> <span class="n">RealList</span><span class="o">.</span><span class="n">nil</span><span class="p">)</span> | ||||
| 
 | ||||
| <span class="k">print</span> <span class="n">l1</span><span class="o">.</span><span class="n">sort</span><span class="p">()</span> | ||||
| </pre></div> | ||||
| </body></html></example> | ||||
| 
 | ||||
| <p>The example above demonstrates that Z3 supports operator overloading. | ||||
| There are several functions named <tt>cons</tt>, but they are different since they receive and/or | ||||
| return values of different sorts. | ||||
| Note that it is not necessary to use a different sort name for each instance of the sort | ||||
| list. That is, the expression <tt>'List_of_%s' % sort.name()</tt> is not necessary, we | ||||
| use it just to provide more meaningful names. | ||||
| </p> | ||||
| 
 | ||||
| <p> | ||||
| As described above enumeration types are a special case of algebraic datatypes. | ||||
| The following example declares an enumeration type consisting of three values: | ||||
| <tt>red</tt>, <tt>green</tt> and <tt>blue</tt>. | ||||
| </p> | ||||
| 
 | ||||
| <example pref="datatype.3"><html><body> | ||||
| <div class="highlight"><pre><span class="n">Color</span> <span class="o">=</span> <span class="n">Datatype</span><span class="p">(</span><span class="s">'Color'</span><span class="p">)</span> | ||||
| <span class="n">Color</span><span class="o">.</span><span class="n">declare</span><span class="p">(</span><span class="s">'red'</span><span class="p">)</span> | ||||
| <span class="n">Color</span><span class="o">.</span><span class="n">declare</span><span class="p">(</span><span class="s">'green'</span><span class="p">)</span> | ||||
| <span class="n">Color</span><span class="o">.</span><span class="n">declare</span><span class="p">(</span><span class="s">'blue'</span><span class="p">)</span> | ||||
| <span class="n">Color</span> <span class="o">=</span> <span class="n">Color</span><span class="o">.</span><span class="n">create</span><span class="p">()</span> | ||||
| 
 | ||||
| <span class="k">print</span> <span class="n">is_expr</span><span class="p">(</span><span class="n">Color</span><span class="o">.</span><span class="n">green</span><span class="p">)</span> | ||||
| <span class="k">print</span> <span class="n">Color</span><span class="o">.</span><span class="n">green</span> <span class="o">==</span> <span class="n">Color</span><span class="o">.</span><span class="n">blue</span> | ||||
| <span class="k">print</span> <span class="n">simplify</span><span class="p">(</span><span class="n">Color</span><span class="o">.</span><span class="n">green</span> <span class="o">==</span> <span class="n">Color</span><span class="o">.</span><span class="n">blue</span><span class="p">)</span> | ||||
| 
 | ||||
| <span class="c"># Let c be a constant of sort Color</span> | ||||
| <span class="n">c</span> <span class="o">=</span> <span class="n">Const</span><span class="p">(</span><span class="s">'c'</span><span class="p">,</span> <span class="n">Color</span><span class="p">)</span> | ||||
| <span class="c"># Then, c must be red, green or blue</span> | ||||
| <span class="n">prove</span><span class="p">(</span><span class="n">Or</span><span class="p">(</span><span class="n">c</span> <span class="o">==</span> <span class="n">Color</span><span class="o">.</span><span class="n">green</span><span class="p">,</span>  | ||||
|          <span class="n">c</span> <span class="o">==</span> <span class="n">Color</span><span class="o">.</span><span class="n">blue</span><span class="p">,</span> | ||||
|          <span class="n">c</span> <span class="o">==</span> <span class="n">Color</span><span class="o">.</span><span class="n">red</span><span class="p">))</span> | ||||
| </pre></div> | ||||
| </body></html></example> | ||||
| 
 | ||||
| <p> | ||||
| Z3Py also provides the following shorthand for declaring enumeration sorts. | ||||
| </p> | ||||
| 
 | ||||
| <example pref="datatype.4"><html><body> | ||||
| <div class="highlight"><pre><span class="n">Color</span><span class="p">,</span> <span class="p">(</span><span class="n">red</span><span class="p">,</span> <span class="n">green</span><span class="p">,</span> <span class="n">blue</span><span class="p">)</span> <span class="o">=</span> <span class="n">EnumSort</span><span class="p">(</span><span class="s">'Color'</span><span class="p">,</span> <span class="p">(</span><span class="s">'red'</span><span class="p">,</span> <span class="s">'green'</span><span class="p">,</span> <span class="s">'blue'</span><span class="p">))</span> | ||||
| 
 | ||||
| <span class="k">print</span> <span class="n">green</span> <span class="o">==</span> <span class="n">blue</span> | ||||
| <span class="k">print</span> <span class="n">simplify</span><span class="p">(</span><span class="n">green</span> <span class="o">==</span> <span class="n">blue</span><span class="p">)</span> | ||||
| 
 | ||||
| <span class="n">c</span> <span class="o">=</span> <span class="n">Const</span><span class="p">(</span><span class="s">'c'</span><span class="p">,</span> <span class="n">Color</span><span class="p">)</span> | ||||
| <span class="n">solve</span><span class="p">(</span><span class="n">c</span> <span class="o">!=</span> <span class="n">green</span><span class="p">,</span> <span class="n">c</span> <span class="o">!=</span> <span class="n">blue</span><span class="p">)</span> | ||||
| </pre></div> | ||||
| </body></html></example> | ||||
| 
 | ||||
| <p> | ||||
| Mutually recursive datatypes can also be declared. The only difference is that we use | ||||
| the function <tt>CreateDatatypes</tt> instead of the method <tt>create()</tt> to create | ||||
| the mutually recursive datatypes. | ||||
| </p> | ||||
| 
 | ||||
| <example pref="datatype.5"><html><body> | ||||
| <div class="highlight"><pre><span class="n">TreeList</span> <span class="o">=</span> <span class="n">Datatype</span><span class="p">(</span><span class="s">'TreeList'</span><span class="p">)</span> | ||||
| <span class="n">Tree</span>     <span class="o">=</span> <span class="n">Datatype</span><span class="p">(</span><span class="s">'Tree'</span><span class="p">)</span> | ||||
| <span class="n">Tree</span><span class="o">.</span><span class="n">declare</span><span class="p">(</span><span class="s">'leaf'</span><span class="p">,</span> <span class="p">(</span><span class="s">'val'</span><span class="p">,</span> <span class="n">IntSort</span><span class="p">()))</span> | ||||
| <span class="n">Tree</span><span class="o">.</span><span class="n">declare</span><span class="p">(</span><span class="s">'node'</span><span class="p">,</span> <span class="p">(</span><span class="s">'left'</span><span class="p">,</span> <span class="n">TreeList</span><span class="p">),</span> <span class="p">(</span><span class="s">'right'</span><span class="p">,</span> <span class="n">TreeList</span><span class="p">))</span> | ||||
| <span class="n">TreeList</span><span class="o">.</span><span class="n">declare</span><span class="p">(</span><span class="s">'nil'</span><span class="p">)</span> | ||||
| <span class="n">TreeList</span><span class="o">.</span><span class="n">declare</span><span class="p">(</span><span class="s">'cons'</span><span class="p">,</span> <span class="p">(</span><span class="s">'car'</span><span class="p">,</span> <span class="n">Tree</span><span class="p">),</span> <span class="p">(</span><span class="s">'cdr'</span><span class="p">,</span> <span class="n">TreeList</span><span class="p">))</span> | ||||
| 
 | ||||
| <span class="n">Tree</span><span class="p">,</span> <span class="n">TreeList</span> <span class="o">=</span> <span class="n">CreateDatatypes</span><span class="p">(</span><span class="n">Tree</span><span class="p">,</span> <span class="n">TreeList</span><span class="p">)</span> | ||||
| 
 | ||||
| <span class="n">t1</span>  <span class="o">=</span> <span class="n">Tree</span><span class="o">.</span><span class="n">leaf</span><span class="p">(</span><span class="mi">10</span><span class="p">)</span> | ||||
| <span class="n">tl1</span> <span class="o">=</span> <span class="n">TreeList</span><span class="o">.</span><span class="n">cons</span><span class="p">(</span><span class="n">t1</span><span class="p">,</span> <span class="n">TreeList</span><span class="o">.</span><span class="n">nil</span><span class="p">)</span> | ||||
| <span class="n">t2</span>  <span class="o">=</span> <span class="n">Tree</span><span class="o">.</span><span class="n">node</span><span class="p">(</span><span class="n">tl1</span><span class="p">,</span> <span class="n">TreeList</span><span class="o">.</span><span class="n">nil</span><span class="p">)</span> | ||||
| <span class="k">print</span> <span class="n">t2</span> | ||||
| <span class="k">print</span> <span class="n">simplify</span><span class="p">(</span><span class="n">Tree</span><span class="o">.</span><span class="n">val</span><span class="p">(</span><span class="n">t1</span><span class="p">))</span> | ||||
| 
 | ||||
| <span class="n">t1</span><span class="p">,</span> <span class="n">t2</span><span class="p">,</span> <span class="n">t3</span> <span class="o">=</span> <span class="n">Consts</span><span class="p">(</span><span class="s">'t1 t2 t3'</span><span class="p">,</span> <span class="n">TreeList</span><span class="p">)</span> | ||||
| 
 | ||||
| <span class="n">solve</span><span class="p">(</span><span class="n">Distinct</span><span class="p">(</span><span class="n">t1</span><span class="p">,</span> <span class="n">t2</span><span class="p">,</span> <span class="n">t3</span><span class="p">))</span> | ||||
| </pre></div> | ||||
| </body></html></example> | ||||
| 
 | ||||
| <h2>Uninterpreted Sorts</h2> | ||||
| 
 | ||||
| <p> | ||||
| Function and constant symbols in pure first-order logic are uninterpreted or free,  | ||||
| which means that no a priori interpretation is attached.  | ||||
| This is in contrast to arithmetic operators such as <tt>+</tt> and <tt>-</tt>  | ||||
| that have a fixed standard interpretation.  | ||||
| Uninterpreted functions and constants are maximally flexible;  | ||||
| they allow any interpretation that is consistent with the constraints over the function or constant. | ||||
| </p> | ||||
| 
 | ||||
| <p> | ||||
| To illustrate uninterpreted functions and constants let us introduce an (uninterpreted) sort <tt>A</tt>,  | ||||
| and the constants <tt>x</tt>, <tt>y</tt> ranging over <tt>A</tt>.  | ||||
| Finally let <tt>f</tt> be an uninterpreted function that takes one | ||||
| argument of sort <tt>A</tt> and results in a value of sort <tt>A</tt>.  | ||||
| The example illustrates how one can force an interpretation where <tt>f</tt> applied twice to <tt>x</tt> results in <tt>x</tt> again,  | ||||
| but <tt>f</tt> applied once to <tt>x</tt> is different from <tt>x</tt>. | ||||
| </p> | ||||
| 
 | ||||
| <example pref="uninterp.1"><html><body> | ||||
| <div class="highlight"><pre><span class="n">A</span>    <span class="o">=</span> <span class="n">DeclareSort</span><span class="p">(</span><span class="s">'A'</span><span class="p">)</span> | ||||
| <span class="n">x</span><span class="p">,</span> <span class="n">y</span> <span class="o">=</span> <span class="n">Consts</span><span class="p">(</span><span class="s">'x y'</span><span class="p">,</span> <span class="n">A</span><span class="p">)</span> | ||||
| <span class="n">f</span>    <span class="o">=</span> <span class="n">Function</span><span class="p">(</span><span class="s">'f'</span><span class="p">,</span> <span class="n">A</span><span class="p">,</span> <span class="n">A</span><span class="p">)</span> | ||||
| 
 | ||||
| <span class="n">s</span>    <span class="o">=</span> <span class="n">Solver</span><span class="p">()</span> | ||||
| <span class="n">s</span><span class="o">.</span><span class="n">add</span><span class="p">(</span><span class="n">f</span><span class="p">(</span><span class="n">f</span><span class="p">(</span><span class="n">x</span><span class="p">))</span> <span class="o">==</span> <span class="n">x</span><span class="p">,</span> <span class="n">f</span><span class="p">(</span><span class="n">x</span><span class="p">)</span> <span class="o">==</span> <span class="n">y</span><span class="p">,</span> <span class="n">x</span> <span class="o">!=</span> <span class="n">y</span><span class="p">)</span> | ||||
| 
 | ||||
| <span class="k">print</span> <span class="n">s</span><span class="o">.</span><span class="n">check</span><span class="p">()</span> | ||||
| <span class="n">m</span> <span class="o">=</span> <span class="n">s</span><span class="o">.</span><span class="n">model</span><span class="p">()</span> | ||||
| <span class="k">print</span> <span class="n">m</span> | ||||
| <span class="k">print</span> <span class="s">"interpretation assigned to A:"</span> | ||||
| <span class="k">print</span> <span class="n">m</span><span class="p">[</span><span class="n">A</span><span class="p">]</span> | ||||
| </pre></div> | ||||
| </body></html></example> | ||||
| 
 | ||||
| <p> | ||||
| The resulting model introduces abstract values for the elements in <tt>A</tt>, | ||||
| because the sort <tt>A</tt> is uninterpreted. The interpretation for <tt>f</tt> in the | ||||
| model toggles between the two values for <tt>x</tt> and <tt>y</tt>, which are different. | ||||
| The expression <tt>m[A]</tt> returns the interpretation (universe) for the uninterpreted sort <tt>A</tt> | ||||
| in the model <tt>m</tt>.  | ||||
| </p> | ||||
| 
 | ||||
| <h2>Quantifiers</h2> | ||||
| 
 | ||||
| <p> | ||||
| Z3 is can solve quantifier-free problems containing arithmetic, bit-vector, Booleans, | ||||
| arrays, functions and datatypes. Z3 also accepts and can work with formulas | ||||
| that use quantifiers. It is no longer a decision procedure for  | ||||
| such formulas in general (and for good reasons, as there can be | ||||
| no decision procedure for first-order logic). | ||||
| </p> | ||||
| 
 | ||||
| <example pref="quant.1"><html><body> | ||||
| <div class="highlight"><pre><span class="n">f</span> <span class="o">=</span> <span class="n">Function</span><span class="p">(</span><span class="s">'f'</span><span class="p">,</span> <span class="n">IntSort</span><span class="p">(),</span> <span class="n">IntSort</span><span class="p">(),</span> <span class="n">IntSort</span><span class="p">())</span> | ||||
| <span class="n">x</span><span class="p">,</span> <span class="n">y</span> <span class="o">=</span> <span class="n">Ints</span><span class="p">(</span><span class="s">'x y'</span><span class="p">)</span> | ||||
| <span class="k">print</span> <span class="n">ForAll</span><span class="p">([</span><span class="n">x</span><span class="p">,</span> <span class="n">y</span><span class="p">],</span> <span class="n">f</span><span class="p">(</span><span class="n">x</span><span class="p">,</span> <span class="n">y</span><span class="p">)</span> <span class="o">==</span> <span class="mi">0</span><span class="p">)</span> | ||||
| <span class="k">print</span> <span class="n">Exists</span><span class="p">(</span><span class="n">x</span><span class="p">,</span> <span class="n">f</span><span class="p">(</span><span class="n">x</span><span class="p">,</span> <span class="n">x</span><span class="p">)</span> <span class="o">>=</span> <span class="mi">0</span><span class="p">)</span> | ||||
| 
 | ||||
| <span class="n">a</span><span class="p">,</span> <span class="n">b</span> <span class="o">=</span> <span class="n">Ints</span><span class="p">(</span><span class="s">'a b'</span><span class="p">)</span> | ||||
| <span class="n">solve</span><span class="p">(</span><span class="n">ForAll</span><span class="p">(</span><span class="n">x</span><span class="p">,</span> <span class="n">f</span><span class="p">(</span><span class="n">x</span><span class="p">,</span> <span class="n">x</span><span class="p">)</span> <span class="o">==</span> <span class="mi">0</span><span class="p">),</span> <span class="n">f</span><span class="p">(</span><span class="n">a</span><span class="p">,</span> <span class="n">b</span><span class="p">)</span> <span class="o">==</span> <span class="mi">1</span><span class="p">)</span> | ||||
| </pre></div> | ||||
| </body></html></example> | ||||
| 
 | ||||
| <p> | ||||
| Nevertheless, Z3 is often able to handle formulas involving | ||||
| quantifiers. It uses several approaches to handle quantifiers. | ||||
| The most prolific approach is using <i>pattern-based</i> quantifier | ||||
| instantiation. This approach allows instantiating quantified formulas | ||||
| with ground terms that appear in the current search context based | ||||
| on <i>pattern annotations</i> on quantifiers.  | ||||
| Z3 also contains a model-based quantifier instantiation  | ||||
| component that uses a model construction to find good terms to instantiate | ||||
| quantifiers with; and Z3 also handles many decidable fragments. | ||||
| </p> | ||||
| 
 | ||||
| <p>Note that in the previous example the constants <tt>x</tt>  | ||||
| and <tt>y</tt> were used to create quantified formulas. | ||||
| This is a "trick" for simplifying the construction of quantified | ||||
| formulas in Z3Py. Internally, these constants are replaced by | ||||
| bounded variables. The next example demonstrates that. The method | ||||
| <tt>body()</tt> retrives the quantified expression. | ||||
| In the resultant formula the bounded variables are free. | ||||
| The function <tt>Var(index, sort)</tt> creates a bounded/free variable | ||||
| with the given index and sort. | ||||
| </p>  | ||||
| 
 | ||||
| <example pref="quant.2"><html><body> | ||||
| <div class="highlight"><pre><span class="n">f</span> <span class="o">=</span> <span class="n">Function</span><span class="p">(</span><span class="s">'f'</span><span class="p">,</span> <span class="n">IntSort</span><span class="p">(),</span> <span class="n">IntSort</span><span class="p">(),</span> <span class="n">IntSort</span><span class="p">())</span> | ||||
| <span class="n">x</span><span class="p">,</span> <span class="n">y</span> <span class="o">=</span> <span class="n">Ints</span><span class="p">(</span><span class="s">'x y'</span><span class="p">)</span> | ||||
| <span class="n">f</span> <span class="o">=</span> <span class="n">ForAll</span><span class="p">([</span><span class="n">x</span><span class="p">,</span> <span class="n">y</span><span class="p">],</span> <span class="n">f</span><span class="p">(</span><span class="n">x</span><span class="p">,</span> <span class="n">y</span><span class="p">)</span> <span class="o">==</span> <span class="mi">0</span><span class="p">)</span> | ||||
| <span class="k">print</span> <span class="n">f</span><span class="o">.</span><span class="n">body</span><span class="p">()</span> | ||||
| <span class="n">v1</span> <span class="o">=</span> <span class="n">f</span><span class="o">.</span><span class="n">body</span><span class="p">()</span><span class="o">.</span><span class="n">arg</span><span class="p">(</span><span class="mi">0</span><span class="p">)</span><span class="o">.</span><span class="n">arg</span><span class="p">(</span><span class="mi">0</span><span class="p">)</span> | ||||
| <span class="k">print</span> <span class="n">v1</span> | ||||
| <span class="k">print</span> <span class="n">eq</span><span class="p">(</span><span class="n">v1</span><span class="p">,</span> <span class="n">Var</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="n">IntSort</span><span class="p">()))</span> | ||||
| </pre></div> | ||||
| </body></html></example> | ||||
| 
 | ||||
| <h3>Modeling with Quantifiers</h3> | ||||
| 
 | ||||
| <p> | ||||
| Suppose we want to model an object oriented type system with single inheritance.  | ||||
| We would need a predicate for sub-typing. Sub-typing should be a partial order,  | ||||
| and respect single inheritance. For some built-in type constructors,  | ||||
| such as for <tt>array_of</tt>, sub-typing should be monotone. | ||||
| </p> | ||||
| 
 | ||||
| <example pref="quant.3"><html><body> | ||||
| <div class="highlight"><pre><span class="n">Type</span>     <span class="o">=</span> <span class="n">DeclareSort</span><span class="p">(</span><span class="s">'Type'</span><span class="p">)</span> | ||||
| <span class="n">subtype</span>  <span class="o">=</span> <span class="n">Function</span><span class="p">(</span><span class="s">'subtype'</span><span class="p">,</span> <span class="n">Type</span><span class="p">,</span> <span class="n">Type</span><span class="p">,</span> <span class="n">BoolSort</span><span class="p">())</span> | ||||
| <span class="n">array_of</span> <span class="o">=</span> <span class="n">Function</span><span class="p">(</span><span class="s">'array_of'</span><span class="p">,</span> <span class="n">Type</span><span class="p">,</span> <span class="n">Type</span><span class="p">)</span> | ||||
| <span class="n">root</span>     <span class="o">=</span> <span class="n">Const</span><span class="p">(</span><span class="s">'root'</span><span class="p">,</span> <span class="n">Type</span><span class="p">)</span> | ||||
| 
 | ||||
| <span class="n">x</span><span class="p">,</span> <span class="n">y</span><span class="p">,</span> <span class="n">z</span>  <span class="o">=</span> <span class="n">Consts</span><span class="p">(</span><span class="s">'x y z'</span><span class="p">,</span> <span class="n">Type</span><span class="p">)</span> | ||||
| 
 | ||||
| <span class="n">axioms</span> <span class="o">=</span> <span class="p">[</span> <span class="n">ForAll</span><span class="p">(</span><span class="n">x</span><span class="p">,</span> <span class="n">subtype</span><span class="p">(</span><span class="n">x</span><span class="p">,</span> <span class="n">x</span><span class="p">)),</span> | ||||
|            <span class="n">ForAll</span><span class="p">([</span><span class="n">x</span><span class="p">,</span> <span class="n">y</span><span class="p">,</span> <span class="n">z</span><span class="p">],</span> <span class="n">Implies</span><span class="p">(</span><span class="n">And</span><span class="p">(</span><span class="n">subtype</span><span class="p">(</span><span class="n">x</span><span class="p">,</span> <span class="n">y</span><span class="p">),</span> <span class="n">subtype</span><span class="p">(</span><span class="n">y</span><span class="p">,</span> <span class="n">z</span><span class="p">)),</span> | ||||
|                                      <span class="n">subtype</span><span class="p">(</span><span class="n">x</span><span class="p">,</span> <span class="n">z</span><span class="p">))),</span> | ||||
|            <span class="n">ForAll</span><span class="p">([</span><span class="n">x</span><span class="p">,</span> <span class="n">y</span><span class="p">],</span> <span class="n">Implies</span><span class="p">(</span><span class="n">And</span><span class="p">(</span><span class="n">subtype</span><span class="p">(</span><span class="n">x</span><span class="p">,</span> <span class="n">y</span><span class="p">),</span> <span class="n">subtype</span><span class="p">(</span><span class="n">y</span><span class="p">,</span> <span class="n">x</span><span class="p">)),</span> | ||||
|                                   <span class="n">x</span> <span class="o">==</span> <span class="n">y</span><span class="p">)),</span> | ||||
|            <span class="n">ForAll</span><span class="p">([</span><span class="n">x</span><span class="p">,</span> <span class="n">y</span><span class="p">,</span> <span class="n">z</span><span class="p">],</span> <span class="n">Implies</span><span class="p">(</span><span class="n">And</span><span class="p">(</span><span class="n">subtype</span><span class="p">(</span><span class="n">x</span><span class="p">,</span> <span class="n">y</span><span class="p">),</span> <span class="n">subtype</span><span class="p">(</span><span class="n">x</span><span class="p">,</span> <span class="n">z</span><span class="p">)),</span> | ||||
|                                      <span class="n">Or</span><span class="p">(</span><span class="n">subtype</span><span class="p">(</span><span class="n">y</span><span class="p">,</span> <span class="n">z</span><span class="p">),</span> <span class="n">subtype</span><span class="p">(</span><span class="n">z</span><span class="p">,</span> <span class="n">y</span><span class="p">)))),</span> | ||||
|            <span class="n">ForAll</span><span class="p">([</span><span class="n">x</span><span class="p">,</span> <span class="n">y</span><span class="p">],</span> <span class="n">Implies</span><span class="p">(</span><span class="n">subtype</span><span class="p">(</span><span class="n">x</span><span class="p">,</span> <span class="n">y</span><span class="p">),</span> | ||||
|                                   <span class="n">subtype</span><span class="p">(</span><span class="n">array_of</span><span class="p">(</span><span class="n">x</span><span class="p">),</span> <span class="n">array_of</span><span class="p">(</span><span class="n">y</span><span class="p">)))),</span> | ||||
|             | ||||
|            <span class="n">ForAll</span><span class="p">(</span><span class="n">x</span><span class="p">,</span> <span class="n">subtype</span><span class="p">(</span><span class="n">root</span><span class="p">,</span> <span class="n">x</span><span class="p">))</span> | ||||
|            <span class="p">]</span> | ||||
| <span class="n">s</span> <span class="o">=</span> <span class="n">Solver</span><span class="p">()</span> | ||||
| <span class="n">s</span><span class="o">.</span><span class="n">add</span><span class="p">(</span><span class="n">axioms</span><span class="p">)</span> | ||||
| <span class="k">print</span> <span class="n">s</span> | ||||
| <span class="k">print</span> <span class="n">s</span><span class="o">.</span><span class="n">check</span><span class="p">()</span> | ||||
| <span class="k">print</span> <span class="s">"Interpretation for Type:"</span> | ||||
| <span class="k">print</span> <span class="n">s</span><span class="o">.</span><span class="n">model</span><span class="p">()[</span><span class="n">Type</span><span class="p">]</span> | ||||
| <span class="k">print</span> <span class="s">"Model:"</span> | ||||
| <span class="k">print</span> <span class="n">s</span><span class="o">.</span><span class="n">model</span><span class="p">()</span> | ||||
| </pre></div> | ||||
| </body></html></example> | ||||
| 
 | ||||
| <h3>Patterns</h3> | ||||
| 
 | ||||
| <p> | ||||
| The Stanford Pascal verifier and the subsequent Simplify theorem prover pioneered  | ||||
| the use of pattern-based quantifier instantiation.  | ||||
| The basic idea behind pattern-based quantifier instantiation is in a sense straight-forward:  | ||||
| Annotate a quantified formula using a pattern that contains all the bound variables.  | ||||
| So a pattern is an expression (that does not contain binding operations, such as quantifiers)  | ||||
| that contains variables bound by a quantifier. Then instantiate the quantifier whenever a term | ||||
|  that matches the pattern is created during search. This is a conceptually easy starting point,  | ||||
| but there are several subtleties that are important. | ||||
| </p> | ||||
| 
 | ||||
| <p> | ||||
| In the following example, the first two options make sure that Model-based quantifier instantiation engine is disabled.  | ||||
| We also annotate the quantified formula with the pattern <tt>f(g(x))</tt>.  | ||||
| Since there is no ground instance of this pattern, the quantifier is not instantiated, and  | ||||
| Z3 fails to show that the formula is unsatisfiable. | ||||
| </p> | ||||
| 
 | ||||
| <example pref="quant.4"><html><body> | ||||
| <div class="highlight"><pre><span class="n">f</span> <span class="o">=</span> <span class="n">Function</span><span class="p">(</span><span class="s">'f'</span><span class="p">,</span> <span class="n">IntSort</span><span class="p">(),</span> <span class="n">IntSort</span><span class="p">())</span> | ||||
| <span class="n">g</span> <span class="o">=</span> <span class="n">Function</span><span class="p">(</span><span class="s">'g'</span><span class="p">,</span> <span class="n">IntSort</span><span class="p">(),</span> <span class="n">IntSort</span><span class="p">())</span> | ||||
| <span class="n">a</span><span class="p">,</span> <span class="n">b</span><span class="p">,</span> <span class="n">c</span> <span class="o">=</span> <span class="n">Ints</span><span class="p">(</span><span class="s">'a b c'</span><span class="p">)</span> | ||||
| <span class="n">x</span> <span class="o">=</span> <span class="n">Int</span><span class="p">(</span><span class="s">'x'</span><span class="p">)</span> | ||||
| 
 | ||||
| <span class="n">s</span> <span class="o">=</span> <span class="n">Solver</span><span class="p">()</span> | ||||
| <span class="n">s</span><span class="o">.</span><span class="n">set</span><span class="p">(</span><span class="n">auto_config</span><span class="o">=</span><span class="bp">False</span><span class="p">,</span> <span class="n">mbqi</span><span class="o">=</span><span class="bp">False</span><span class="p">)</span> | ||||
| 
 | ||||
| <span class="n">s</span><span class="o">.</span><span class="n">add</span><span class="p">(</span> <span class="n">ForAll</span><span class="p">(</span><span class="n">x</span><span class="p">,</span> <span class="n">f</span><span class="p">(</span><span class="n">g</span><span class="p">(</span><span class="n">x</span><span class="p">))</span> <span class="o">==</span> <span class="n">x</span><span class="p">,</span> <span class="n">patterns</span> <span class="o">=</span> <span class="p">[</span><span class="n">f</span><span class="p">(</span><span class="n">g</span><span class="p">(</span><span class="n">x</span><span class="p">))]),</span> | ||||
|        <span class="n">g</span><span class="p">(</span><span class="n">a</span><span class="p">)</span> <span class="o">==</span> <span class="n">c</span><span class="p">,</span> | ||||
|        <span class="n">g</span><span class="p">(</span><span class="n">b</span><span class="p">)</span> <span class="o">==</span> <span class="n">c</span><span class="p">,</span> | ||||
|        <span class="n">a</span> <span class="o">!=</span> <span class="n">b</span> <span class="p">)</span> | ||||
| 
 | ||||
| <span class="c"># Display solver state using internal format</span> | ||||
| <span class="k">print</span> <span class="n">s</span><span class="o">.</span><span class="n">sexpr</span><span class="p">()</span> | ||||
| <span class="k">print</span> <span class="n">s</span><span class="o">.</span><span class="n">check</span><span class="p">()</span> | ||||
| </pre></div> | ||||
| </body></html></example> | ||||
| 
 | ||||
| <p>When the more permissive pattern <tt>g(x)</tt> is used. Z3 proves the formula | ||||
| to be unsatisfiable. More restrive patterns minimize the number of | ||||
| instantiations (and potentially improve performance), but they may | ||||
| also make Z3 "less complete". | ||||
| </p> | ||||
| 
 | ||||
| <example pref="quant.5"><html><body> | ||||
| <div class="highlight"><pre><span class="n">f</span> <span class="o">=</span> <span class="n">Function</span><span class="p">(</span><span class="s">'f'</span><span class="p">,</span> <span class="n">IntSort</span><span class="p">(),</span> <span class="n">IntSort</span><span class="p">())</span> | ||||
| <span class="n">g</span> <span class="o">=</span> <span class="n">Function</span><span class="p">(</span><span class="s">'g'</span><span class="p">,</span> <span class="n">IntSort</span><span class="p">(),</span> <span class="n">IntSort</span><span class="p">())</span> | ||||
| <span class="n">a</span><span class="p">,</span> <span class="n">b</span><span class="p">,</span> <span class="n">c</span> <span class="o">=</span> <span class="n">Ints</span><span class="p">(</span><span class="s">'a b c'</span><span class="p">)</span> | ||||
| <span class="n">x</span> <span class="o">=</span> <span class="n">Int</span><span class="p">(</span><span class="s">'x'</span><span class="p">)</span> | ||||
| 
 | ||||
| <span class="n">s</span> <span class="o">=</span> <span class="n">Solver</span><span class="p">()</span> | ||||
| <span class="n">s</span><span class="o">.</span><span class="n">set</span><span class="p">(</span><span class="n">auto_config</span><span class="o">=</span><span class="bp">False</span><span class="p">,</span> <span class="n">mbqi</span><span class="o">=</span><span class="bp">False</span><span class="p">)</span> | ||||
| 
 | ||||
| <span class="n">s</span><span class="o">.</span><span class="n">add</span><span class="p">(</span> <span class="n">ForAll</span><span class="p">(</span><span class="n">x</span><span class="p">,</span> <span class="n">f</span><span class="p">(</span><span class="n">g</span><span class="p">(</span><span class="n">x</span><span class="p">))</span> <span class="o">==</span> <span class="n">x</span><span class="p">,</span> <span class="n">patterns</span> <span class="o">=</span> <span class="p">[</span><span class="n">g</span><span class="p">(</span><span class="n">x</span><span class="p">)]),</span> | ||||
|        <span class="n">g</span><span class="p">(</span><span class="n">a</span><span class="p">)</span> <span class="o">==</span> <span class="n">c</span><span class="p">,</span> | ||||
|        <span class="n">g</span><span class="p">(</span><span class="n">b</span><span class="p">)</span> <span class="o">==</span> <span class="n">c</span><span class="p">,</span> | ||||
|        <span class="n">a</span> <span class="o">!=</span> <span class="n">b</span> <span class="p">)</span> | ||||
| 
 | ||||
| <span class="c"># Display solver state using internal format</span> | ||||
| <span class="k">print</span> <span class="n">s</span><span class="o">.</span><span class="n">sexpr</span><span class="p">()</span> | ||||
| <span class="k">print</span> <span class="n">s</span><span class="o">.</span><span class="n">check</span><span class="p">()</span> | ||||
| </pre></div> | ||||
| </body></html></example> | ||||
| 
 | ||||
| <p> | ||||
| Some patterns may also create long instantiation chains. Consider the following assertion. | ||||
| </p> | ||||
| 
 | ||||
| <pre> | ||||
| ForAll([x, y], Implies(subtype(x, y), | ||||
|                        subtype(array_of(x), array_of(y))), | ||||
|        patterns=[subtype(x, y)]) | ||||
| </pre> | ||||
| 
 | ||||
| <p> | ||||
| The axiom gets instantiated whenever there is some ground term of the | ||||
| form <tt>subtype(s, t)</tt>. The instantiation causes a fresh ground term | ||||
| <tt>subtype(array_of(s), array_of(t))</tt>, which enables a new | ||||
| instantiation. This undesirable situation is called a matching | ||||
| loop. Z3 uses many heuristics to break matching loops. | ||||
| </p> | ||||
| 
 | ||||
| <p> | ||||
| Before elaborating on the subtleties, we should address an important | ||||
| first question. What defines the terms that are created during search? | ||||
| In the context of most SMT solvers, and of the Simplify theorem | ||||
| prover, terms exist as part of the input formula, they are of course | ||||
| also created by instantiating quantifiers, but terms are also | ||||
| implicitly created when equalities are asserted. The last point means | ||||
| that terms are considered up to congruence and pattern matching takes | ||||
| place modulo ground equalities. We call the matching problem | ||||
| <b>E-matching</b>. For example, if we have the following equalities: | ||||
| </p> | ||||
| 
 | ||||
| <example pref="quant.6"><html><body> | ||||
| <div class="highlight"><pre><span class="n">f</span> <span class="o">=</span> <span class="n">Function</span><span class="p">(</span><span class="s">'f'</span><span class="p">,</span> <span class="n">IntSort</span><span class="p">(),</span> <span class="n">IntSort</span><span class="p">())</span> | ||||
| <span class="n">g</span> <span class="o">=</span> <span class="n">Function</span><span class="p">(</span><span class="s">'g'</span><span class="p">,</span> <span class="n">IntSort</span><span class="p">(),</span> <span class="n">IntSort</span><span class="p">())</span> | ||||
| <span class="n">a</span><span class="p">,</span> <span class="n">b</span><span class="p">,</span> <span class="n">c</span> <span class="o">=</span> <span class="n">Ints</span><span class="p">(</span><span class="s">'a b c'</span><span class="p">)</span> | ||||
| <span class="n">x</span> <span class="o">=</span> <span class="n">Int</span><span class="p">(</span><span class="s">'x'</span><span class="p">)</span> | ||||
| 
 | ||||
| <span class="n">s</span> <span class="o">=</span> <span class="n">Solver</span><span class="p">()</span> | ||||
| <span class="n">s</span><span class="o">.</span><span class="n">set</span><span class="p">(</span><span class="n">auto_config</span><span class="o">=</span><span class="bp">False</span><span class="p">,</span> <span class="n">mbqi</span><span class="o">=</span><span class="bp">False</span><span class="p">)</span> | ||||
| 
 | ||||
| <span class="n">s</span><span class="o">.</span><span class="n">add</span><span class="p">(</span> <span class="n">ForAll</span><span class="p">(</span><span class="n">x</span><span class="p">,</span> <span class="n">f</span><span class="p">(</span><span class="n">g</span><span class="p">(</span><span class="n">x</span><span class="p">))</span> <span class="o">==</span> <span class="n">x</span><span class="p">,</span> <span class="n">patterns</span> <span class="o">=</span> <span class="p">[</span><span class="n">f</span><span class="p">(</span><span class="n">g</span><span class="p">(</span><span class="n">x</span><span class="p">))]),</span> | ||||
|        <span class="n">a</span> <span class="o">==</span> <span class="n">g</span><span class="p">(</span><span class="n">b</span><span class="p">),</span> | ||||
|        <span class="n">b</span> <span class="o">==</span> <span class="n">c</span><span class="p">,</span> | ||||
|        <span class="n">f</span><span class="p">(</span><span class="n">a</span><span class="p">)</span> <span class="o">!=</span> <span class="n">c</span> <span class="p">)</span> | ||||
| 
 | ||||
| <span class="k">print</span> <span class="n">s</span><span class="o">.</span><span class="n">check</span><span class="p">()</span> | ||||
| </pre></div> | ||||
| </body></html></example> | ||||
| 
 | ||||
| <p> | ||||
| The terms <tt>f(a)</tt> and <tt>f(g(b))</tt> are equal modulo the | ||||
| equalities. The pattern <tt>f(g(x))</tt> can be matched and <tt>x</tt> bound to <tt>b</tt> | ||||
| and the equality <tt>f(g(b)) ==  b</tt> is deduced. | ||||
| </p> | ||||
| 
 | ||||
| <p> | ||||
| While E-matching is an NP-complete problem, the main sources of overhead in larger verification | ||||
| problems comes from matching thousands of patterns in the context of an evolving set of terms and | ||||
| equalities. Z3 integrates an efficient E-matching engine using term indexing techniques. | ||||
| </p> | ||||
| 
 | ||||
| <h3>Multi-patterns</h3> | ||||
| 
 | ||||
| <p> | ||||
| In some cases, there is no pattern that contains all bound variables | ||||
| and does not contain interpreted symbols. In these cases, we use | ||||
| multi-patterns. In the following example, the quantified formula | ||||
| states that <tt>f</tt> is injective. This quantified formula is annotated with | ||||
| the multi-pattern <tt>MultiPattern(f(x), f(y))</tt>.   | ||||
| </p> | ||||
| 
 | ||||
| <example pref="quant.7"><html><body> | ||||
| <div class="highlight"><pre><span class="n">A</span> <span class="o">=</span> <span class="n">DeclareSort</span><span class="p">(</span><span class="s">'A'</span><span class="p">)</span> | ||||
| <span class="n">B</span> <span class="o">=</span> <span class="n">DeclareSort</span><span class="p">(</span><span class="s">'B'</span><span class="p">)</span> | ||||
| <span class="n">f</span> <span class="o">=</span> <span class="n">Function</span><span class="p">(</span><span class="s">'f'</span><span class="p">,</span> <span class="n">A</span><span class="p">,</span> <span class="n">B</span><span class="p">)</span> | ||||
| <span class="n">a1</span><span class="p">,</span> <span class="n">a2</span> <span class="o">=</span> <span class="n">Consts</span><span class="p">(</span><span class="s">'a1 a2'</span><span class="p">,</span> <span class="n">A</span><span class="p">)</span> | ||||
| <span class="n">b</span>      <span class="o">=</span> <span class="n">Const</span><span class="p">(</span><span class="s">'b'</span><span class="p">,</span> <span class="n">B</span><span class="p">)</span> | ||||
| <span class="n">x</span><span class="p">,</span>  <span class="n">y</span>  <span class="o">=</span> <span class="n">Consts</span><span class="p">(</span><span class="s">'x y'</span><span class="p">,</span> <span class="n">A</span><span class="p">)</span> | ||||
| 
 | ||||
| <span class="n">s</span> <span class="o">=</span> <span class="n">Solver</span><span class="p">()</span> | ||||
| <span class="n">s</span><span class="o">.</span><span class="n">add</span><span class="p">(</span><span class="n">a1</span> <span class="o">!=</span> <span class="n">a2</span><span class="p">,</span> | ||||
|       <span class="n">f</span><span class="p">(</span><span class="n">a1</span><span class="p">)</span> <span class="o">==</span> <span class="n">b</span><span class="p">,</span> | ||||
|       <span class="n">f</span><span class="p">(</span><span class="n">a2</span><span class="p">)</span> <span class="o">==</span> <span class="n">b</span><span class="p">,</span> | ||||
|       <span class="n">ForAll</span><span class="p">([</span><span class="n">x</span><span class="p">,</span> <span class="n">y</span><span class="p">],</span> <span class="n">Implies</span><span class="p">(</span><span class="n">f</span><span class="p">(</span><span class="n">x</span><span class="p">)</span> <span class="o">==</span> <span class="n">f</span><span class="p">(</span><span class="n">y</span><span class="p">),</span> <span class="n">x</span> <span class="o">==</span> <span class="n">y</span><span class="p">),</span> | ||||
|              <span class="n">patterns</span><span class="o">=</span><span class="p">[</span><span class="n">MultiPattern</span><span class="p">(</span><span class="n">f</span><span class="p">(</span><span class="n">x</span><span class="p">),</span> <span class="n">f</span><span class="p">(</span><span class="n">y</span><span class="p">))])</span> | ||||
|       <span class="p">)</span> | ||||
| <span class="k">print</span> <span class="n">s</span><span class="o">.</span><span class="n">check</span><span class="p">()</span> | ||||
| </pre></div> | ||||
| </body></html></example> | ||||
| 
 | ||||
| <p> | ||||
| The quantified formula is instantiated for every pair of occurrences | ||||
| of <tt>f</tt>. A simple trick allows formulating injectivity of <tt>f</tt> in such a way | ||||
| that only a linear number of instantiations is required. The trick is | ||||
| to realize that <tt>f</tt> is injective if and only if it has a partial | ||||
| inverse. | ||||
| </p> | ||||
| 
 | ||||
| <example pref="quant.8"><html><body> | ||||
| <div class="highlight"><pre><span class="n">A</span> <span class="o">=</span> <span class="n">DeclareSort</span><span class="p">(</span><span class="s">'A'</span><span class="p">)</span> | ||||
| <span class="n">B</span> <span class="o">=</span> <span class="n">DeclareSort</span><span class="p">(</span><span class="s">'B'</span><span class="p">)</span> | ||||
| <span class="n">f</span> <span class="o">=</span> <span class="n">Function</span><span class="p">(</span><span class="s">'f'</span><span class="p">,</span> <span class="n">A</span><span class="p">,</span> <span class="n">B</span><span class="p">)</span> | ||||
| <span class="n">finv</span> <span class="o">=</span> <span class="n">Function</span><span class="p">(</span><span class="s">'finv'</span><span class="p">,</span> <span class="n">B</span><span class="p">,</span> <span class="n">A</span><span class="p">)</span> | ||||
| <span class="n">a1</span><span class="p">,</span> <span class="n">a2</span> <span class="o">=</span> <span class="n">Consts</span><span class="p">(</span><span class="s">'a1 a2'</span><span class="p">,</span> <span class="n">A</span><span class="p">)</span> | ||||
| <span class="n">b</span>      <span class="o">=</span> <span class="n">Const</span><span class="p">(</span><span class="s">'b'</span><span class="p">,</span> <span class="n">B</span><span class="p">)</span> | ||||
| <span class="n">x</span><span class="p">,</span>  <span class="n">y</span>  <span class="o">=</span> <span class="n">Consts</span><span class="p">(</span><span class="s">'x y'</span><span class="p">,</span> <span class="n">A</span><span class="p">)</span> | ||||
| 
 | ||||
| <span class="n">s</span> <span class="o">=</span> <span class="n">Solver</span><span class="p">()</span> | ||||
| <span class="n">s</span><span class="o">.</span><span class="n">add</span><span class="p">(</span><span class="n">a1</span> <span class="o">!=</span> <span class="n">a2</span><span class="p">,</span> | ||||
|       <span class="n">f</span><span class="p">(</span><span class="n">a1</span><span class="p">)</span> <span class="o">==</span> <span class="n">b</span><span class="p">,</span> | ||||
|       <span class="n">f</span><span class="p">(</span><span class="n">a2</span><span class="p">)</span> <span class="o">==</span> <span class="n">b</span><span class="p">,</span> | ||||
|       <span class="n">ForAll</span><span class="p">(</span><span class="n">x</span><span class="p">,</span> <span class="n">finv</span><span class="p">(</span><span class="n">f</span><span class="p">(</span><span class="n">x</span><span class="p">))</span> <span class="o">==</span> <span class="n">x</span><span class="p">)</span> | ||||
|       <span class="p">)</span> | ||||
| <span class="k">print</span> <span class="n">s</span><span class="o">.</span><span class="n">check</span><span class="p">()</span> | ||||
| </pre></div> | ||||
| </body></html></example> | ||||
| 
 | ||||
| <h3>Other attributes</h3> | ||||
| 
 | ||||
| <p> | ||||
| In Z3Py, the following additional attributes are supported: <b>qid</b> (quantifier identifier | ||||
| for debugging), <b>weight</b> (hint to the quantifier instantiation module: "more weight equals less instances"),  | ||||
| <b>no_patterns</b> (expressions that should not be used as patterns, <b>skid</b> (identifier | ||||
| prefix used to create skolem constants/functions. | ||||
| </p> | ||||
| 
 | ||||
| <h2>Multiple Solvers</h2> | ||||
| 
 | ||||
| <p>In Z3Py and Z3 4.0 multiple solvers can be simultaneously used. | ||||
| It is also very easy to copy assertions/formulas from one solver to another. | ||||
| </p> | ||||
| 
 | ||||
| <example pref="msolver.1"><html><body> | ||||
| <div class="highlight"><pre><span class="n">x</span><span class="p">,</span> <span class="n">y</span> <span class="o">=</span> <span class="n">Ints</span><span class="p">(</span><span class="s">'x y'</span><span class="p">)</span> | ||||
| <span class="n">s1</span> <span class="o">=</span> <span class="n">Solver</span><span class="p">()</span> | ||||
| <span class="n">s1</span><span class="o">.</span><span class="n">add</span><span class="p">(</span><span class="n">x</span> <span class="o">></span> <span class="mi">10</span><span class="p">,</span> <span class="n">y</span> <span class="o">></span> <span class="mi">10</span><span class="p">)</span> | ||||
| <span class="n">s2</span> <span class="o">=</span> <span class="n">Solver</span><span class="p">()</span> | ||||
| <span class="c"># solver s2 is empty</span> | ||||
| <span class="k">print</span> <span class="n">s2</span> | ||||
| <span class="c"># copy assertions from s1 to s2</span> | ||||
| <span class="n">s2</span><span class="o">.</span><span class="n">add</span><span class="p">(</span><span class="n">s1</span><span class="o">.</span><span class="n">assertions</span><span class="p">())</span> | ||||
| <span class="k">print</span> <span class="n">s2</span> | ||||
| </pre></div> | ||||
| </body></html></example> | ||||
| 
 | ||||
| <h2>Unsat Cores and Soft Constraints</h2> | ||||
| 
 | ||||
| <p>Z3Py also supports <i>unsat core extraction</i>. The basic idea is to use | ||||
| <i>assumptions</i>, that is, auxiliary propositional variables that we want to track. | ||||
| Assumptions are also available in the Z3 SMT 2.0 frontend, and in other Z3 front-ends. | ||||
| They are used to extract unsatisfiable cores. They may be also used to "retract" | ||||
| constraints. Note that, assumptions are not really <i>soft constraints</i>, but they can be used to implement them.  | ||||
| </p> | ||||
| 
 | ||||
| <example pref="unsatcore.1"><html><body> | ||||
| <div class="highlight"><pre><span class="n">p1</span><span class="p">,</span> <span class="n">p2</span><span class="p">,</span> <span class="n">p3</span> <span class="o">=</span> <span class="n">Bools</span><span class="p">(</span><span class="s">'p1 p2 p3'</span><span class="p">)</span> | ||||
| <span class="n">x</span><span class="p">,</span> <span class="n">y</span> <span class="o">=</span> <span class="n">Ints</span><span class="p">(</span><span class="s">'x y'</span><span class="p">)</span> | ||||
| <span class="c"># We assert Implies(p, C) to track constraint C using p</span> | ||||
| <span class="n">s</span> <span class="o">=</span> <span class="n">Solver</span><span class="p">()</span> | ||||
| <span class="n">s</span><span class="o">.</span><span class="n">add</span><span class="p">(</span><span class="n">Implies</span><span class="p">(</span><span class="n">p1</span><span class="p">,</span> <span class="n">x</span> <span class="o">></span> <span class="mi">10</span><span class="p">),</span> | ||||
|       <span class="n">Implies</span><span class="p">(</span><span class="n">p1</span><span class="p">,</span> <span class="n">y</span> <span class="o">></span> <span class="n">x</span><span class="p">),</span> | ||||
|       <span class="n">Implies</span><span class="p">(</span><span class="n">p2</span><span class="p">,</span> <span class="n">y</span> <span class="o"><</span> <span class="mi">5</span><span class="p">),</span> | ||||
|       <span class="n">Implies</span><span class="p">(</span><span class="n">p3</span><span class="p">,</span> <span class="n">y</span> <span class="o">></span> <span class="mi">0</span><span class="p">))</span> | ||||
| <span class="k">print</span> <span class="n">s</span> | ||||
| <span class="c"># Check satisfiability assuming p1, p2, p3 are true</span> | ||||
| <span class="k">print</span> <span class="n">s</span><span class="o">.</span><span class="n">check</span><span class="p">(</span><span class="n">p1</span><span class="p">,</span> <span class="n">p2</span><span class="p">,</span> <span class="n">p3</span><span class="p">)</span> | ||||
| <span class="k">print</span> <span class="n">s</span><span class="o">.</span><span class="n">unsat_core</span><span class="p">()</span> | ||||
| 
 | ||||
| <span class="c"># Try again retracting p2</span> | ||||
| <span class="k">print</span> <span class="n">s</span><span class="o">.</span><span class="n">check</span><span class="p">(</span><span class="n">p1</span><span class="p">,</span> <span class="n">p3</span><span class="p">)</span> | ||||
| <span class="k">print</span> <span class="n">s</span><span class="o">.</span><span class="n">model</span><span class="p">()</span> | ||||
| </pre></div> | ||||
| </body></html></example> | ||||
| 
 | ||||
| <p>The example above also shows that a Boolean variable (<tt>p1</tt>) can be used to track | ||||
| more than one constraint. Note that Z3 does not guarantee that the unsat cores are minimal. | ||||
| </p> | ||||
| 
 | ||||
| <h2>Formatter</h2> | ||||
| 
 | ||||
| <p> | ||||
| Z3Py uses a formatter (aka pretty printer) for displaying formulas, expressions, solvers, and other | ||||
| Z3 objects. The formatter supports many configuration options.  | ||||
| The command <tt>set_option(html_mode=False)</tt> makes all formulas and expressions to be | ||||
| displayed in Z3Py notation. | ||||
| </p> | ||||
| 
 | ||||
| <example pref="printer"><html><body> | ||||
| <div class="highlight"><pre><span class="n">x</span> <span class="o">=</span> <span class="n">Int</span><span class="p">(</span><span class="s">'x'</span><span class="p">)</span> | ||||
| <span class="n">y</span> <span class="o">=</span> <span class="n">Int</span><span class="p">(</span><span class="s">'y'</span><span class="p">)</span> | ||||
| <span class="k">print</span> <span class="n">x</span><span class="o">**</span><span class="mi">2</span> <span class="o">+</span> <span class="n">y</span><span class="o">**</span><span class="mi">2</span> <span class="o">>=</span> <span class="mi">1</span> | ||||
| <span class="n">set_option</span><span class="p">(</span><span class="n">html_mode</span><span class="o">=</span><span class="bp">False</span><span class="p">)</span> | ||||
| <span class="k">print</span> <span class="n">x</span><span class="o">**</span><span class="mi">2</span> <span class="o">+</span> <span class="n">y</span><span class="o">**</span><span class="mi">2</span> <span class="o">>=</span> <span class="mi">1</span> | ||||
| </pre></div> | ||||
| </body></html></example> | ||||
| 
 | ||||
| <p>By default, Z3Py will truncate the output if the object being displayed is too big. | ||||
| Z3Py uses … to denote the output is truncated. | ||||
| The following configuration options can be set to control the behavior of Z3Py's formatter: | ||||
| </p> | ||||
| 
 | ||||
| <ul> | ||||
| <li> <tt>max_depth</tt> Maximal expression depth. Deep expressions are replaced with …. </li> | ||||
| <li> <tt>max_args</tt> Maximal number of arguments to display per node. </li> | ||||
| <li> <tt>rational_to_decimal</tt> Display rationals as decimals if True. </li> | ||||
| <li> <tt>precision</tt> Maximal number of decimal places for numbers being displayed in decimal notation. </li> | ||||
| <li> <tt>max_lines</tt> Maximal number of lines to be displayed. </li> | ||||
| <li> <tt>max_width</tt> Maximal line width (this is a suggestion to Z3Py). </li> | ||||
| <li> <tt>max_indent</tt> Maximal indentation.</li> | ||||
| </ul> | ||||
| 
 | ||||
| <example pref="format"><html><body> | ||||
| <div class="highlight"><pre><span class="n">x</span> <span class="o">=</span> <span class="n">IntVector</span><span class="p">(</span><span class="s">'x'</span><span class="p">,</span> <span class="mi">20</span><span class="p">)</span> | ||||
| <span class="n">y</span> <span class="o">=</span> <span class="n">IntVector</span><span class="p">(</span><span class="s">'y'</span><span class="p">,</span> <span class="mi">20</span><span class="p">)</span> | ||||
| <span class="n">f</span> <span class="o">=</span> <span class="n">And</span><span class="p">(</span><span class="n">Sum</span><span class="p">(</span><span class="n">x</span><span class="p">)</span> <span class="o">>=</span> <span class="mi">0</span><span class="p">,</span> <span class="n">Sum</span><span class="p">(</span><span class="n">y</span><span class="p">)</span> <span class="o">>=</span> <span class="mi">0</span><span class="p">)</span> | ||||
| 
 | ||||
| <span class="n">set_option</span><span class="p">(</span><span class="n">max_args</span><span class="o">=</span><span class="mi">5</span><span class="p">)</span> | ||||
| <span class="k">print</span> <span class="s">"</span><span class="se">\n</span><span class="s">test 1:"</span> | ||||
| <span class="k">print</span> <span class="n">f</span> | ||||
| 
 | ||||
| <span class="k">print</span> <span class="s">"</span><span class="se">\n</span><span class="s">test 2:"</span> | ||||
| <span class="n">set_option</span><span class="p">(</span><span class="n">max_args</span><span class="o">=</span><span class="mi">100</span><span class="p">,</span> <span class="n">max_lines</span><span class="o">=</span><span class="mi">10</span><span class="p">)</span> | ||||
| <span class="k">print</span> <span class="n">f</span> | ||||
| 
 | ||||
| <span class="k">print</span> <span class="s">"</span><span class="se">\n</span><span class="s">test 3:"</span> | ||||
| <span class="n">set_option</span><span class="p">(</span><span class="n">max_width</span><span class="o">=</span><span class="mi">300</span><span class="p">)</span> | ||||
| <span class="k">print</span> <span class="n">f</span> | ||||
| </pre></div> | ||||
| </body></html></example> | ||||
| 
 | ||||
| </body> | ||||
| </html> | ||||
							
								
								
									
										651
									
								
								examples/python/tutorial/html/fixpoint-examples.htm
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										651
									
								
								examples/python/tutorial/html/fixpoint-examples.htm
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,651 @@ | |||
| <html> | ||||
| <head> | ||||
| <title>Z3Py Fixedpoints</title> | ||||
| <link rel="StyleSheet" href="style.css" type="text/css"> | ||||
| </head> | ||||
| <body> | ||||
| 
 | ||||
| <h1>Fixedpoints</h1> | ||||
| 
 | ||||
| <p> | ||||
| </p> | ||||
| 
 | ||||
| <p> | ||||
| This tutorial illustrates uses of Z3's fixedpoint engine. | ||||
| The following papers | ||||
| <a href="http://research.microsoft.com/en-us/people/nbjorner/z3fix.pdf"> | ||||
| μZ - An Efficient Engine for Fixed-Points with Constraints.</a> | ||||
| (CAV 2011) and | ||||
| <a href="http://research.microsoft.com/en-us/people/nbjorner/z3pdr.pdf"> | ||||
| Generalized Property Directed Reachability</a> (SAT 2012) | ||||
| describe some of the main features of the engine. | ||||
| </p> | ||||
| 
 | ||||
| <p> | ||||
| Please send feedback, comments and/or corrections to  | ||||
| <a href="mailto:nbjorner@microsoft.com">nbjorner@microsoft.com</a>. | ||||
| </p> | ||||
| 
 | ||||
| <h2>Introduction</h2> | ||||
| 
 | ||||
| 
 | ||||
| <p> | ||||
| This tutorial covers some of the fixedpoint utilities available with Z3. | ||||
| The main features are a basic Datalog engine, an engine with relational | ||||
| algebra and an engine based on a generalization of the Property | ||||
| Directed Reachability algorithm. | ||||
| </p> | ||||
| 
 | ||||
| 
 | ||||
| <h2>Basic Datalog </h2> | ||||
| 
 | ||||
| <p>The default fixed-point engine is a bottom-up Datalog engine.  | ||||
| It works with finite relations and uses finite table representations | ||||
| as hash tables as the default way to represent finite relations. | ||||
| </p> | ||||
| 
 | ||||
| <h3>Relations, rules and queries</h3> | ||||
| 
 | ||||
| The first example illustrates how to declare relations, rules and | ||||
| how to pose queries. | ||||
| 
 | ||||
| <example pref="fixedpoint.1"><html><body> | ||||
| <div class="highlight"><pre><span class="n">fp</span> <span class="o">=</span> <span class="n">Fixedpoint</span><span class="p">()</span> | ||||
| 
 | ||||
| <span class="n">a</span><span class="p">,</span> <span class="n">b</span><span class="p">,</span> <span class="n">c</span> <span class="o">=</span> <span class="n">Bools</span><span class="p">(</span><span class="s">'a b c'</span><span class="p">)</span> | ||||
| 
 | ||||
| <span class="n">fp</span><span class="o">.</span><span class="n">register_relation</span><span class="p">(</span><span class="n">a</span><span class="o">.</span><span class="n">decl</span><span class="p">(),</span> <span class="n">b</span><span class="o">.</span><span class="n">decl</span><span class="p">(),</span> <span class="n">c</span><span class="o">.</span><span class="n">decl</span><span class="p">())</span> | ||||
| <span class="n">fp</span><span class="o">.</span><span class="n">rule</span><span class="p">(</span><span class="n">a</span><span class="p">,</span><span class="n">b</span><span class="p">)</span> | ||||
| <span class="n">fp</span><span class="o">.</span><span class="n">rule</span><span class="p">(</span><span class="n">b</span><span class="p">,</span><span class="n">c</span><span class="p">)</span> | ||||
| <span class="n">fp</span><span class="o">.</span><span class="n">set</span><span class="p">(</span><span class="n">engine</span><span class="o">=</span><span class="s">'datalog'</span><span class="p">)</span> | ||||
| 
 | ||||
| <span class="k">print</span> <span class="s">"current set of rules</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">fp</span> | ||||
| <span class="k">print</span> <span class="n">fp</span><span class="o">.</span><span class="n">query</span><span class="p">(</span><span class="n">a</span><span class="p">)</span> | ||||
| 
 | ||||
| <span class="n">fp</span><span class="o">.</span><span class="n">fact</span><span class="p">(</span><span class="n">c</span><span class="p">)</span> | ||||
| <span class="k">print</span> <span class="s">"updated set of rules</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">fp</span> | ||||
| <span class="k">print</span> <span class="n">fp</span><span class="o">.</span><span class="n">query</span><span class="p">(</span><span class="n">a</span><span class="p">)</span> | ||||
| <span class="k">print</span> <span class="n">fp</span><span class="o">.</span><span class="n">get_answer</span><span class="p">()</span> | ||||
| </pre></div> | ||||
| </body></html></example> | ||||
| 
 | ||||
| The example illustrates some of the basic constructs. | ||||
| <pre> | ||||
|   fp = Fixedpoint() | ||||
| </pre> | ||||
| creates a context for fixed-point computation. | ||||
| <pre> | ||||
|  fp.register_relation(a.decl(), b.decl(), c.decl()) | ||||
| </pre> | ||||
| Register the relations <tt>a, b, c</tt> as recursively defined. | ||||
| <pre> | ||||
|  fp.rule(a,b) | ||||
| </pre> | ||||
| Create the rule that <tt>a</tt> follows from <tt>b</tt>.  | ||||
| In general you can create a rule with multiple premises and a name using  | ||||
| the format | ||||
| <pre> | ||||
|  fp.rule(<em>head</em>,[<em>body1,...,bodyN</em>],<em>name</em>) | ||||
| </pre> | ||||
| The <em>name</em> is optional. It is used for tracking the rule in derivation proofs. | ||||
| 
 | ||||
| Continuing with the example, <tt>a</tt> is false unless <tt>b</tt> is established. | ||||
| <pre> | ||||
|  fp.query(a) | ||||
| </pre> | ||||
| Asks if <tt>a</tt> can be derived. The rules so far say that <tt>a</tt>  | ||||
| follows if <tt>b</tt> is established and that <tt>b</tt> follows if <tt>c</tt>  | ||||
| is established. But nothing establishes <tt>c</tt> and <tt>b</tt> is also not | ||||
| established, so <tt>a</tt> cannot be derived. | ||||
| <pre> | ||||
|  fp.fact(c) | ||||
| </pre> | ||||
| Add a fact (shorthand for <tt>fp.rule(c,True)</tt>). | ||||
| Now it is the case that <tt>a</tt> can be derived. | ||||
| 
 | ||||
| <h3>Explanations</h3> | ||||
| <p> | ||||
| It is also possible to get an explanation for a derived query. | ||||
| For the finite Datalog engine, an explanation is a trace that | ||||
| provides information of how a fact was derived. The explanation | ||||
| is an expression whose function symbols are Horn rules and facts used | ||||
| in the derivation. | ||||
| </p> | ||||
| <example pref="fixedpoint.2"><html><body> | ||||
| <div class="highlight"><pre><span class="n">fp</span> <span class="o">=</span> <span class="n">Fixedpoint</span><span class="p">()</span> | ||||
| 
 | ||||
| <span class="n">a</span><span class="p">,</span> <span class="n">b</span><span class="p">,</span> <span class="n">c</span> <span class="o">=</span> <span class="n">Bools</span><span class="p">(</span><span class="s">'a b c'</span><span class="p">)</span> | ||||
| 
 | ||||
| <span class="n">fp</span><span class="o">.</span><span class="n">register_relation</span><span class="p">(</span><span class="n">a</span><span class="o">.</span><span class="n">decl</span><span class="p">(),</span> <span class="n">b</span><span class="o">.</span><span class="n">decl</span><span class="p">(),</span> <span class="n">c</span><span class="o">.</span><span class="n">decl</span><span class="p">())</span> | ||||
| <span class="n">fp</span><span class="o">.</span><span class="n">rule</span><span class="p">(</span><span class="n">a</span><span class="p">,</span><span class="n">b</span><span class="p">)</span> | ||||
| <span class="n">fp</span><span class="o">.</span><span class="n">rule</span><span class="p">(</span><span class="n">b</span><span class="p">,</span><span class="n">c</span><span class="p">)</span> | ||||
| <span class="n">fp</span><span class="o">.</span><span class="n">fact</span><span class="p">(</span><span class="n">c</span><span class="p">)</span> | ||||
| <span class="n">fp</span><span class="o">.</span><span class="n">set</span><span class="p">(</span><span class="n">generate_explanations</span><span class="o">=</span><span class="bp">True</span><span class="p">,</span> <span class="n">engine</span><span class="o">=</span><span class="s">'datalog'</span><span class="p">)</span> | ||||
| <span class="k">print</span> <span class="n">fp</span><span class="o">.</span><span class="n">query</span><span class="p">(</span><span class="n">a</span><span class="p">)</span> | ||||
| <span class="k">print</span> <span class="n">fp</span><span class="o">.</span><span class="n">get_answer</span><span class="p">()</span> | ||||
| </pre></div> | ||||
| </body></html></example> | ||||
| 
 | ||||
| <h3>Relations with arguments</h3> | ||||
| <p> | ||||
| Relations can take arguments. We illustrate relations with arguments | ||||
| using edges and paths in a graph. | ||||
| </p> | ||||
| <example pref="fixedpoint.3"><html><body> | ||||
| <div class="highlight"><pre><span class="n">fp</span> <span class="o">=</span> <span class="n">Fixedpoint</span><span class="p">()</span> | ||||
| <span class="n">fp</span><span class="o">.</span><span class="n">set</span><span class="p">(</span><span class="n">engine</span><span class="o">=</span><span class="s">'datalog'</span><span class="p">)</span> | ||||
| 
 | ||||
| <span class="n">s</span> <span class="o">=</span> <span class="n">BitVecSort</span><span class="p">(</span><span class="mi">3</span><span class="p">)</span> | ||||
| <span class="n">edge</span> <span class="o">=</span> <span class="n">Function</span><span class="p">(</span><span class="s">'edge'</span><span class="p">,</span> <span class="n">s</span><span class="p">,</span> <span class="n">s</span><span class="p">,</span> <span class="n">BoolSort</span><span class="p">())</span> | ||||
| <span class="n">path</span> <span class="o">=</span> <span class="n">Function</span><span class="p">(</span><span class="s">'path'</span><span class="p">,</span> <span class="n">s</span><span class="p">,</span> <span class="n">s</span><span class="p">,</span> <span class="n">BoolSort</span><span class="p">())</span> | ||||
| <span class="n">a</span> <span class="o">=</span> <span class="n">Const</span><span class="p">(</span><span class="s">'a'</span><span class="p">,</span><span class="n">s</span><span class="p">)</span> | ||||
| <span class="n">b</span> <span class="o">=</span> <span class="n">Const</span><span class="p">(</span><span class="s">'b'</span><span class="p">,</span><span class="n">s</span><span class="p">)</span> | ||||
| <span class="n">c</span> <span class="o">=</span> <span class="n">Const</span><span class="p">(</span><span class="s">'c'</span><span class="p">,</span><span class="n">s</span><span class="p">)</span> | ||||
| 
 | ||||
| <span class="n">fp</span><span class="o">.</span><span class="n">register_relation</span><span class="p">(</span><span class="n">path</span><span class="p">,</span><span class="n">edge</span><span class="p">)</span> | ||||
| <span class="n">fp</span><span class="o">.</span><span class="n">declare_var</span><span class="p">(</span><span class="n">a</span><span class="p">,</span><span class="n">b</span><span class="p">,</span><span class="n">c</span><span class="p">)</span> | ||||
| <span class="n">fp</span><span class="o">.</span><span class="n">rule</span><span class="p">(</span><span class="n">path</span><span class="p">(</span><span class="n">a</span><span class="p">,</span><span class="n">b</span><span class="p">),</span> <span class="n">edge</span><span class="p">(</span><span class="n">a</span><span class="p">,</span><span class="n">b</span><span class="p">))</span> | ||||
| <span class="n">fp</span><span class="o">.</span><span class="n">rule</span><span class="p">(</span><span class="n">path</span><span class="p">(</span><span class="n">a</span><span class="p">,</span><span class="n">c</span><span class="p">),</span> <span class="p">[</span><span class="n">edge</span><span class="p">(</span><span class="n">a</span><span class="p">,</span><span class="n">b</span><span class="p">),</span><span class="n">path</span><span class="p">(</span><span class="n">b</span><span class="p">,</span><span class="n">c</span><span class="p">)])</span> | ||||
| 
 | ||||
| <span class="n">v1</span> <span class="o">=</span> <span class="n">BitVecVal</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span><span class="n">s</span><span class="p">)</span> | ||||
| <span class="n">v2</span> <span class="o">=</span> <span class="n">BitVecVal</span><span class="p">(</span><span class="mi">2</span><span class="p">,</span><span class="n">s</span><span class="p">)</span> | ||||
| <span class="n">v3</span> <span class="o">=</span> <span class="n">BitVecVal</span><span class="p">(</span><span class="mi">3</span><span class="p">,</span><span class="n">s</span><span class="p">)</span> | ||||
| <span class="n">v4</span> <span class="o">=</span> <span class="n">BitVecVal</span><span class="p">(</span><span class="mi">4</span><span class="p">,</span><span class="n">s</span><span class="p">)</span> | ||||
| 
 | ||||
| <span class="n">fp</span><span class="o">.</span><span class="n">fact</span><span class="p">(</span><span class="n">edge</span><span class="p">(</span><span class="n">v1</span><span class="p">,</span><span class="n">v2</span><span class="p">))</span> | ||||
| <span class="n">fp</span><span class="o">.</span><span class="n">fact</span><span class="p">(</span><span class="n">edge</span><span class="p">(</span><span class="n">v1</span><span class="p">,</span><span class="n">v3</span><span class="p">))</span> | ||||
| <span class="n">fp</span><span class="o">.</span><span class="n">fact</span><span class="p">(</span><span class="n">edge</span><span class="p">(</span><span class="n">v2</span><span class="p">,</span><span class="n">v4</span><span class="p">))</span> | ||||
| 
 | ||||
| <span class="k">print</span> <span class="s">"current set of rules"</span><span class="p">,</span> <span class="n">fp</span> | ||||
| 
 | ||||
| 
 | ||||
| <span class="k">print</span> <span class="n">fp</span><span class="o">.</span><span class="n">query</span><span class="p">(</span><span class="n">path</span><span class="p">(</span><span class="n">v1</span><span class="p">,</span><span class="n">v4</span><span class="p">)),</span> <span class="s">"yes we can reach v4 from v1"</span> | ||||
| 
 | ||||
| <span class="k">print</span> <span class="n">fp</span><span class="o">.</span><span class="n">query</span><span class="p">(</span><span class="n">path</span><span class="p">(</span><span class="n">v3</span><span class="p">,</span><span class="n">v4</span><span class="p">)),</span> <span class="s">"no we cannot reach v4 from v3"</span> | ||||
| </pre></div> | ||||
| </body></html></example> | ||||
| 
 | ||||
| The example uses the declaration | ||||
| <pre> | ||||
|  fp.declare_var(a,b,c) | ||||
| </pre> | ||||
| to instrument the fixed-point engine that <tt>a, b, c</tt>  | ||||
| should be treated as variables | ||||
| when they appear in rules. Think of the convention as they way bound variables are | ||||
| passed to quantifiers in Z3Py. | ||||
| 
 | ||||
| <h3>Rush Hour</h3> | ||||
| <p> | ||||
| A more entertaining example of using the basic fixed point engine | ||||
| is to solve the Rush Hour puzzle. The puzzle is about moving | ||||
| a red car out of a gridlock. We have encoded a configuration  | ||||
| and compiled a set of rules that encode the legal moves of the cars | ||||
| given the configuration. Other configurations can be tested by | ||||
| changing the parameters passed to the constructor for <t>Car</t>. | ||||
| We have encoded the configuration from  | ||||
| <a href="http://www.puzzles.com/products/RushHour/RHfromMarkRiedel/Jam.html?40" target="_top">  | ||||
| an online puzzle you can solve manually, or cheat on by asking Z3</a>. | ||||
| </p> | ||||
| <example pref="fixedpoint.4"><html><body> | ||||
| <div class="highlight"><pre><span class="k">class</span> <span class="nc">Car</span><span class="p">():</span> | ||||
|     <span class="k">def</span> <span class="nf">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">is_vertical</span><span class="p">,</span> <span class="n">base_pos</span><span class="p">,</span> <span class="n">length</span><span class="p">,</span> <span class="n">start</span><span class="p">,</span> <span class="n">color</span><span class="p">):</span> | ||||
| 	<span class="bp">self</span><span class="o">.</span><span class="n">is_vertical</span> <span class="o">=</span> <span class="n">is_vertical</span> | ||||
| 	<span class="bp">self</span><span class="o">.</span><span class="n">base</span> <span class="o">=</span> <span class="n">base_pos</span> | ||||
| 	<span class="bp">self</span><span class="o">.</span><span class="n">length</span> <span class="o">=</span> <span class="n">length</span> | ||||
| 	<span class="bp">self</span><span class="o">.</span><span class="n">start</span> <span class="o">=</span> <span class="n">start</span> | ||||
| 	<span class="bp">self</span><span class="o">.</span><span class="n">color</span> <span class="o">=</span> <span class="n">color</span> | ||||
| 
 | ||||
|     <span class="k">def</span> <span class="nf">__eq__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">other</span><span class="p">):</span> | ||||
| 	<span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">color</span> <span class="o">==</span> <span class="n">other</span><span class="o">.</span><span class="n">color</span> | ||||
| 
 | ||||
|     <span class="k">def</span> <span class="nf">__ne__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">other</span><span class="p">):</span> | ||||
| 	<span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">color</span> <span class="o">!=</span> <span class="n">other</span><span class="o">.</span><span class="n">color</span> | ||||
| 
 | ||||
| <span class="n">dimension</span> <span class="o">=</span> <span class="mi">6</span> | ||||
| 
 | ||||
| <span class="n">red_car</span> <span class="o">=</span> <span class="n">Car</span><span class="p">(</span><span class="bp">False</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">3</span><span class="p">,</span> <span class="s">"red"</span><span class="p">)</span> | ||||
| <span class="n">cars</span> <span class="o">=</span> <span class="p">[</span> | ||||
|     <span class="n">Car</span><span class="p">(</span><span class="bp">True</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">3</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="s">'yellow'</span><span class="p">),</span> | ||||
|     <span class="n">Car</span><span class="p">(</span><span class="bp">False</span><span class="p">,</span> <span class="mi">3</span><span class="p">,</span> <span class="mi">3</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="s">'blue'</span><span class="p">),</span> | ||||
|     <span class="n">Car</span><span class="p">(</span><span class="bp">False</span><span class="p">,</span> <span class="mi">5</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="s">"brown"</span><span class="p">),</span> | ||||
|     <span class="n">Car</span><span class="p">(</span><span class="bp">False</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="s">"lgreen"</span><span class="p">),</span> | ||||
|     <span class="n">Car</span><span class="p">(</span><span class="bp">True</span><span class="p">,</span>  <span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="s">"light blue"</span><span class="p">),</span> | ||||
|     <span class="n">Car</span><span class="p">(</span><span class="bp">True</span><span class="p">,</span>  <span class="mi">2</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="s">"pink"</span><span class="p">),</span> | ||||
|     <span class="n">Car</span><span class="p">(</span><span class="bp">True</span><span class="p">,</span>  <span class="mi">2</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">4</span><span class="p">,</span> <span class="s">"dark green"</span><span class="p">),</span> | ||||
|     <span class="n">red_car</span><span class="p">,</span> | ||||
|     <span class="n">Car</span><span class="p">(</span><span class="bp">True</span><span class="p">,</span>  <span class="mi">3</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">3</span><span class="p">,</span> <span class="s">"purple"</span><span class="p">),</span> | ||||
|     <span class="n">Car</span><span class="p">(</span><span class="bp">False</span><span class="p">,</span> <span class="mi">5</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">3</span><span class="p">,</span> <span class="s">"light yellow"</span><span class="p">),</span> | ||||
|     <span class="n">Car</span><span class="p">(</span><span class="bp">True</span><span class="p">,</span>  <span class="mi">4</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="s">"orange"</span><span class="p">),</span> | ||||
|     <span class="n">Car</span><span class="p">(</span><span class="bp">False</span><span class="p">,</span> <span class="mi">4</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">4</span><span class="p">,</span> <span class="s">"black"</span><span class="p">),</span> | ||||
|     <span class="n">Car</span><span class="p">(</span><span class="bp">True</span><span class="p">,</span>  <span class="mi">5</span><span class="p">,</span> <span class="mi">3</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="s">"light purple"</span><span class="p">)</span> | ||||
|     <span class="p">]</span> | ||||
| 
 | ||||
| <span class="n">num_cars</span> <span class="o">=</span> <span class="nb">len</span><span class="p">(</span><span class="n">cars</span><span class="p">)</span> | ||||
| <span class="n">B</span> <span class="o">=</span> <span class="n">BoolSort</span><span class="p">()</span> | ||||
| <span class="n">bv3</span> <span class="o">=</span> <span class="n">BitVecSort</span><span class="p">(</span><span class="mi">3</span><span class="p">)</span> | ||||
| 
 | ||||
| 
 | ||||
| <span class="n">state</span> <span class="o">=</span> <span class="n">Function</span><span class="p">(</span><span class="s">'state'</span><span class="p">,</span> <span class="p">[</span> <span class="n">bv3</span> <span class="k">for</span> <span class="n">c</span> <span class="ow">in</span> <span class="n">cars</span><span class="p">]</span> <span class="o">+</span> <span class="p">[</span><span class="n">B</span><span class="p">])</span> | ||||
| 
 | ||||
| <span class="k">def</span> <span class="nf">num</span><span class="p">(</span><span class="n">i</span><span class="p">):</span> | ||||
|     <span class="k">return</span> <span class="n">BitVecVal</span><span class="p">(</span><span class="n">i</span><span class="p">,</span><span class="n">bv3</span><span class="p">)</span> | ||||
| 
 | ||||
| <span class="k">def</span> <span class="nf">bound</span><span class="p">(</span><span class="n">i</span><span class="p">):</span> | ||||
|     <span class="k">return</span> <span class="n">Const</span><span class="p">(</span><span class="n">cars</span><span class="p">[</span><span class="n">i</span><span class="p">]</span><span class="o">.</span><span class="n">color</span><span class="p">,</span> <span class="n">bv3</span><span class="p">)</span> | ||||
| 
 | ||||
| <span class="n">fp</span> <span class="o">=</span> <span class="n">Fixedpoint</span><span class="p">()</span> | ||||
| <span class="n">fp</span><span class="o">.</span><span class="n">set</span><span class="p">(</span><span class="n">generate_explanations</span><span class="o">=</span><span class="bp">True</span><span class="p">)</span> | ||||
| <span class="n">fp</span><span class="o">.</span><span class="n">declare_var</span><span class="p">([</span><span class="n">bound</span><span class="p">(</span><span class="n">i</span><span class="p">)</span> <span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="n">num_cars</span><span class="p">)])</span> | ||||
| <span class="n">fp</span><span class="o">.</span><span class="n">register_relation</span><span class="p">(</span><span class="n">state</span><span class="p">)</span> | ||||
| 
 | ||||
| <span class="k">def</span> <span class="nf">mk_state</span><span class="p">(</span><span class="n">car</span><span class="p">,</span> <span class="n">value</span><span class="p">):</span> | ||||
|     <span class="k">return</span> <span class="n">state</span><span class="p">([</span> <span class="p">(</span><span class="n">num</span><span class="p">(</span><span class="n">value</span><span class="p">)</span> <span class="k">if</span> <span class="p">(</span><span class="n">cars</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">==</span> <span class="n">car</span><span class="p">)</span> <span class="k">else</span> <span class="n">bound</span><span class="p">(</span><span class="n">i</span><span class="p">))</span> | ||||
| 		   <span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="n">num_cars</span><span class="p">)])</span> | ||||
| 
 | ||||
| <span class="k">def</span> <span class="nf">mk_transition</span><span class="p">(</span><span class="n">row</span><span class="p">,</span> <span class="n">col</span><span class="p">,</span> <span class="n">i0</span><span class="p">,</span> <span class="n">j</span><span class="p">,</span> <span class="n">car0</span><span class="p">):</span> | ||||
|     <span class="n">body</span> <span class="o">=</span> <span class="p">[</span><span class="n">mk_state</span><span class="p">(</span><span class="n">car0</span><span class="p">,</span> <span class="n">i0</span><span class="p">)]</span> | ||||
|     <span class="k">for</span> <span class="n">index</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="n">num_cars</span><span class="p">):</span> | ||||
| 	<span class="n">car</span> <span class="o">=</span> <span class="n">cars</span><span class="p">[</span><span class="n">index</span><span class="p">]</span> | ||||
| 	<span class="k">if</span> <span class="n">car0</span> <span class="o">!=</span> <span class="n">car</span><span class="p">:</span> | ||||
| 	    <span class="k">if</span> <span class="n">car</span><span class="o">.</span><span class="n">is_vertical</span> <span class="ow">and</span> <span class="n">car</span><span class="o">.</span><span class="n">base</span> <span class="o">==</span> <span class="n">col</span><span class="p">:</span> | ||||
| 		<span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="n">dimension</span><span class="p">):</span> | ||||
| 		    <span class="k">if</span> <span class="n">i</span> <span class="o"><=</span> <span class="n">row</span> <span class="ow">and</span> <span class="n">row</span> <span class="o"><</span> <span class="n">i</span> <span class="o">+</span> <span class="n">car</span><span class="o">.</span><span class="n">length</span> <span class="ow">and</span> <span class="n">i</span> <span class="o">+</span> <span class="n">car</span><span class="o">.</span><span class="n">length</span> <span class="o"><=</span> <span class="n">dimension</span><span class="p">:</span> | ||||
| 			   <span class="n">body</span> <span class="o">+=</span> <span class="p">[</span><span class="n">bound</span><span class="p">(</span><span class="n">index</span><span class="p">)</span> <span class="o">!=</span> <span class="n">num</span><span class="p">(</span><span class="n">i</span><span class="p">)]</span> | ||||
| 	    <span class="k">if</span> <span class="n">car</span><span class="o">.</span><span class="n">base</span> <span class="o">==</span> <span class="n">row</span> <span class="ow">and</span> <span class="ow">not</span> <span class="n">car</span><span class="o">.</span><span class="n">is_vertical</span><span class="p">:</span> | ||||
| 		<span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="n">dimension</span><span class="p">):</span> | ||||
| 		    <span class="k">if</span> <span class="n">i</span> <span class="o"><=</span> <span class="n">col</span> <span class="ow">and</span> <span class="n">col</span> <span class="o"><</span> <span class="n">i</span> <span class="o">+</span> <span class="n">car</span><span class="o">.</span><span class="n">length</span> <span class="ow">and</span> <span class="n">i</span> <span class="o">+</span> <span class="n">car</span><span class="o">.</span><span class="n">length</span> <span class="o"><=</span> <span class="n">dimension</span><span class="p">:</span> | ||||
| 			   <span class="n">body</span> <span class="o">+=</span> <span class="p">[</span><span class="n">bound</span><span class="p">(</span><span class="n">index</span><span class="p">)</span> <span class="o">!=</span> <span class="n">num</span><span class="p">(</span><span class="n">i</span><span class="p">)]</span> | ||||
| 
 | ||||
|     <span class="n">s</span> <span class="o">=</span> <span class="s">"</span><span class="si">%s</span><span class="s"> </span><span class="si">%d</span><span class="s">-></span><span class="si">%d</span><span class="s">"</span> <span class="o">%</span> <span class="p">(</span><span class="n">car0</span><span class="o">.</span><span class="n">color</span><span class="p">,</span> <span class="n">i0</span><span class="p">,</span> <span class="n">j</span><span class="p">)</span> | ||||
| 			 | ||||
|     <span class="n">fp</span><span class="o">.</span><span class="n">rule</span><span class="p">(</span><span class="n">mk_state</span><span class="p">(</span><span class="n">car0</span><span class="p">,</span> <span class="n">j</span><span class="p">),</span> <span class="n">body</span><span class="p">,</span> <span class="n">s</span><span class="p">)</span> | ||||
|      | ||||
| 
 | ||||
| <span class="k">def</span> <span class="nf">move_down</span><span class="p">(</span><span class="n">i</span><span class="p">,</span> <span class="n">car</span><span class="p">):</span> | ||||
|     <span class="n">free_row</span> <span class="o">=</span> <span class="n">i</span> <span class="o">+</span> <span class="n">car</span><span class="o">.</span><span class="n">length</span> | ||||
|     <span class="k">if</span> <span class="n">free_row</span> <span class="o"><</span> <span class="n">dimension</span><span class="p">:</span> | ||||
| 	<span class="n">mk_transition</span><span class="p">(</span><span class="n">free_row</span><span class="p">,</span> <span class="n">car</span><span class="o">.</span><span class="n">base</span><span class="p">,</span> <span class="n">i</span><span class="p">,</span> <span class="n">i</span> <span class="o">+</span> <span class="mi">1</span><span class="p">,</span> <span class="n">car</span><span class="p">)</span> | ||||
|              | ||||
| 
 | ||||
| <span class="k">def</span> <span class="nf">move_up</span><span class="p">(</span><span class="n">i</span><span class="p">,</span> <span class="n">car</span><span class="p">):</span> | ||||
|     <span class="n">free_row</span> <span class="o">=</span> <span class="n">i</span>  <span class="o">-</span> <span class="mi">1</span> | ||||
|     <span class="k">if</span> <span class="mi">0</span> <span class="o"><=</span> <span class="n">free_row</span> <span class="ow">and</span> <span class="n">i</span> <span class="o">+</span> <span class="n">car</span><span class="o">.</span><span class="n">length</span> <span class="o"><=</span> <span class="n">dimension</span><span class="p">:</span> | ||||
| 	<span class="n">mk_transition</span><span class="p">(</span><span class="n">free_row</span><span class="p">,</span> <span class="n">car</span><span class="o">.</span><span class="n">base</span><span class="p">,</span> <span class="n">i</span><span class="p">,</span> <span class="n">i</span> <span class="o">-</span> <span class="mi">1</span><span class="p">,</span> <span class="n">car</span><span class="p">)</span> | ||||
| 
 | ||||
| <span class="k">def</span> <span class="nf">move_left</span><span class="p">(</span><span class="n">i</span><span class="p">,</span> <span class="n">car</span><span class="p">):</span> | ||||
|     <span class="n">free_col</span> <span class="o">=</span> <span class="n">i</span> <span class="o">-</span> <span class="mi">1</span><span class="p">;</span> | ||||
|     <span class="k">if</span> <span class="mi">0</span> <span class="o"><=</span> <span class="n">free_col</span> <span class="ow">and</span> <span class="n">i</span> <span class="o">+</span> <span class="n">car</span><span class="o">.</span><span class="n">length</span> <span class="o"><=</span> <span class="n">dimension</span><span class="p">:</span> | ||||
| 	<span class="n">mk_transition</span><span class="p">(</span><span class="n">car</span><span class="o">.</span><span class="n">base</span><span class="p">,</span> <span class="n">free_col</span><span class="p">,</span> <span class="n">i</span><span class="p">,</span> <span class="n">i</span> <span class="o">-</span> <span class="mi">1</span><span class="p">,</span> <span class="n">car</span><span class="p">)</span> | ||||
| 	 | ||||
| 
 | ||||
| <span class="k">def</span> <span class="nf">move_right</span><span class="p">(</span><span class="n">i</span><span class="p">,</span> <span class="n">car</span><span class="p">):</span> | ||||
|     <span class="n">free_col</span> <span class="o">=</span> <span class="n">car</span><span class="o">.</span><span class="n">length</span> <span class="o">+</span> <span class="n">i</span> | ||||
|     <span class="k">if</span> <span class="n">free_col</span> <span class="o"><</span> <span class="n">dimension</span><span class="p">:</span> | ||||
| 	<span class="n">mk_transition</span><span class="p">(</span><span class="n">car</span><span class="o">.</span><span class="n">base</span><span class="p">,</span> <span class="n">free_col</span><span class="p">,</span> <span class="n">i</span><span class="p">,</span> <span class="n">i</span> <span class="o">+</span> <span class="mi">1</span><span class="p">,</span> <span class="n">car</span><span class="p">)</span> | ||||
| 	 | ||||
| 
 | ||||
| <span class="c"># Initial state:</span> | ||||
| <span class="n">fp</span><span class="o">.</span><span class="n">fact</span><span class="p">(</span><span class="n">state</span><span class="p">([</span><span class="n">num</span><span class="p">(</span><span class="n">cars</span><span class="p">[</span><span class="n">i</span><span class="p">]</span><span class="o">.</span><span class="n">start</span><span class="p">)</span> <span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="n">num_cars</span><span class="p">)]))</span> | ||||
| 
 | ||||
| <span class="c"># Transitions:</span> | ||||
| <span class="k">for</span> <span class="n">car</span> <span class="ow">in</span> <span class="n">cars</span><span class="p">:</span> | ||||
|     <span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="n">dimension</span><span class="p">):</span> | ||||
| 	<span class="k">if</span> <span class="n">car</span><span class="o">.</span><span class="n">is_vertical</span><span class="p">:</span> | ||||
| 	    <span class="n">move_down</span><span class="p">(</span><span class="n">i</span><span class="p">,</span> <span class="n">car</span><span class="p">)</span> | ||||
| 	    <span class="n">move_up</span><span class="p">(</span><span class="n">i</span><span class="p">,</span> <span class="n">car</span><span class="p">)</span> | ||||
| 	<span class="k">else</span><span class="p">:</span> | ||||
| 	    <span class="n">move_left</span><span class="p">(</span><span class="n">i</span><span class="p">,</span> <span class="n">car</span><span class="p">)</span> | ||||
| 	    <span class="n">move_right</span><span class="p">(</span><span class="n">i</span><span class="p">,</span> <span class="n">car</span><span class="p">)</span> | ||||
|      | ||||
| 
 | ||||
| <span class="k">def</span> <span class="nf">get_instructions</span><span class="p">(</span><span class="n">ans</span><span class="p">):</span> | ||||
|     <span class="n">lastAnd</span> <span class="o">=</span> <span class="n">ans</span><span class="o">.</span><span class="n">arg</span><span class="p">(</span><span class="mi">0</span><span class="p">)</span><span class="o">.</span><span class="n">children</span><span class="p">()[</span><span class="o">-</span><span class="mi">1</span><span class="p">]</span> | ||||
|     <span class="n">trace</span> <span class="o">=</span> <span class="n">lastAnd</span><span class="o">.</span><span class="n">children</span><span class="p">()[</span><span class="mi">1</span><span class="p">]</span> | ||||
|     <span class="k">while</span> <span class="n">trace</span><span class="o">.</span><span class="n">num_args</span><span class="p">()</span> <span class="o">></span> <span class="mi">0</span><span class="p">:</span> | ||||
| 	<span class="k">print</span> <span class="n">trace</span><span class="o">.</span><span class="n">decl</span><span class="p">()</span> | ||||
| 	<span class="n">trace</span> <span class="o">=</span> <span class="n">trace</span><span class="o">.</span><span class="n">children</span><span class="p">()[</span><span class="o">-</span><span class="mi">1</span><span class="p">]</span> | ||||
| 
 | ||||
| <span class="k">print</span> <span class="n">fp</span> | ||||
| 
 | ||||
| <span class="n">goal</span> <span class="o">=</span> <span class="n">state</span><span class="p">([</span> <span class="p">(</span><span class="n">num</span><span class="p">(</span><span class="mi">4</span><span class="p">)</span> <span class="k">if</span> <span class="n">cars</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">==</span> <span class="n">red_car</span> <span class="k">else</span> <span class="n">bound</span><span class="p">(</span><span class="n">i</span><span class="p">))</span> | ||||
| 	       <span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="n">num_cars</span><span class="p">)])</span> | ||||
| <span class="n">fp</span><span class="o">.</span><span class="n">query</span><span class="p">(</span><span class="n">goal</span><span class="p">)</span> | ||||
| 
 | ||||
| <span class="n">get_instructions</span><span class="p">(</span><span class="n">fp</span><span class="o">.</span><span class="n">get_answer</span><span class="p">())</span> | ||||
|      | ||||
| </pre></div> | ||||
| </body></html></example> | ||||
| 
 | ||||
| 
 | ||||
| <h2>Abstract Domains</h2> | ||||
| The underlying engine uses table operations  | ||||
| that are based on relational algebra. Representations are | ||||
| opaque to the underlying engine.  | ||||
| Relational algebra operations are well defined for arbitrary relations. | ||||
| They don't depend on whether the relations denote a finite or an  | ||||
| infinite set of values. | ||||
| Z3 contains two built-in tables for infinite domains. | ||||
| The first is for intervals of integers and reals. | ||||
| The second is for bound constraints between two integers or reals.  | ||||
| A bound constraint is of the form <tt>x  or <tt> x . | ||||
| When used in conjunction, they form | ||||
| an abstract domain that is called the  | ||||
| <a href="http://www.sciencedirect.com/science/article/pii/S0167642309000719"> | ||||
| <em>Pentagon</em></a> abstract | ||||
| domain. Z3 implements <em>reduced products</em> | ||||
| of abstract domains that enables sharing constraints between | ||||
| the interval and bounds domains. | ||||
| 
 | ||||
| </tt></tt><p> | ||||
| Below we give a simple example that illustrates a loop at location <tt>l0</tt>. | ||||
| The loop is incremented as long as the loop counter does not exceed an upper | ||||
| bound. Using the combination of bound and interval domains | ||||
| we can collect derived invariants from the loop and we can also establish | ||||
| that the state after the loop does not exceed the bound. | ||||
| </p> | ||||
| 
 | ||||
| 
 | ||||
| <example pref="fixedpoint.5"><html><body> | ||||
| <div class="highlight"><pre><span class="n">I</span>  <span class="o">=</span> <span class="n">IntSort</span><span class="p">()</span> | ||||
| <span class="n">B</span>  <span class="o">=</span> <span class="n">BoolSort</span><span class="p">()</span> | ||||
| <span class="n">l0</span> <span class="o">=</span> <span class="n">Function</span><span class="p">(</span><span class="s">'l0'</span><span class="p">,</span><span class="n">I</span><span class="p">,</span><span class="n">I</span><span class="p">,</span><span class="n">B</span><span class="p">)</span> | ||||
| <span class="n">l1</span> <span class="o">=</span> <span class="n">Function</span><span class="p">(</span><span class="s">'l1'</span><span class="p">,</span><span class="n">I</span><span class="p">,</span><span class="n">I</span><span class="p">,</span><span class="n">B</span><span class="p">)</span> | ||||
| 
 | ||||
| <span class="n">s</span> <span class="o">=</span> <span class="n">Fixedpoint</span><span class="p">()</span> | ||||
| <span class="n">s</span><span class="o">.</span><span class="n">set</span><span class="p">(</span><span class="n">engine</span><span class="o">=</span><span class="s">'datalog'</span><span class="p">,</span><span class="n">compile_with_widening</span><span class="o">=</span><span class="bp">True</span><span class="p">,</span> | ||||
|       <span class="n">unbound_compressor</span><span class="o">=</span><span class="bp">False</span><span class="p">)</span> | ||||
| 
 | ||||
| <span class="n">s</span><span class="o">.</span><span class="n">register_relation</span><span class="p">(</span><span class="n">l0</span><span class="p">,</span><span class="n">l1</span><span class="p">)</span> | ||||
| <span class="n">s</span><span class="o">.</span><span class="n">set_predicate_representation</span><span class="p">(</span><span class="n">l0</span><span class="p">,</span> <span class="s">'interval_relation'</span><span class="p">,</span> <span class="s">'bound_relation'</span><span class="p">)</span> | ||||
| <span class="n">s</span><span class="o">.</span><span class="n">set_predicate_representation</span><span class="p">(</span><span class="n">l1</span><span class="p">,</span> <span class="s">'interval_relation'</span><span class="p">,</span> <span class="s">'bound_relation'</span><span class="p">)</span> | ||||
| 
 | ||||
| <span class="n">m</span><span class="p">,</span> <span class="n">x</span><span class="p">,</span> <span class="n">y</span> <span class="o">=</span> <span class="n">Ints</span><span class="p">(</span><span class="s">'m x y'</span><span class="p">)</span> | ||||
| 
 | ||||
| <span class="n">s</span><span class="o">.</span><span class="n">declare_var</span><span class="p">(</span><span class="n">m</span><span class="p">,</span> <span class="n">x</span><span class="p">,</span> <span class="n">y</span><span class="p">)</span> | ||||
| <span class="n">s</span><span class="o">.</span><span class="n">rule</span><span class="p">(</span><span class="n">l0</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span><span class="n">m</span><span class="p">),</span>   <span class="mi">0</span> <span class="o"><</span> <span class="n">m</span><span class="p">)</span> | ||||
| <span class="n">s</span><span class="o">.</span><span class="n">rule</span><span class="p">(</span><span class="n">l0</span><span class="p">(</span><span class="n">x</span><span class="o">+</span><span class="mi">1</span><span class="p">,</span><span class="n">m</span><span class="p">),</span> <span class="p">[</span><span class="n">l0</span><span class="p">(</span><span class="n">x</span><span class="p">,</span><span class="n">m</span><span class="p">),</span> <span class="n">x</span> <span class="o"><</span> <span class="n">m</span><span class="p">])</span> | ||||
| <span class="n">s</span><span class="o">.</span><span class="n">rule</span><span class="p">(</span><span class="n">l1</span><span class="p">(</span><span class="n">x</span><span class="p">,</span><span class="n">m</span><span class="p">),</span>   <span class="p">[</span><span class="n">l0</span><span class="p">(</span><span class="n">x</span><span class="p">,</span><span class="n">m</span><span class="p">),</span> <span class="n">m</span> <span class="o"><=</span> <span class="n">x</span><span class="p">])</span> | ||||
| 
 | ||||
| <span class="k">print</span> <span class="s">"At l0 we learn that x, y are non-negative:"</span> | ||||
| <span class="k">print</span> <span class="n">s</span><span class="o">.</span><span class="n">query</span><span class="p">(</span><span class="n">l0</span><span class="p">(</span><span class="n">x</span><span class="p">,</span><span class="n">y</span><span class="p">))</span> | ||||
| <span class="k">print</span> <span class="n">s</span><span class="o">.</span><span class="n">get_answer</span><span class="p">()</span> | ||||
| 
 | ||||
| <span class="k">print</span> <span class="s">"At l1 we learn that x <= y and both x and y are bigger than 0:"</span> | ||||
| <span class="k">print</span> <span class="n">s</span><span class="o">.</span><span class="n">query</span><span class="p">(</span><span class="n">l1</span><span class="p">(</span><span class="n">x</span><span class="p">,</span><span class="n">y</span><span class="p">))</span> | ||||
| <span class="k">print</span> <span class="n">s</span><span class="o">.</span><span class="n">get_answer</span><span class="p">()</span> | ||||
| 
 | ||||
| 
 | ||||
| <span class="k">print</span> <span class="s">"The state where x < y is not reachable"</span> | ||||
| <span class="k">print</span> <span class="n">s</span><span class="o">.</span><span class="n">query</span><span class="p">(</span><span class="n">And</span><span class="p">(</span><span class="n">l1</span><span class="p">(</span><span class="n">x</span><span class="p">,</span><span class="n">y</span><span class="p">),</span> <span class="n">x</span> <span class="o"><</span> <span class="n">y</span><span class="p">))</span> | ||||
| </pre></div> | ||||
| </body></html></example> | ||||
| 
 | ||||
| The example uses the option | ||||
| <pre> | ||||
|    set_option(dl_compile_with_widening=True) | ||||
| </pre> | ||||
| to instrument Z3 to apply abstract interpretation <em>widening</em> on loop boundaries.  | ||||
| 
 | ||||
| 
 | ||||
| <h2>Engine for Property Directed Reachability</h2> | ||||
| 
 | ||||
| A different underlying engine for fixed-points is based on | ||||
| an algorithm for <it>Property Directed Reachability (PDR)</it>. | ||||
| The PDR engine is enabled using the instruction | ||||
| <pre> | ||||
|   set_option(dl_engine=1) | ||||
| </pre> | ||||
| The version in Z3 applies to Horn clauses with arithmetic and | ||||
| Boolean domains. When using arithmetic you should enable | ||||
| the main abstraction engine used in Z3 for arithmetic in PDR. | ||||
| <pre> | ||||
|  set_option(dl_pdr_use_farkas=True) | ||||
| </pre> | ||||
| The engine also works with domains using algebraic | ||||
| data-types and bit-vectors, although it is currently not | ||||
| overly tuned for either. | ||||
| The PDR engine is targeted at applications from symbolic model  | ||||
| checking of software. The systems may be infinite state.  | ||||
| The following examples also serve a purpose of showing  | ||||
| how software model checking problems (of safety properties) | ||||
| can be embedded into Horn clauses and solved using PDR. | ||||
| 
 | ||||
| <h3>Procedure Calls</h3> | ||||
| <p> | ||||
| McCarthy's 91 function illustrates a procedure that calls itself recursively | ||||
| twice. The Horn clauses below encode the recursive function: | ||||
| 
 | ||||
| </p> | ||||
| <pre> | ||||
|   mc(x) = if x > 100 then x - 10 else mc(mc(x+11)) | ||||
| </pre> | ||||
| 
 | ||||
| The general scheme for encoding recursive procedures is by creating a predicate | ||||
| for each procedure and adding an additional output variable to the predicate. | ||||
| Nested calls to procedures within a body can be encoded as a conjunction | ||||
| of relations. | ||||
| 
 | ||||
| 
 | ||||
| <example pref="fixedpoint.8"><html><body> | ||||
| <div class="highlight"><pre><span class="n">mc</span> <span class="o">=</span> <span class="n">Function</span><span class="p">(</span><span class="s">'mc'</span><span class="p">,</span> <span class="n">IntSort</span><span class="p">(),</span> <span class="n">IntSort</span><span class="p">(),</span> <span class="n">BoolSort</span><span class="p">())</span> | ||||
| <span class="n">n</span><span class="p">,</span> <span class="n">m</span><span class="p">,</span> <span class="n">p</span> <span class="o">=</span> <span class="n">Ints</span><span class="p">(</span><span class="s">'n m p'</span><span class="p">)</span> | ||||
| 
 | ||||
| <span class="n">fp</span> <span class="o">=</span> <span class="n">Fixedpoint</span><span class="p">()</span> | ||||
| 
 | ||||
| <span class="n">fp</span><span class="o">.</span><span class="n">declare_var</span><span class="p">(</span><span class="n">n</span><span class="p">,</span><span class="n">m</span><span class="p">)</span> | ||||
| <span class="n">fp</span><span class="o">.</span><span class="n">register_relation</span><span class="p">(</span><span class="n">mc</span><span class="p">)</span> | ||||
| 
 | ||||
| <span class="n">fp</span><span class="o">.</span><span class="n">rule</span><span class="p">(</span><span class="n">mc</span><span class="p">(</span><span class="n">m</span><span class="p">,</span> <span class="n">m</span><span class="o">-</span><span class="mi">10</span><span class="p">),</span> <span class="n">m</span> <span class="o">></span> <span class="mi">100</span><span class="p">)</span> | ||||
| <span class="n">fp</span><span class="o">.</span><span class="n">rule</span><span class="p">(</span><span class="n">mc</span><span class="p">(</span><span class="n">m</span><span class="p">,</span> <span class="n">n</span><span class="p">),</span> <span class="p">[</span><span class="n">m</span> <span class="o"><=</span> <span class="mi">100</span><span class="p">,</span> <span class="n">mc</span><span class="p">(</span><span class="n">m</span><span class="o">+</span><span class="mi">11</span><span class="p">,</span><span class="n">p</span><span class="p">),</span><span class="n">mc</span><span class="p">(</span><span class="n">p</span><span class="p">,</span><span class="n">n</span><span class="p">)])</span> | ||||
|      | ||||
| <span class="k">print</span> <span class="n">fp</span><span class="o">.</span><span class="n">query</span><span class="p">(</span><span class="n">And</span><span class="p">(</span><span class="n">mc</span><span class="p">(</span><span class="n">m</span><span class="p">,</span><span class="n">n</span><span class="p">),</span><span class="n">n</span> <span class="o"><</span> <span class="mi">90</span><span class="p">))</span> | ||||
| <span class="k">print</span> <span class="n">fp</span><span class="o">.</span><span class="n">get_answer</span><span class="p">()</span> | ||||
| 
 | ||||
| <span class="k">print</span> <span class="n">fp</span><span class="o">.</span><span class="n">query</span><span class="p">(</span><span class="n">And</span><span class="p">(</span><span class="n">mc</span><span class="p">(</span><span class="n">m</span><span class="p">,</span><span class="n">n</span><span class="p">),</span><span class="n">n</span> <span class="o"><</span> <span class="mi">91</span><span class="p">))</span> | ||||
| <span class="k">print</span> <span class="n">fp</span><span class="o">.</span><span class="n">get_answer</span><span class="p">()</span> | ||||
| 
 | ||||
| <span class="k">print</span> <span class="n">fp</span><span class="o">.</span><span class="n">query</span><span class="p">(</span><span class="n">And</span><span class="p">(</span><span class="n">mc</span><span class="p">(</span><span class="n">m</span><span class="p">,</span><span class="n">n</span><span class="p">),</span><span class="n">n</span> <span class="o"><</span> <span class="mi">92</span><span class="p">))</span> | ||||
| <span class="k">print</span> <span class="n">fp</span><span class="o">.</span><span class="n">get_answer</span><span class="p">()</span> | ||||
| </pre></div> | ||||
| </body></html></example> | ||||
| 
 | ||||
| The first two queries are unsatisfiable. The PDR engine produces the same proof of unsatisfiability. | ||||
| The proof is an inductive invariant for each recursive predicate. The PDR engine introduces a | ||||
| special query predicate for the query. | ||||
| 
 | ||||
| <h3>Bakery</h3> | ||||
| 
 | ||||
| <p> | ||||
| We can also prove invariants of reactive systems. It is convenient to encode reactive systems | ||||
| as guarded transition systems. It is perhaps for some not as convenient to directly encode  | ||||
| guarded transitions as recursive Horn clauses. But it is fairly easy to write a translator | ||||
| from guarded transition systems to recursive Horn clauses. We illustrate a translator | ||||
| and Lamport's two process Bakery algorithm in the next example. | ||||
| </p> | ||||
| 
 | ||||
| <example pref="fixedpoint.9"><html><body> | ||||
| <div class="highlight"><pre><span class="n">set_option</span><span class="p">(</span><span class="n">relevancy</span><span class="o">=</span><span class="mi">0</span><span class="p">,</span><span class="n">verbose</span><span class="o">=</span><span class="mi">1</span><span class="p">)</span> | ||||
| 
 | ||||
| <span class="k">def</span> <span class="nf">flatten</span><span class="p">(</span><span class="n">l</span><span class="p">):</span> | ||||
|     <span class="k">return</span> <span class="p">[</span><span class="n">s</span> <span class="k">for</span> <span class="n">t</span> <span class="ow">in</span> <span class="n">l</span> <span class="k">for</span> <span class="n">s</span> <span class="ow">in</span> <span class="n">t</span><span class="p">]</span> | ||||
| 
 | ||||
| 
 | ||||
| <span class="k">class</span> <span class="nc">TransitionSystem</span><span class="p">():</span> | ||||
|     <span class="k">def</span> <span class="nf">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">initial</span><span class="p">,</span> <span class="n">transitions</span><span class="p">,</span> <span class="n">vars1</span><span class="p">):</span> | ||||
| 	<span class="bp">self</span><span class="o">.</span><span class="n">fp</span> <span class="o">=</span> <span class="n">Fixedpoint</span><span class="p">()</span>         | ||||
| 	<span class="bp">self</span><span class="o">.</span><span class="n">initial</span>     <span class="o">=</span> <span class="n">initial</span> | ||||
| 	<span class="bp">self</span><span class="o">.</span><span class="n">transitions</span> <span class="o">=</span> <span class="n">transitions</span> | ||||
| 	<span class="bp">self</span><span class="o">.</span><span class="n">vars1</span> <span class="o">=</span> <span class="n">vars1</span> | ||||
| 
 | ||||
|     <span class="k">def</span> <span class="nf">declare_rels</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span> | ||||
| 	<span class="n">B</span> <span class="o">=</span> <span class="n">BoolSort</span><span class="p">()</span> | ||||
| 	<span class="n">var_sorts</span>   <span class="o">=</span> <span class="p">[</span> <span class="n">v</span><span class="o">.</span><span class="n">sort</span><span class="p">()</span> <span class="k">for</span> <span class="n">v</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">vars1</span> <span class="p">]</span> | ||||
| 	<span class="n">state_sorts</span> <span class="o">=</span> <span class="n">var_sorts</span> | ||||
| 	<span class="bp">self</span><span class="o">.</span><span class="n">state_vals</span> <span class="o">=</span> <span class="p">[</span> <span class="n">v</span> <span class="k">for</span> <span class="n">v</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">vars1</span> <span class="p">]</span> | ||||
| 	<span class="bp">self</span><span class="o">.</span><span class="n">state_sorts</span>  <span class="o">=</span> <span class="n">state_sorts</span> | ||||
| 	<span class="bp">self</span><span class="o">.</span><span class="n">var_sorts</span> <span class="o">=</span> <span class="n">var_sorts</span> | ||||
| 	<span class="bp">self</span><span class="o">.</span><span class="n">state</span>  <span class="o">=</span> <span class="n">Function</span><span class="p">(</span><span class="s">'state'</span><span class="p">,</span> <span class="n">state_sorts</span> <span class="o">+</span> <span class="p">[</span> <span class="n">B</span> <span class="p">])</span> | ||||
| 	<span class="bp">self</span><span class="o">.</span><span class="n">step</span>   <span class="o">=</span> <span class="n">Function</span><span class="p">(</span><span class="s">'step'</span><span class="p">,</span>  <span class="n">state_sorts</span> <span class="o">+</span> <span class="n">state_sorts</span> <span class="o">+</span> <span class="p">[</span> <span class="n">B</span> <span class="p">])</span> | ||||
| 	<span class="bp">self</span><span class="o">.</span><span class="n">fp</span><span class="o">.</span><span class="n">register_relation</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">state</span><span class="p">)</span> | ||||
| 	<span class="bp">self</span><span class="o">.</span><span class="n">fp</span><span class="o">.</span><span class="n">register_relation</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">step</span><span class="p">)</span> | ||||
| 
 | ||||
| <span class="c"># Set of reachable states are transitive closure of step.</span> | ||||
| 
 | ||||
|     <span class="k">def</span> <span class="nf">state0</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span> | ||||
| 	<span class="n">idx</span> <span class="o">=</span> <span class="nb">range</span><span class="p">(</span><span class="nb">len</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">state_sorts</span><span class="p">))</span> | ||||
| 	<span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">state</span><span class="p">([</span><span class="n">Var</span><span class="p">(</span><span class="n">i</span><span class="p">,</span><span class="bp">self</span><span class="o">.</span><span class="n">state_sorts</span><span class="p">[</span><span class="n">i</span><span class="p">])</span> <span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="n">idx</span><span class="p">])</span> | ||||
| 	 | ||||
|     <span class="k">def</span> <span class="nf">state1</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span> | ||||
| 	<span class="n">n</span> <span class="o">=</span> <span class="nb">len</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">state_sorts</span><span class="p">)</span> | ||||
| 	<span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">state</span><span class="p">([</span><span class="n">Var</span><span class="p">(</span><span class="n">i</span><span class="o">+</span><span class="n">n</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">state_sorts</span><span class="p">[</span><span class="n">i</span><span class="p">])</span> <span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="n">n</span><span class="p">)])</span> | ||||
| 
 | ||||
|     <span class="k">def</span> <span class="nf">rho</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span> | ||||
| 	<span class="n">n</span> <span class="o">=</span> <span class="nb">len</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">state_sorts</span><span class="p">)</span> | ||||
| 	<span class="n">args1</span> <span class="o">=</span> <span class="p">[</span> <span class="n">Var</span><span class="p">(</span><span class="n">i</span><span class="p">,</span><span class="bp">self</span><span class="o">.</span><span class="n">state_sorts</span><span class="p">[</span><span class="n">i</span><span class="p">])</span> <span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="n">n</span><span class="p">)</span> <span class="p">]</span> | ||||
| 	<span class="n">args2</span> <span class="o">=</span> <span class="p">[</span> <span class="n">Var</span><span class="p">(</span><span class="n">i</span><span class="o">+</span><span class="n">n</span><span class="p">,</span><span class="bp">self</span><span class="o">.</span><span class="n">state_sorts</span><span class="p">[</span><span class="n">i</span><span class="p">])</span> <span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="n">n</span><span class="p">)</span> <span class="p">]</span> | ||||
| 	<span class="n">args</span> <span class="o">=</span> <span class="n">args1</span> <span class="o">+</span> <span class="n">args2</span>  | ||||
| 	<span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">step</span><span class="p">(</span><span class="n">args</span><span class="p">)</span> | ||||
| 
 | ||||
|     <span class="k">def</span> <span class="nf">declare_reachability</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span> | ||||
| 	<span class="bp">self</span><span class="o">.</span><span class="n">fp</span><span class="o">.</span><span class="n">rule</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">state1</span><span class="p">(),</span> <span class="p">[</span><span class="bp">self</span><span class="o">.</span><span class="n">state0</span><span class="p">(),</span> <span class="bp">self</span><span class="o">.</span><span class="n">rho</span><span class="p">()])</span> | ||||
| 
 | ||||
| 
 | ||||
| <span class="c"># Define transition relation</span> | ||||
| 
 | ||||
|     <span class="k">def</span> <span class="nf">abstract</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">e</span><span class="p">):</span> | ||||
| 	<span class="n">n</span> <span class="o">=</span> <span class="nb">len</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">state_sorts</span><span class="p">)</span> | ||||
| 	<span class="n">sub</span> <span class="o">=</span> <span class="p">[(</span><span class="bp">self</span><span class="o">.</span><span class="n">state_vals</span><span class="p">[</span><span class="n">i</span><span class="p">],</span> <span class="n">Var</span><span class="p">(</span><span class="n">i</span><span class="p">,</span><span class="bp">self</span><span class="o">.</span><span class="n">state_sorts</span><span class="p">[</span><span class="n">i</span><span class="p">]))</span> <span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="n">n</span><span class="p">)]</span> | ||||
| 	<span class="k">return</span> <span class="n">substitute</span><span class="p">(</span><span class="n">e</span><span class="p">,</span> <span class="n">sub</span><span class="p">)</span> | ||||
| 	 | ||||
|     <span class="k">def</span> <span class="nf">declare_transition</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">tr</span><span class="p">):</span> | ||||
| 	<span class="n">len_s</span>  <span class="o">=</span> <span class="nb">len</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">state_sorts</span><span class="p">)</span> | ||||
| 	<span class="n">effect</span> <span class="o">=</span> <span class="n">tr</span><span class="p">[</span><span class="s">"effect"</span><span class="p">]</span> | ||||
| 	<span class="n">vars1</span>  <span class="o">=</span> <span class="p">[</span><span class="n">Var</span><span class="p">(</span><span class="n">i</span><span class="p">,</span><span class="bp">self</span><span class="o">.</span><span class="n">state_sorts</span><span class="p">[</span><span class="n">i</span><span class="p">])</span> <span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="n">len_s</span><span class="p">)]</span> <span class="o">+</span> <span class="n">effect</span> | ||||
| 	<span class="n">rho1</span>  <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">abstract</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">step</span><span class="p">(</span><span class="n">vars1</span><span class="p">))</span> | ||||
| 	<span class="n">guard</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">abstract</span><span class="p">(</span><span class="n">tr</span><span class="p">[</span><span class="s">"guard"</span><span class="p">])</span> | ||||
| 	<span class="bp">self</span><span class="o">.</span><span class="n">fp</span><span class="o">.</span><span class="n">rule</span><span class="p">(</span><span class="n">rho1</span><span class="p">,</span> <span class="n">guard</span><span class="p">)</span> | ||||
| 	 | ||||
|     <span class="k">def</span> <span class="nf">declare_transitions</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span> | ||||
| 	<span class="k">for</span> <span class="n">t</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">transitions</span><span class="p">:</span> | ||||
| 	    <span class="bp">self</span><span class="o">.</span><span class="n">declare_transition</span><span class="p">(</span><span class="n">t</span><span class="p">)</span> | ||||
| 
 | ||||
|     <span class="k">def</span> <span class="nf">declare_initial</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span> | ||||
| 	<span class="bp">self</span><span class="o">.</span><span class="n">fp</span><span class="o">.</span><span class="n">rule</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">state0</span><span class="p">(),[</span><span class="bp">self</span><span class="o">.</span><span class="n">abstract</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">initial</span><span class="p">)])</span> | ||||
| 	 | ||||
|     <span class="k">def</span> <span class="nf">query</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">query</span><span class="p">):</span> | ||||
| 	<span class="bp">self</span><span class="o">.</span><span class="n">declare_rels</span><span class="p">()</span> | ||||
| 	<span class="bp">self</span><span class="o">.</span><span class="n">declare_initial</span><span class="p">()</span> | ||||
| 	<span class="bp">self</span><span class="o">.</span><span class="n">declare_reachability</span><span class="p">()</span> | ||||
| 	<span class="bp">self</span><span class="o">.</span><span class="n">declare_transitions</span><span class="p">()</span> | ||||
| 	<span class="n">query</span> <span class="o">=</span> <span class="n">And</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">state0</span><span class="p">(),</span> <span class="bp">self</span><span class="o">.</span><span class="n">abstract</span><span class="p">(</span><span class="n">query</span><span class="p">))</span> | ||||
| 	<span class="k">print</span> <span class="bp">self</span><span class="o">.</span><span class="n">fp</span> | ||||
| 	<span class="k">print</span> <span class="n">query</span> | ||||
| 	<span class="k">print</span> <span class="bp">self</span><span class="o">.</span><span class="n">fp</span><span class="o">.</span><span class="n">query</span><span class="p">(</span><span class="n">query</span><span class="p">)</span> | ||||
| 	<span class="k">print</span> <span class="bp">self</span><span class="o">.</span><span class="n">fp</span><span class="o">.</span><span class="n">get_answer</span><span class="p">()</span> | ||||
| <span class="c">#	print self.fp.statistics()</span> | ||||
| 
 | ||||
| 
 | ||||
| <span class="n">L</span> <span class="o">=</span> <span class="n">Datatype</span><span class="p">(</span><span class="s">'L'</span><span class="p">)</span> | ||||
| <span class="n">L</span><span class="o">.</span><span class="n">declare</span><span class="p">(</span><span class="s">'L0'</span><span class="p">)</span> | ||||
| <span class="n">L</span><span class="o">.</span><span class="n">declare</span><span class="p">(</span><span class="s">'L1'</span><span class="p">)</span> | ||||
| <span class="n">L</span><span class="o">.</span><span class="n">declare</span><span class="p">(</span><span class="s">'L2'</span><span class="p">)</span> | ||||
| <span class="n">L</span> <span class="o">=</span> <span class="n">L</span><span class="o">.</span><span class="n">create</span><span class="p">()</span> | ||||
| <span class="n">L0</span> <span class="o">=</span> <span class="n">L</span><span class="o">.</span><span class="n">L0</span> | ||||
| <span class="n">L1</span> <span class="o">=</span> <span class="n">L</span><span class="o">.</span><span class="n">L1</span> | ||||
| <span class="n">L2</span> <span class="o">=</span> <span class="n">L</span><span class="o">.</span><span class="n">L2</span> | ||||
| 
 | ||||
| 
 | ||||
| <span class="n">y0</span> <span class="o">=</span> <span class="n">Int</span><span class="p">(</span><span class="s">'y0'</span><span class="p">)</span> | ||||
| <span class="n">y1</span> <span class="o">=</span> <span class="n">Int</span><span class="p">(</span><span class="s">'y1'</span><span class="p">)</span> | ||||
| <span class="n">l</span>  <span class="o">=</span> <span class="n">Const</span><span class="p">(</span><span class="s">'l'</span><span class="p">,</span> <span class="n">L</span><span class="p">)</span> | ||||
| <span class="n">m</span>  <span class="o">=</span> <span class="n">Const</span><span class="p">(</span><span class="s">'m'</span><span class="p">,</span> <span class="n">L</span><span class="p">)</span> | ||||
| 
 | ||||
| 
 | ||||
| <span class="n">t1</span> <span class="o">=</span> <span class="p">{</span> <span class="s">"guard"</span> <span class="p">:</span> <span class="n">l</span> <span class="o">==</span> <span class="n">L0</span><span class="p">,</span> | ||||
|        <span class="s">"effect"</span> <span class="p">:</span> <span class="p">[</span> <span class="n">L1</span><span class="p">,</span> <span class="n">y1</span> <span class="o">+</span> <span class="mi">1</span><span class="p">,</span> <span class="n">m</span><span class="p">,</span> <span class="n">y1</span> <span class="p">]</span> <span class="p">}</span> | ||||
| <span class="n">t2</span> <span class="o">=</span> <span class="p">{</span> <span class="s">"guard"</span> <span class="p">:</span> <span class="n">And</span><span class="p">(</span><span class="n">l</span> <span class="o">==</span> <span class="n">L1</span><span class="p">,</span> <span class="n">Or</span><span class="p">([</span><span class="n">y0</span> <span class="o"><=</span> <span class="n">y1</span><span class="p">,</span> <span class="n">y1</span> <span class="o">==</span> <span class="mi">0</span><span class="p">])),</span> | ||||
|        <span class="s">"effect"</span> <span class="p">:</span> <span class="p">[</span> <span class="n">L2</span><span class="p">,</span> <span class="n">y0</span><span class="p">,</span>     <span class="n">m</span><span class="p">,</span> <span class="n">y1</span> <span class="p">]</span> <span class="p">}</span> | ||||
| <span class="n">t3</span> <span class="o">=</span> <span class="p">{</span> <span class="s">"guard"</span> <span class="p">:</span> <span class="n">l</span> <span class="o">==</span> <span class="n">L2</span><span class="p">,</span> | ||||
|        <span class="s">"effect"</span> <span class="p">:</span> <span class="p">[</span> <span class="n">L0</span><span class="p">,</span> <span class="n">IntVal</span><span class="p">(</span><span class="mi">0</span><span class="p">),</span> <span class="n">m</span><span class="p">,</span> <span class="n">y1</span> <span class="p">]}</span> | ||||
| <span class="n">s1</span> <span class="o">=</span> <span class="p">{</span> <span class="s">"guard"</span> <span class="p">:</span> <span class="n">m</span> <span class="o">==</span> <span class="n">L0</span><span class="p">,</span> | ||||
|        <span class="s">"effect"</span> <span class="p">:</span> <span class="p">[</span> <span class="n">l</span><span class="p">,</span>  <span class="n">y0</span><span class="p">,</span> <span class="n">L1</span><span class="p">,</span> <span class="n">y0</span> <span class="o">+</span> <span class="mi">1</span> <span class="p">]</span> <span class="p">}</span> | ||||
| <span class="n">s2</span> <span class="o">=</span> <span class="p">{</span> <span class="s">"guard"</span> <span class="p">:</span> <span class="n">And</span><span class="p">(</span><span class="n">m</span> <span class="o">==</span> <span class="n">L1</span><span class="p">,</span> <span class="n">Or</span><span class="p">([</span><span class="n">y1</span> <span class="o"><=</span> <span class="n">y0</span><span class="p">,</span> <span class="n">y0</span> <span class="o">==</span> <span class="mi">0</span><span class="p">])),</span> | ||||
|        <span class="s">"effect"</span> <span class="p">:</span> <span class="p">[</span> <span class="n">l</span><span class="p">,</span>  <span class="n">y0</span><span class="p">,</span> <span class="n">L2</span><span class="p">,</span> <span class="n">y1</span> <span class="p">]</span> <span class="p">}</span> | ||||
| <span class="n">s3</span> <span class="o">=</span> <span class="p">{</span> <span class="s">"guard"</span> <span class="p">:</span> <span class="n">m</span> <span class="o">==</span> <span class="n">L2</span><span class="p">,</span> | ||||
|        <span class="s">"effect"</span> <span class="p">:</span> <span class="p">[</span> <span class="n">l</span><span class="p">,</span>  <span class="n">y0</span><span class="p">,</span> <span class="n">L0</span><span class="p">,</span> <span class="n">IntVal</span><span class="p">(</span><span class="mi">0</span><span class="p">)</span> <span class="p">]}</span> | ||||
| 
 | ||||
| 
 | ||||
| <span class="n">ptr</span> <span class="o">=</span> <span class="n">TransitionSystem</span><span class="p">(</span> <span class="n">And</span><span class="p">(</span><span class="n">l</span> <span class="o">==</span> <span class="n">L0</span><span class="p">,</span> <span class="n">y0</span> <span class="o">==</span> <span class="mi">0</span><span class="p">,</span> <span class="n">m</span> <span class="o">==</span> <span class="n">L0</span><span class="p">,</span> <span class="n">y1</span> <span class="o">==</span> <span class="mi">0</span><span class="p">),</span> | ||||
| 			<span class="p">[</span><span class="n">t1</span><span class="p">,</span> <span class="n">t2</span><span class="p">,</span> <span class="n">t3</span><span class="p">,</span> <span class="n">s1</span><span class="p">,</span> <span class="n">s2</span><span class="p">,</span> <span class="n">s3</span><span class="p">],</span> | ||||
| 			<span class="p">[</span><span class="n">l</span><span class="p">,</span> <span class="n">y0</span><span class="p">,</span> <span class="n">m</span><span class="p">,</span> <span class="n">y1</span><span class="p">])</span> | ||||
| 
 | ||||
| <span class="n">ptr</span><span class="o">.</span><span class="n">query</span><span class="p">(</span><span class="n">And</span><span class="p">([</span><span class="n">l</span> <span class="o">==</span> <span class="n">L2</span><span class="p">,</span> <span class="n">m</span> <span class="o">==</span> <span class="n">L2</span> <span class="p">]))</span> | ||||
| </pre></div> | ||||
| </body></html></example> | ||||
| The rather verbose (and in no way minimal) inductive invariants are produced as answers. | ||||
| 
 | ||||
| <h3>Functional Programs</h3> | ||||
| We can also verify some properties of functional programs using Z3's  | ||||
| generalized PDR. Let us here consider an example from  | ||||
| <a href="http://www.kb.is.s.u-tokyo.ac.jp/~uhiro/"> | ||||
| <em>Predicate Abstraction and CEGAR for Higher-Order Model  | ||||
| Checking, Kobayashi et.al. PLDI 2011</em></a>. | ||||
| We encode functional programs by taking a suitable operational | ||||
| semantics and encoding an evaluator that is specialized to | ||||
| the program being verified (we don't encode a general purpose | ||||
| evaluator, you should partial evaluate it to help verification). | ||||
| We use algebraic data-types to encode the current closure that is | ||||
| being evaluated. | ||||
| 
 | ||||
| <example pref="fixedpoint.10"><html><body> | ||||
| <div class="highlight"><pre><span class="c"># let max max2 x y z = max2 (max2 x y) z</span> | ||||
| <span class="c"># let f x y = if x > y then x else y</span> | ||||
| <span class="c"># assert (f (max f x y z) x) = (max f x y z)</span> | ||||
| 
 | ||||
| 
 | ||||
| <span class="n">Expr</span> <span class="o">=</span> <span class="n">Datatype</span><span class="p">(</span><span class="s">'Expr'</span><span class="p">)</span> | ||||
| <span class="n">Expr</span><span class="o">.</span><span class="n">declare</span><span class="p">(</span><span class="s">'Max'</span><span class="p">)</span> | ||||
| <span class="n">Expr</span><span class="o">.</span><span class="n">declare</span><span class="p">(</span><span class="s">'f'</span><span class="p">)</span> | ||||
| <span class="n">Expr</span><span class="o">.</span><span class="n">declare</span><span class="p">(</span><span class="s">'I'</span><span class="p">,</span> <span class="p">(</span><span class="s">'i'</span><span class="p">,</span> <span class="n">IntSort</span><span class="p">()))</span> | ||||
| <span class="n">Expr</span><span class="o">.</span><span class="n">declare</span><span class="p">(</span><span class="s">'App'</span><span class="p">,</span> <span class="p">(</span><span class="s">'fn'</span><span class="p">,</span><span class="n">Expr</span><span class="p">),(</span><span class="s">'arg'</span><span class="p">,</span><span class="n">Expr</span><span class="p">))</span> | ||||
| <span class="n">Expr</span> <span class="o">=</span> <span class="n">Expr</span><span class="o">.</span><span class="n">create</span><span class="p">()</span> | ||||
| <span class="n">Max</span>  <span class="o">=</span> <span class="n">Expr</span><span class="o">.</span><span class="n">Max</span> | ||||
| <span class="n">I</span>    <span class="o">=</span> <span class="n">Expr</span><span class="o">.</span><span class="n">I</span> | ||||
| <span class="n">App</span>  <span class="o">=</span> <span class="n">Expr</span><span class="o">.</span><span class="n">App</span> | ||||
| <span class="n">f</span>    <span class="o">=</span> <span class="n">Expr</span><span class="o">.</span><span class="n">f</span> | ||||
| <span class="n">Eval</span> <span class="o">=</span> <span class="n">Function</span><span class="p">(</span><span class="s">'Eval'</span><span class="p">,</span><span class="n">Expr</span><span class="p">,</span><span class="n">Expr</span><span class="p">,</span><span class="n">Expr</span><span class="p">,</span><span class="n">BoolSort</span><span class="p">())</span> | ||||
| 
 | ||||
| <span class="n">x</span>   <span class="o">=</span> <span class="n">Const</span><span class="p">(</span><span class="s">'x'</span><span class="p">,</span><span class="n">Expr</span><span class="p">)</span> | ||||
| <span class="n">y</span>   <span class="o">=</span> <span class="n">Const</span><span class="p">(</span><span class="s">'y'</span><span class="p">,</span><span class="n">Expr</span><span class="p">)</span> | ||||
| <span class="n">z</span>   <span class="o">=</span> <span class="n">Const</span><span class="p">(</span><span class="s">'z'</span><span class="p">,</span><span class="n">Expr</span><span class="p">)</span> | ||||
| <span class="n">r1</span>  <span class="o">=</span> <span class="n">Const</span><span class="p">(</span><span class="s">'r1'</span><span class="p">,</span><span class="n">Expr</span><span class="p">)</span> | ||||
| <span class="n">r2</span>  <span class="o">=</span> <span class="n">Const</span><span class="p">(</span><span class="s">'r2'</span><span class="p">,</span><span class="n">Expr</span><span class="p">)</span> | ||||
| <span class="nb">max</span> <span class="o">=</span> <span class="n">Const</span><span class="p">(</span><span class="s">'max'</span><span class="p">,</span><span class="n">Expr</span><span class="p">)</span> | ||||
| <span class="n">xi</span>  <span class="o">=</span> <span class="n">Const</span><span class="p">(</span><span class="s">'xi'</span><span class="p">,</span><span class="n">IntSort</span><span class="p">())</span> | ||||
| <span class="n">yi</span>  <span class="o">=</span> <span class="n">Const</span><span class="p">(</span><span class="s">'yi'</span><span class="p">,</span><span class="n">IntSort</span><span class="p">())</span> | ||||
| 
 | ||||
| <span class="n">fp</span> <span class="o">=</span> <span class="n">Fixedpoint</span><span class="p">()</span> | ||||
| <span class="n">fp</span><span class="o">.</span><span class="n">register_relation</span><span class="p">(</span><span class="n">Eval</span><span class="p">)</span> | ||||
| <span class="n">fp</span><span class="o">.</span><span class="n">declare_var</span><span class="p">(</span><span class="n">x</span><span class="p">,</span><span class="n">y</span><span class="p">,</span><span class="n">z</span><span class="p">,</span><span class="n">r1</span><span class="p">,</span><span class="n">r2</span><span class="p">,</span><span class="nb">max</span><span class="p">,</span><span class="n">xi</span><span class="p">,</span><span class="n">yi</span><span class="p">)</span> | ||||
| 
 | ||||
| <span class="c"># Max max x y z = max (max x y) z</span> | ||||
| <span class="n">fp</span><span class="o">.</span><span class="n">rule</span><span class="p">(</span><span class="n">Eval</span><span class="p">(</span><span class="n">App</span><span class="p">(</span><span class="n">App</span><span class="p">(</span><span class="n">App</span><span class="p">(</span><span class="n">Max</span><span class="p">,</span><span class="nb">max</span><span class="p">),</span><span class="n">x</span><span class="p">),</span><span class="n">y</span><span class="p">),</span> <span class="n">z</span><span class="p">,</span> <span class="n">r2</span><span class="p">),</span> | ||||
| 	<span class="p">[</span><span class="n">Eval</span><span class="p">(</span><span class="n">App</span><span class="p">(</span><span class="nb">max</span><span class="p">,</span><span class="n">x</span><span class="p">),</span><span class="n">y</span><span class="p">,</span><span class="n">r1</span><span class="p">),</span> | ||||
| 	 <span class="n">Eval</span><span class="p">(</span><span class="n">App</span><span class="p">(</span><span class="nb">max</span><span class="p">,</span><span class="n">r1</span><span class="p">),</span><span class="n">z</span><span class="p">,</span><span class="n">r2</span><span class="p">)])</span> | ||||
| 
 | ||||
| <span class="c"># f x y = x if x >= y</span> | ||||
| <span class="c"># f x y = y if x < y</span> | ||||
| <span class="n">fp</span><span class="o">.</span><span class="n">rule</span><span class="p">(</span><span class="n">Eval</span><span class="p">(</span><span class="n">App</span><span class="p">(</span><span class="n">f</span><span class="p">,</span><span class="n">I</span><span class="p">(</span><span class="n">xi</span><span class="p">)),</span><span class="n">I</span><span class="p">(</span><span class="n">yi</span><span class="p">),</span><span class="n">I</span><span class="p">(</span><span class="n">xi</span><span class="p">)),</span><span class="n">xi</span> <span class="o">>=</span> <span class="n">yi</span><span class="p">)</span> | ||||
| <span class="n">fp</span><span class="o">.</span><span class="n">rule</span><span class="p">(</span><span class="n">Eval</span><span class="p">(</span><span class="n">App</span><span class="p">(</span><span class="n">f</span><span class="p">,</span><span class="n">I</span><span class="p">(</span><span class="n">xi</span><span class="p">)),</span><span class="n">I</span><span class="p">(</span><span class="n">yi</span><span class="p">),</span><span class="n">I</span><span class="p">(</span><span class="n">yi</span><span class="p">)),</span><span class="n">xi</span> <span class="o"><</span> <span class="n">yi</span><span class="p">)</span> | ||||
| 
 | ||||
| <span class="k">print</span> <span class="n">fp</span><span class="o">.</span><span class="n">query</span><span class="p">(</span><span class="n">And</span><span class="p">(</span><span class="n">Eval</span><span class="p">(</span><span class="n">App</span><span class="p">(</span><span class="n">App</span><span class="p">(</span><span class="n">App</span><span class="p">(</span><span class="n">Max</span><span class="p">,</span><span class="n">f</span><span class="p">),</span><span class="n">x</span><span class="p">),</span><span class="n">y</span><span class="p">),</span><span class="n">z</span><span class="p">,</span><span class="n">r1</span><span class="p">),</span> | ||||
| 		   <span class="n">Eval</span><span class="p">(</span><span class="n">App</span><span class="p">(</span><span class="n">f</span><span class="p">,</span><span class="n">x</span><span class="p">),</span><span class="n">r1</span><span class="p">,</span><span class="n">r2</span><span class="p">),</span> | ||||
| 		   <span class="n">r1</span> <span class="o">!=</span> <span class="n">r2</span><span class="p">))</span> | ||||
| 
 | ||||
| <span class="k">print</span> <span class="n">fp</span><span class="o">.</span><span class="n">get_answer</span><span class="p">()</span> | ||||
| </pre></div> | ||||
| </body></html></example> | ||||
| 
 | ||||
| 
 | ||||
| </body> | ||||
| </html> | ||||
							
								
								
									
										1101
									
								
								examples/python/tutorial/html/guide-examples.htm
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										1101
									
								
								examples/python/tutorial/html/guide-examples.htm
									
										
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load diff
											
										
									
								
							
							
								
								
									
										1
									
								
								examples/python/tutorial/html/index.html
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								examples/python/tutorial/html/index.html
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1 @@ | |||
| <html><body><script>location.replace("guide-examples.htm")</script></body></html> | ||||
							
								
								
									
										350
									
								
								examples/python/tutorial/html/strategies-examples.htm
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										350
									
								
								examples/python/tutorial/html/strategies-examples.htm
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,350 @@ | |||
| <html> | ||||
| <head> | ||||
| <title>Z3Py Strategies</title> | ||||
| <link rel="StyleSheet" href="style.css" type="text/css"> | ||||
| </head> | ||||
| <body> | ||||
| 
 | ||||
| <h1>Strategies</h1> | ||||
| 
 | ||||
| <p> | ||||
| High-performance solvers, such as Z3, contain many tightly integrated, handcrafted heuristic  | ||||
| combinations of algorithmic proof methods. While these heuristic | ||||
| combinations tend to be highly tuned for known classes of problems,  | ||||
| they may easily perform very badly on new classes of problems. | ||||
| This issue is becoming increasingly pressing | ||||
| as solvers begin to gain the attention of practitioners in diverse areas of science and engineering.  | ||||
| In many cases, changes to the solver heuristics can make a | ||||
| tremendous difference. | ||||
| </p> | ||||
| 
 | ||||
| <p> | ||||
| In this tutorial we show how to create custom strategies using the basic building blocks | ||||
| available in Z3. Z3Py and Z3 4.0 implement the ideas proposed in this <a target="_blank" href="http://research.microsoft.com/en-us/um/people/leonardo/strategy.pdf">article</a>. | ||||
| </p> | ||||
| 
 | ||||
| <p> | ||||
| Please send feedback, comments and/or corrections to <a href="mailto:leonardo@microsoft.com">leonardo@microsoft.com</a>. | ||||
| Your comments are very valuable. | ||||
| </p> | ||||
| 
 | ||||
| <h2>Introduction</h2> | ||||
| 
 | ||||
| <p> | ||||
| Z3 implements  a methodology for orchestrating reasoning | ||||
| engines where "big" symbolic reasoning steps are represented as | ||||
| functions known as <b>tactics</b>, and tactics are composed using | ||||
| combinators known as <b>tacticals</b>. Tactics process sets of  | ||||
| formulas called <b>Goals</b>. | ||||
| </p> | ||||
| 
 | ||||
| <p> | ||||
| When a tactic is applied to some goal <tt>G</tt>, four different outcomes  | ||||
| are possible. The tactic succeeds in showing <tt>G</tt> to be satisfiable (i.e., feasible); | ||||
| succeeds in showing <tt>G</tt> to be unsatisfiable (i.e., infeasible); produces a sequence of subgoals; or fails. | ||||
| When reducing a goal <tt>G</tt> to a sequence of subgoals <tt>G1</tt>, ..., | ||||
| <tt>Gn</tt>, we face the problem of model conversion. | ||||
| A <b>model converter</b> construct a model for <tt>G</tt> | ||||
| using a model for some subgoal <tt>Gi</tt>.  | ||||
| </p> | ||||
| 
 | ||||
| <p>In the following example, we create a goal <tt>g</tt> consisting of three formulas, and a tactic <tt>t</tt> | ||||
| composed of two built-in tactics: <tt>simplify</tt> and <tt>solve-eqs</tt>. The tactic <tt>simplify</tt> | ||||
| apply transformations equivalent to the ones found in the command <tt>simplify</tt>. The tactic <tt>solver-eqs</tt> | ||||
| eliminate variables using Gaussian elimination. Actually, <tt>solve-eqs</tt> is not restricted only to linear arithmetic. | ||||
| It can also eliminate arbitrary variables. Then, combinator <tt>Then</tt> applies <tt>simplify</tt> to the input goal | ||||
| and <tt>solve-eqs</tt> to each subgoal produced by <tt>simplify</tt>. In this example, only one subgoal is produced. | ||||
| </p> | ||||
| 
 | ||||
| <example pref="tactic.1"><html><body> | ||||
| <div class="highlight"><pre><span class="n">x</span><span class="p">,</span> <span class="n">y</span> <span class="o">=</span> <span class="n">Reals</span><span class="p">(</span><span class="s">'x y'</span><span class="p">)</span> | ||||
| <span class="n">g</span>  <span class="o">=</span> <span class="n">Goal</span><span class="p">()</span> | ||||
| <span class="n">g</span><span class="o">.</span><span class="n">add</span><span class="p">(</span><span class="n">x</span> <span class="o">></span> <span class="mi">0</span><span class="p">,</span> <span class="n">y</span> <span class="o">></span> <span class="mi">0</span><span class="p">,</span> <span class="n">x</span> <span class="o">==</span> <span class="n">y</span> <span class="o">+</span> <span class="mi">2</span><span class="p">)</span> | ||||
| <span class="k">print</span> <span class="n">g</span> | ||||
| 
 | ||||
| <span class="n">t1</span> <span class="o">=</span> <span class="n">Tactic</span><span class="p">(</span><span class="s">'simplify'</span><span class="p">)</span> | ||||
| <span class="n">t2</span> <span class="o">=</span> <span class="n">Tactic</span><span class="p">(</span><span class="s">'solve-eqs'</span><span class="p">)</span> | ||||
| <span class="n">t</span>  <span class="o">=</span> <span class="n">Then</span><span class="p">(</span><span class="n">t1</span><span class="p">,</span> <span class="n">t2</span><span class="p">)</span> | ||||
| <span class="k">print</span> <span class="n">t</span><span class="p">(</span><span class="n">g</span><span class="p">)</span> | ||||
| </pre></div> | ||||
| </body></html></example> | ||||
| 
 | ||||
| <p>In the example above, variable <tt>x</tt> is eliminated, and is not present the resultant goal. | ||||
| </p> | ||||
| 
 | ||||
| <p>In Z3, we say a <b>clause</b> is any constraint of the form <tt>Or(f_1, ..., f_n)</tt>. | ||||
| The tactic <tt>split-clause</tt> will select a clause <tt>Or(f_1, ..., f_n)</tt> in the input goal, and split it  | ||||
| <tt>n</tt> subgoals. One for each subformula <tt>f_i</tt>. | ||||
| </p> | ||||
| 
 | ||||
| <example pref="tactic.2"><html><body> | ||||
| <div class="highlight"><pre><span class="n">x</span><span class="p">,</span> <span class="n">y</span> <span class="o">=</span> <span class="n">Reals</span><span class="p">(</span><span class="s">'x y'</span><span class="p">)</span> | ||||
| <span class="n">g</span>  <span class="o">=</span> <span class="n">Goal</span><span class="p">()</span> | ||||
| <span class="n">g</span><span class="o">.</span><span class="n">add</span><span class="p">(</span><span class="n">Or</span><span class="p">(</span><span class="n">x</span> <span class="o"><</span> <span class="mi">0</span><span class="p">,</span> <span class="n">x</span> <span class="o">></span> <span class="mi">0</span><span class="p">),</span> <span class="n">x</span> <span class="o">==</span> <span class="n">y</span> <span class="o">+</span> <span class="mi">1</span><span class="p">,</span> <span class="n">y</span> <span class="o"><</span> <span class="mi">0</span><span class="p">)</span> | ||||
| 
 | ||||
| <span class="n">t</span> <span class="o">=</span> <span class="n">Tactic</span><span class="p">(</span><span class="s">'split-clause'</span><span class="p">)</span> | ||||
| <span class="n">r</span> <span class="o">=</span> <span class="n">t</span><span class="p">(</span><span class="n">g</span><span class="p">)</span> | ||||
| <span class="k">for</span> <span class="n">g</span> <span class="ow">in</span> <span class="n">r</span><span class="p">:</span>  | ||||
|     <span class="k">print</span> <span class="n">g</span> | ||||
| </pre></div> | ||||
| </body></html></example> | ||||
| 
 | ||||
| <h2>Tactics</h2> | ||||
| 
 | ||||
| <p>Z3 comes equipped with many built-in tactics. | ||||
| The command <tt>describe_tactics()</tt> provides a short description of all built-in tactics. | ||||
| </p> | ||||
| 
 | ||||
| <example pref="tactic.3"><html><body> | ||||
| <div class="highlight"><pre><span class="n">describe_tactics</span><span class="p">()</span> | ||||
| </pre></div> | ||||
| </body></html></example> | ||||
| 
 | ||||
| <p>Z3Py comes equipped with the following tactic combinators (aka tacticals): | ||||
| </p> | ||||
| 
 | ||||
| <ul> | ||||
| <li> <tt>Then(t, s)</tt> | ||||
| applies <tt>t</tt> to the input goal and <tt>s</tt> | ||||
|   to every subgoal produced by <tt>t</tt>. | ||||
| </li> | ||||
| <li> <tt>OrElse(t, s)</tt> | ||||
| first applies <tt>t</tt> to the given goal, | ||||
| if it fails then returns the result of <tt>s</tt> applied to the given goal. | ||||
| </li> | ||||
| <li> <tt>Repeat(t)</tt> Keep applying the given tactic until no subgoal is modified by it. | ||||
| </li> | ||||
| <li> <tt>Repeat(t, n)</tt> Keep applying the given tactic until no subgoal is modified by it, or | ||||
| the number of iterations is greater than <tt>n</tt>. | ||||
| </li> | ||||
| <li> <tt>TryFor(t, ms)</tt> Apply tactic <tt>t</tt> to the input goal, if it does not return in | ||||
| <tt>ms</tt> millisenconds, it fails. | ||||
| </li> | ||||
| <li> <tt>With(t, params)</tt> Apply the given tactic using the given parameters. | ||||
| </li> | ||||
| </ul> | ||||
| 
 | ||||
| <p>The following example demonstrate how to use these combinators.</p> | ||||
| 
 | ||||
| <example pref="tactic.4"><html><body> | ||||
| <div class="highlight"><pre><span class="n">x</span><span class="p">,</span> <span class="n">y</span><span class="p">,</span> <span class="n">z</span> <span class="o">=</span> <span class="n">Reals</span><span class="p">(</span><span class="s">'x y z'</span><span class="p">)</span> | ||||
| <span class="n">g</span> <span class="o">=</span> <span class="n">Goal</span><span class="p">()</span> | ||||
| <span class="n">g</span><span class="o">.</span><span class="n">add</span><span class="p">(</span><span class="n">Or</span><span class="p">(</span><span class="n">x</span> <span class="o">==</span> <span class="mi">0</span><span class="p">,</span> <span class="n">x</span> <span class="o">==</span> <span class="mi">1</span><span class="p">),</span>  | ||||
|       <span class="n">Or</span><span class="p">(</span><span class="n">y</span> <span class="o">==</span> <span class="mi">0</span><span class="p">,</span> <span class="n">y</span> <span class="o">==</span> <span class="mi">1</span><span class="p">),</span>  | ||||
|       <span class="n">Or</span><span class="p">(</span><span class="n">z</span> <span class="o">==</span> <span class="mi">0</span><span class="p">,</span> <span class="n">z</span> <span class="o">==</span> <span class="mi">1</span><span class="p">),</span> | ||||
|       <span class="n">x</span> <span class="o">+</span> <span class="n">y</span> <span class="o">+</span> <span class="n">z</span> <span class="o">></span> <span class="mi">2</span><span class="p">)</span> | ||||
| 
 | ||||
| <span class="c"># Split all clauses"</span> | ||||
| <span class="n">split_all</span> <span class="o">=</span> <span class="n">Repeat</span><span class="p">(</span><span class="n">OrElse</span><span class="p">(</span><span class="n">Tactic</span><span class="p">(</span><span class="s">'split-clause'</span><span class="p">),</span> | ||||
|                           <span class="n">Tactic</span><span class="p">(</span><span class="s">'skip'</span><span class="p">)))</span> | ||||
| <span class="k">print</span> <span class="n">split_all</span><span class="p">(</span><span class="n">g</span><span class="p">)</span> | ||||
| 
 | ||||
| <span class="n">split_at_most_2</span> <span class="o">=</span> <span class="n">Repeat</span><span class="p">(</span><span class="n">OrElse</span><span class="p">(</span><span class="n">Tactic</span><span class="p">(</span><span class="s">'split-clause'</span><span class="p">),</span> | ||||
|                           <span class="n">Tactic</span><span class="p">(</span><span class="s">'skip'</span><span class="p">)),</span> | ||||
|                          <span class="mi">1</span><span class="p">)</span> | ||||
| <span class="k">print</span> <span class="n">split_at_most_2</span><span class="p">(</span><span class="n">g</span><span class="p">)</span> | ||||
| 
 | ||||
| <span class="c"># Split all clauses and solve equations</span> | ||||
| <span class="n">split_solve</span> <span class="o">=</span> <span class="n">Then</span><span class="p">(</span><span class="n">Repeat</span><span class="p">(</span><span class="n">OrElse</span><span class="p">(</span><span class="n">Tactic</span><span class="p">(</span><span class="s">'split-clause'</span><span class="p">),</span> | ||||
|                                  <span class="n">Tactic</span><span class="p">(</span><span class="s">'skip'</span><span class="p">))),</span> | ||||
|                    <span class="n">Tactic</span><span class="p">(</span><span class="s">'solve-eqs'</span><span class="p">))</span> | ||||
| 
 | ||||
| <span class="k">print</span> <span class="n">split_solve</span><span class="p">(</span><span class="n">g</span><span class="p">)</span> | ||||
| </pre></div> | ||||
| </body></html></example> | ||||
| 
 | ||||
| <p>In the tactic <tt>split_solver</tt>, the tactic <tt>solve-eqs</tt> discharges all but one goal. | ||||
| Note that, this tactic generates one goal: the empty goal which is trivially satisfiable (i.e., feasible) </p> | ||||
| 
 | ||||
| <p>The list of subgoals can be easily traversed using the Python <tt>for</tt> statement.</p> | ||||
| 
 | ||||
| <example pref="tactic.5"><html><body> | ||||
| <div class="highlight"><pre><span class="n">x</span><span class="p">,</span> <span class="n">y</span><span class="p">,</span> <span class="n">z</span> <span class="o">=</span> <span class="n">Reals</span><span class="p">(</span><span class="s">'x y z'</span><span class="p">)</span> | ||||
| <span class="n">g</span> <span class="o">=</span> <span class="n">Goal</span><span class="p">()</span> | ||||
| <span class="n">g</span><span class="o">.</span><span class="n">add</span><span class="p">(</span><span class="n">Or</span><span class="p">(</span><span class="n">x</span> <span class="o">==</span> <span class="mi">0</span><span class="p">,</span> <span class="n">x</span> <span class="o">==</span> <span class="mi">1</span><span class="p">),</span>  | ||||
|       <span class="n">Or</span><span class="p">(</span><span class="n">y</span> <span class="o">==</span> <span class="mi">0</span><span class="p">,</span> <span class="n">y</span> <span class="o">==</span> <span class="mi">1</span><span class="p">),</span>  | ||||
|       <span class="n">Or</span><span class="p">(</span><span class="n">z</span> <span class="o">==</span> <span class="mi">0</span><span class="p">,</span> <span class="n">z</span> <span class="o">==</span> <span class="mi">1</span><span class="p">),</span> | ||||
|       <span class="n">x</span> <span class="o">+</span> <span class="n">y</span> <span class="o">+</span> <span class="n">z</span> <span class="o">></span> <span class="mi">2</span><span class="p">)</span> | ||||
| 
 | ||||
| <span class="c"># Split all clauses"</span> | ||||
| <span class="n">split_all</span> <span class="o">=</span> <span class="n">Repeat</span><span class="p">(</span><span class="n">OrElse</span><span class="p">(</span><span class="n">Tactic</span><span class="p">(</span><span class="s">'split-clause'</span><span class="p">),</span> | ||||
|                           <span class="n">Tactic</span><span class="p">(</span><span class="s">'skip'</span><span class="p">)))</span> | ||||
| <span class="k">for</span> <span class="n">s</span> <span class="ow">in</span> <span class="n">split_all</span><span class="p">(</span><span class="n">g</span><span class="p">):</span> | ||||
|     <span class="k">print</span> <span class="n">s</span> | ||||
| </pre></div> | ||||
| </body></html></example> | ||||
| 
 | ||||
| <p>A tactic can be converted into a solver object using the method <tt>solver()</tt>. | ||||
| If the tactic produces the empty goal, then the associated solver returns <tt>sat</tt>. | ||||
| If the tactic produces a single goal containing <tt>False</tt>, then the solver returns <tt>unsat</tt>. | ||||
| Otherwise, it returns <tt>unknown</tt>. | ||||
| </p> | ||||
| 
 | ||||
| <example pref="tactic.6"><html><body> | ||||
| <div class="highlight"><pre><span class="n">bv_solver</span> <span class="o">=</span> <span class="n">Then</span><span class="p">(</span><span class="s">'simplify'</span><span class="p">,</span>  | ||||
|                  <span class="s">'solve-eqs'</span><span class="p">,</span>  | ||||
|                  <span class="s">'bit-blast'</span><span class="p">,</span>  | ||||
|                  <span class="s">'sat'</span><span class="p">)</span><span class="o">.</span><span class="n">solver</span><span class="p">()</span> | ||||
| 
 | ||||
| <span class="n">x</span><span class="p">,</span> <span class="n">y</span> <span class="o">=</span> <span class="n">BitVecs</span><span class="p">(</span><span class="s">'x y'</span><span class="p">,</span> <span class="mi">16</span><span class="p">)</span> | ||||
| <span class="n">solve_using</span><span class="p">(</span><span class="n">bv_solver</span><span class="p">,</span> <span class="n">x</span> <span class="o">|</span> <span class="n">y</span> <span class="o">==</span> <span class="mi">13</span><span class="p">,</span> <span class="n">x</span> <span class="o">></span> <span class="n">y</span><span class="p">)</span> | ||||
| </pre></div> | ||||
| </body></html></example> | ||||
| 
 | ||||
| <p>In the example above, the tactic <tt>bv_solver</tt> implements a basic bit-vector solver using equation solving, | ||||
| bit-blasting, and a propositional SAT solver. Note that, the command <tt>Tactic</tt> is suppressed. | ||||
| All Z3Py combinators automatically invoke <tt>Tactic</tt> command if the argument is a string. | ||||
| Finally, the command <tt>solve_using</tt> is a variant of the <tt>solve</tt> command where the first | ||||
| argument specifies the solver to be used. | ||||
| </p> | ||||
| 
 | ||||
| <p>In the following example, we use the solver API directly instead of the command <tt>solve_using</tt>. | ||||
| We use the combinator <tt>With</tt> to configure our little solver. We also include the tactic <tt>aig</tt> | ||||
| which tries to compress Boolean formulas using And-Inverted Graphs. | ||||
| </p> | ||||
| 
 | ||||
| <example pref="tactic.7"><html><body> | ||||
| <div class="highlight"><pre><span class="n">bv_solver</span> <span class="o">=</span> <span class="n">Then</span><span class="p">(</span><span class="n">With</span><span class="p">(</span><span class="s">'simplify'</span><span class="p">,</span> <span class="n">mul2concat</span><span class="o">=</span><span class="bp">True</span><span class="p">),</span> | ||||
|                  <span class="s">'solve-eqs'</span><span class="p">,</span>  | ||||
|                  <span class="s">'bit-blast'</span><span class="p">,</span>  | ||||
|                  <span class="s">'aig'</span><span class="p">,</span> | ||||
|                  <span class="s">'sat'</span><span class="p">)</span><span class="o">.</span><span class="n">solver</span><span class="p">()</span> | ||||
| <span class="n">x</span><span class="p">,</span> <span class="n">y</span> <span class="o">=</span> <span class="n">BitVecs</span><span class="p">(</span><span class="s">'x y'</span><span class="p">,</span> <span class="mi">16</span><span class="p">)</span> | ||||
| <span class="n">bv_solver</span><span class="o">.</span><span class="n">add</span><span class="p">(</span><span class="n">x</span><span class="o">*</span><span class="mi">32</span> <span class="o">+</span> <span class="n">y</span> <span class="o">==</span> <span class="mi">13</span><span class="p">,</span> <span class="n">x</span> <span class="o">&</span> <span class="n">y</span> <span class="o"><</span> <span class="mi">10</span><span class="p">,</span> <span class="n">y</span> <span class="o">></span> <span class="o">-</span><span class="mi">100</span><span class="p">)</span> | ||||
| <span class="k">print</span> <span class="n">bv_solver</span><span class="o">.</span><span class="n">check</span><span class="p">()</span> | ||||
| <span class="n">m</span> <span class="o">=</span> <span class="n">bv_solver</span><span class="o">.</span><span class="n">model</span><span class="p">()</span> | ||||
| <span class="k">print</span> <span class="n">m</span> | ||||
| <span class="k">print</span> <span class="n">x</span><span class="o">*</span><span class="mi">32</span> <span class="o">+</span> <span class="n">y</span><span class="p">,</span> <span class="s">"=="</span><span class="p">,</span> <span class="n">m</span><span class="o">.</span><span class="n">evaluate</span><span class="p">(</span><span class="n">x</span><span class="o">*</span><span class="mi">32</span> <span class="o">+</span> <span class="n">y</span><span class="p">)</span> | ||||
| <span class="k">print</span> <span class="n">x</span> <span class="o">&</span> <span class="n">y</span><span class="p">,</span> <span class="s">"=="</span><span class="p">,</span> <span class="n">m</span><span class="o">.</span><span class="n">evaluate</span><span class="p">(</span><span class="n">x</span> <span class="o">&</span> <span class="n">y</span><span class="p">)</span> | ||||
| </pre></div> | ||||
| </body></html></example> | ||||
| 
 | ||||
| <p>The tactic <tt>smt</tt> wraps the main solver in Z3 as a tactic.</p> | ||||
| 
 | ||||
| <example pref="tactic.8"><html><body> | ||||
| <div class="highlight"><pre><span class="n">x</span><span class="p">,</span> <span class="n">y</span> <span class="o">=</span> <span class="n">Ints</span><span class="p">(</span><span class="s">'x y'</span><span class="p">)</span> | ||||
| <span class="n">s</span> <span class="o">=</span> <span class="n">Tactic</span><span class="p">(</span><span class="s">'smt'</span><span class="p">)</span><span class="o">.</span><span class="n">solver</span><span class="p">()</span> | ||||
| <span class="n">s</span><span class="o">.</span><span class="n">add</span><span class="p">(</span><span class="n">x</span> <span class="o">></span> <span class="n">y</span> <span class="o">+</span> <span class="mi">1</span><span class="p">)</span> | ||||
| <span class="k">print</span> <span class="n">s</span><span class="o">.</span><span class="n">check</span><span class="p">()</span> | ||||
| <span class="k">print</span> <span class="n">s</span><span class="o">.</span><span class="n">model</span><span class="p">()</span> | ||||
| </pre></div> | ||||
| </body></html></example> | ||||
| 
 | ||||
| <p>Now, we show how to implement a solver for integer arithmetic using SAT. The solver is complete | ||||
| only for problems where every variable has a lower and upper bound. | ||||
| </p> | ||||
| 
 | ||||
| <example pref="tactic.9"><html><body> | ||||
| <div class="highlight"><pre><span class="n">s</span> <span class="o">=</span> <span class="n">Then</span><span class="p">(</span><span class="n">With</span><span class="p">(</span><span class="s">'simplify'</span><span class="p">,</span> <span class="n">arith_lhs</span><span class="o">=</span><span class="bp">True</span><span class="p">,</span> <span class="n">som</span><span class="o">=</span><span class="bp">True</span><span class="p">),</span> | ||||
|          <span class="s">'normalize-bounds'</span><span class="p">,</span> <span class="s">'lia2pb'</span><span class="p">,</span> <span class="s">'pb2bv'</span><span class="p">,</span>  | ||||
|          <span class="s">'bit-blast'</span><span class="p">,</span> <span class="s">'sat'</span><span class="p">)</span><span class="o">.</span><span class="n">solver</span><span class="p">()</span> | ||||
| <span class="n">x</span><span class="p">,</span> <span class="n">y</span><span class="p">,</span> <span class="n">z</span> <span class="o">=</span> <span class="n">Ints</span><span class="p">(</span><span class="s">'x y z'</span><span class="p">)</span> | ||||
| <span class="n">solve_using</span><span class="p">(</span><span class="n">s</span><span class="p">,</span>  | ||||
|             <span class="n">x</span> <span class="o">></span> <span class="mi">0</span><span class="p">,</span> <span class="n">x</span> <span class="o"><</span> <span class="mi">10</span><span class="p">,</span>  | ||||
|             <span class="n">y</span> <span class="o">></span> <span class="mi">0</span><span class="p">,</span> <span class="n">y</span> <span class="o"><</span> <span class="mi">10</span><span class="p">,</span>  | ||||
|             <span class="n">z</span> <span class="o">></span> <span class="mi">0</span><span class="p">,</span> <span class="n">z</span> <span class="o"><</span> <span class="mi">10</span><span class="p">,</span> | ||||
|             <span class="mi">3</span><span class="o">*</span><span class="n">y</span> <span class="o">+</span> <span class="mi">2</span><span class="o">*</span><span class="n">x</span> <span class="o">==</span> <span class="n">z</span><span class="p">)</span> | ||||
| <span class="c"># It fails on the next example (it is unbounded)</span> | ||||
| <span class="n">s</span><span class="o">.</span><span class="n">reset</span><span class="p">()</span> | ||||
| <span class="n">solve_using</span><span class="p">(</span><span class="n">s</span><span class="p">,</span> <span class="mi">3</span><span class="o">*</span><span class="n">y</span> <span class="o">+</span> <span class="mi">2</span><span class="o">*</span><span class="n">x</span> <span class="o">==</span> <span class="n">z</span><span class="p">)</span> | ||||
| </pre></div> | ||||
| </body></html></example> | ||||
| 
 | ||||
| <p> | ||||
| Tactics can be combined with solvers. For example, we can apply a tactic to a goal, produced a set of subgoals,  | ||||
| then select one of the subgoals and solve it using a solver. The next example demonstrates how to do that, and how to | ||||
| use model converters to convert a model for a subgoal into a model for the original goal. | ||||
| </p> | ||||
| 
 | ||||
| <example pref="tactic.10"><html><body> | ||||
| <div class="highlight"><pre><span class="n">t</span> <span class="o">=</span> <span class="n">Then</span><span class="p">(</span><span class="s">'simplify'</span><span class="p">,</span>  | ||||
|          <span class="s">'normalize-bounds'</span><span class="p">,</span>  | ||||
|          <span class="s">'solve-eqs'</span><span class="p">)</span> | ||||
| 
 | ||||
| <span class="n">x</span><span class="p">,</span> <span class="n">y</span><span class="p">,</span> <span class="n">z</span> <span class="o">=</span> <span class="n">Ints</span><span class="p">(</span><span class="s">'x y z'</span><span class="p">)</span> | ||||
| <span class="n">g</span> <span class="o">=</span> <span class="n">Goal</span><span class="p">()</span> | ||||
| <span class="n">g</span><span class="o">.</span><span class="n">add</span><span class="p">(</span><span class="n">x</span> <span class="o">></span> <span class="mi">10</span><span class="p">,</span> <span class="n">y</span> <span class="o">==</span> <span class="n">x</span> <span class="o">+</span> <span class="mi">3</span><span class="p">,</span> <span class="n">z</span> <span class="o">></span> <span class="n">y</span><span class="p">)</span> | ||||
| 
 | ||||
| <span class="n">r</span> <span class="o">=</span> <span class="n">t</span><span class="p">(</span><span class="n">g</span><span class="p">)</span> | ||||
| <span class="c"># r contains only one subgoal</span> | ||||
| <span class="k">print</span> <span class="n">r</span> | ||||
| 
 | ||||
| <span class="n">s</span> <span class="o">=</span> <span class="n">Solver</span><span class="p">()</span> | ||||
| <span class="n">s</span><span class="o">.</span><span class="n">add</span><span class="p">(</span><span class="n">r</span><span class="p">[</span><span class="mi">0</span><span class="p">])</span> | ||||
| <span class="k">print</span> <span class="n">s</span><span class="o">.</span><span class="n">check</span><span class="p">()</span> | ||||
| <span class="c"># Model for the subgoal</span> | ||||
| <span class="k">print</span> <span class="n">s</span><span class="o">.</span><span class="n">model</span><span class="p">()</span> | ||||
| <span class="c"># Model for the original goal</span> | ||||
| <span class="k">print</span> <span class="n">r</span><span class="o">.</span><span class="n">convert_model</span><span class="p">(</span><span class="n">s</span><span class="o">.</span><span class="n">model</span><span class="p">())</span> | ||||
| </pre></div> | ||||
| </body></html></example> | ||||
| 
 | ||||
| <h2>Probes</h2> | ||||
| 
 | ||||
| <p> | ||||
| <b>Probes</b> (aka formula measures) are evaluated over goals. | ||||
| Boolean expressions over them can be built using relational operators and Boolean connectives. | ||||
| The tactic <tt>FailIf(cond)</tt> fails if the given goal does not satisfy the condition <tt>cond</tt>. | ||||
| Many numeric and Boolean measures are available in Z3Py. The command <tt>describe_probes()</tt> provides the list of  | ||||
| all built-in probes. | ||||
| </p> | ||||
| 
 | ||||
| <example pref="probe.1"><html><body> | ||||
| <div class="highlight"><pre><span class="n">describe_probes</span><span class="p">()</span> | ||||
| </pre></div> | ||||
| </body></html></example> | ||||
| 
 | ||||
| <p>In the following example, we build a simple tactic using <tt>FailIf</tt>. It also shows that a probe can be applied directly  | ||||
| to a goal.</p> | ||||
| 
 | ||||
| <example pref="probe.2"><html><body> | ||||
| <div class="highlight"><pre><span class="n">x</span><span class="p">,</span> <span class="n">y</span><span class="p">,</span> <span class="n">z</span> <span class="o">=</span> <span class="n">Reals</span><span class="p">(</span><span class="s">'x y z'</span><span class="p">)</span> | ||||
| <span class="n">g</span> <span class="o">=</span> <span class="n">Goal</span><span class="p">()</span> | ||||
| <span class="n">g</span><span class="o">.</span><span class="n">add</span><span class="p">(</span><span class="n">x</span> <span class="o">+</span> <span class="n">y</span> <span class="o">+</span> <span class="n">z</span> <span class="o">></span> <span class="mi">0</span><span class="p">)</span> | ||||
| 
 | ||||
| <span class="n">p</span> <span class="o">=</span> <span class="n">Probe</span><span class="p">(</span><span class="s">'num-consts'</span><span class="p">)</span> | ||||
| <span class="k">print</span> <span class="s">"num-consts:"</span><span class="p">,</span> <span class="n">p</span><span class="p">(</span><span class="n">g</span><span class="p">)</span> | ||||
| 
 | ||||
| <span class="n">t</span> <span class="o">=</span> <span class="n">FailIf</span><span class="p">(</span><span class="n">p</span> <span class="o">></span> <span class="mi">2</span><span class="p">)</span> | ||||
| <span class="k">try</span><span class="p">:</span> | ||||
|     <span class="n">t</span><span class="p">(</span><span class="n">g</span><span class="p">)</span> | ||||
| <span class="k">except</span> <span class="n">Z3Exception</span><span class="p">:</span> | ||||
|     <span class="k">print</span> <span class="s">"tactic failed"</span> | ||||
| 
 | ||||
| <span class="k">print</span> <span class="s">"trying again..."</span> | ||||
| <span class="n">g</span> <span class="o">=</span> <span class="n">Goal</span><span class="p">()</span> | ||||
| <span class="n">g</span><span class="o">.</span><span class="n">add</span><span class="p">(</span><span class="n">x</span> <span class="o">+</span> <span class="n">y</span> <span class="o">></span> <span class="mi">0</span><span class="p">)</span> | ||||
| <span class="k">print</span> <span class="n">t</span><span class="p">(</span><span class="n">g</span><span class="p">)</span> | ||||
| </pre></div> | ||||
| </body></html></example> | ||||
| 
 | ||||
| <p>Z3Py also provides the combinator (tactical) <tt>If(p, t1, t2)</tt> which is a shorthand for:</p> | ||||
| 
 | ||||
| <pre>OrElse(Then(FailIf(Not(p)), t1), t2)</pre> | ||||
| 
 | ||||
| <p>The combinator <tt>When(p, t)</tt> is a shorthand for:</p> | ||||
| 
 | ||||
| <pre>If(p, t, 'skip')</pre> | ||||
| 
 | ||||
| <p>The tactic <tt>skip</tt> just returns the input goal. | ||||
| The following example demonstrates how to use the <tt>If</tt> combinator.</p> | ||||
| 
 | ||||
| <example pref="probe.3"><html><body> | ||||
| <div class="highlight"><pre><span class="n">x</span><span class="p">,</span> <span class="n">y</span><span class="p">,</span> <span class="n">z</span> <span class="o">=</span> <span class="n">Reals</span><span class="p">(</span><span class="s">'x y z'</span><span class="p">)</span> | ||||
| <span class="n">g</span> <span class="o">=</span> <span class="n">Goal</span><span class="p">()</span> | ||||
| <span class="n">g</span><span class="o">.</span><span class="n">add</span><span class="p">(</span><span class="n">x</span><span class="o">**</span><span class="mi">2</span> <span class="o">-</span> <span class="n">y</span><span class="o">**</span><span class="mi">2</span> <span class="o">>=</span> <span class="mi">0</span><span class="p">)</span> | ||||
| 
 | ||||
| <span class="n">p</span> <span class="o">=</span> <span class="n">Probe</span><span class="p">(</span><span class="s">'num-consts'</span><span class="p">)</span> | ||||
| <span class="n">t</span> <span class="o">=</span> <span class="n">If</span><span class="p">(</span><span class="n">p</span> <span class="o">></span> <span class="mi">2</span><span class="p">,</span> <span class="s">'simplify'</span><span class="p">,</span> <span class="s">'factor'</span><span class="p">)</span> | ||||
| 
 | ||||
| <span class="k">print</span> <span class="n">t</span><span class="p">(</span><span class="n">g</span><span class="p">)</span> | ||||
| 
 | ||||
| <span class="n">g</span> <span class="o">=</span> <span class="n">Goal</span><span class="p">()</span> | ||||
| <span class="n">g</span><span class="o">.</span><span class="n">add</span><span class="p">(</span><span class="n">x</span> <span class="o">+</span> <span class="n">x</span> <span class="o">+</span> <span class="n">y</span> <span class="o">+</span> <span class="n">z</span> <span class="o">>=</span> <span class="mi">0</span><span class="p">,</span> <span class="n">x</span><span class="o">**</span><span class="mi">2</span> <span class="o">-</span> <span class="n">y</span><span class="o">**</span><span class="mi">2</span> <span class="o">>=</span> <span class="mi">0</span><span class="p">)</span> | ||||
| 
 | ||||
| <span class="k">print</span> <span class="n">t</span><span class="p">(</span><span class="n">g</span><span class="p">)</span> | ||||
| </pre></div> | ||||
| </body></html></example> | ||||
| 
 | ||||
| </body> | ||||
| </html> | ||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue