mirror of
https://github.com/Z3Prover/z3
synced 2025-04-07 09:55:19 +00:00
862 lines
83 KiB
HTML
862 lines
83 KiB
HTML
<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>
|