/*++ Copyright (c) 2006 Microsoft Corporation Module Name: z3_solver.h Abstract: Native ast parser. Author: Nikolaj Bjorner (nbjorner) 2007-07-17 Revision History: --*/ /** \defgroup z3native Z3 low level input format This format is mainly used for generating logs. These logs capture the expressions created using the Z3 API, and the main commands available there. It is very low-level and follows some of the conventions found in the DIMACS format for SAT problems and by the Spear input format. The format is extensible, as the grammar allows for selecting solvers and adding \emph{semantic attachments} with constructors. The SMT-LIB and Simplify text formats are easier to write and read for a human consumer. Every line consists of a command that gets interpreted as a declaration of a node in anbstract syntax tree, or as a control instruction to Z3, such as to augment the current context with constraints or check for satisfiability. \nicebox{ command := | ast | control | ; commented line } White spaces are implicit in the production rules. The legal white-spaces have the ASCII representations \nicebox{ ' ' | \ t | \ r } Comment lines start with \c ;. All characters up to the newline \ n are ignored. We use id for identifiers in general. Identifiers associated with certain semantic categories, such as \emph{ast} nodes, or \emph{type}s are prefixed by the category and suffixed by \emph{id}. For example, we have: \nicebox{ ast-id - identifier for ast nodes type-id - identifier for type nodes parameter-id - identifier for ast name-id - identifier for a function/type name decl-id - identifier for declaration node context-id - identifier for Boolean context } Identifiers can be any sequence of non-whitespace and non-newline characters whose first character is not one of the decimal digits. Identifiers enclosed in quotes ''...'' are treated specially: the quotes are stripped. Thus, the identifier consisting of zero characters is written ''''. The identifier ''null'' is allowed for skolem-id and quant-id. \section nativecontrol Control commands To load a theory solver for integer linear arithmetic, include a line of the form \ty{Solver LIA}. To load the mixed integer/real solver include instead a line of the form \ty{Solver LRA} Use \ty{Push} and \ty{Pop} to push/pop contexts (constraints that are asserted under a \ty{Push} are removed after a \ty{Pop}). To reset the state entirely, use \ty{Reset}. To assert a constraint use \ty{Assert} \emph{ast-id}, where the \emph{ast-id} is an identifier declared for a boolean typed term. To check for satisfiability of all asserted constraints use \ty{Check}. \nicebox{ control := | Solver solver - load specified theory solver | Assert ast-id - assert constraint | Check - check for satisfiability of asserts | Push - push a context | Pop - pop a context | Version major minor build-number revision - specify Z3 version solver := | LRA - mixed integer/real arithmetic | LIA - integer arithmetic} \section z3nativeast Abstract syntax trees Every node in the abstract syntax trees understood by Z3 is declared by using a syntax category identifier, followed by a (unique) identifier that names the node. The node identifier is followed by a description of the node. In overview abstract syntax tree nodes are declared using the commands: \nicebox{ ast := | Type id type | Dec id declaration | Const id constant | Fun id function | App id built-in | Num id numeral | Qua id quantifier | Var id bound-variable | Ctx id local-context | Lab id label-term | Pat id pattern } \subsection z3nativetypes Types Types are created from a name and optional parameters. A number of names are reserved for built-in theories. These names are: \nicebox{ Int Real Bool bv array } When the name of a type is one of these, the type is automatically associated with the respective theory. The \ty{bv} type takes one numeric parameter (the bit-width of the bit-vector), and \ty{array} takes n+1 parameters (the n types for the domain of the array and the last parameter for the range of the array. \nicebox{ type := name '[' parameter* ']' parameter := number | ast-id | symbol } A parameter can either be an integer, an identifier used for another defined term or type, or a symbol. Symbols are given as strings. The parser first attempts to identify a parameter as a previously defined term or type, and if there is no such previously defined term/type, then it treats the string as a symbol. \subsection nativez3Fuctions Function and constant declarations In Z3, functions are constants that take more than zero arguments, thus, everything is treated as a constant. Constant declarations comprise of a name, followed by a non-empty list of types, all but the first types are the domain of the function (there are no domain types for 0-ary constants), the last type is the range. A constant declaration is followed by optional theory specific information. The codes used in the theory specific information is described under \ref theories The theory specific information indicates whether the constant is associative/commutative/injective; a list of parameters may also be used to indicate auxiliary information for the constant declarations. \nicebox{ declaration := name-id type-id* [const-info] const-info := BUILTIN theory kind-num (:assoc | :comm | :inj | parameter)* theory := | basic - built-in types and operations | arith - arithmetical | bv - bit-vectors | array - arrays | datatype - datatypes } \subsection z3nativeterms Terms Terms are built from constants, function applications, labeling, context formation, quantification and bound variables. A constant consists of a declarations, functions consist of a declaration followed by a non-empty list of term identifiers. All constants and function applications can be constructed using the \ty{Fun} construct. However, two shortcuts are available. \nicebox{ constant := name-id type-id function := decl-id ast-id* built-in := name-id [ [ parameter* ] ] ast-id* } Labeled terms consist of a polarity (\ty{LBLPOS} for positive context, \ty{LBLNEG} for negative contexts), a name, and a term identifier. \nicebox{ label-term := (LBLPOS | LBLNEG) label-name ast-id } Local contexts consist of an identifier for the underlying term, followed by a predicate summarizing the context in which the term is interpreted. \nicebox{ local-context := ast-id context-id } A quantifier consists of \nicebox{ quantifier := (FORALL | EXISTS) weight-num skolem-id quant-id decls-num (name-id type-id)* pattern-num pattern-id* ast-id } A bound variable consists of a de-Brujin index for the bound variable together with the type of the bound variable. While the type can be computed by matching the index of the de-Brujin index with the associated quantifier, Patterns comprise of a list of terms. \nicebox{ bound-variable := index-num type-id numeral := rational type-id rational := number [/number] number := [0-9]+ pattern := id ast-id* } \section z3nativeexamples Examples \subsection z3nativearithmetic Integer Arithmetic Suppose we wish to check whether \nicebox{ z0 >= 0 && z1 >= 0 && z2 >= 1 && z1 >= z2 && z2 >= z0 } is satisfiable for
z0, z1, z2
integers. With the low-level input format, we may specify this by: \nicebox{ Type INT Int Type BOOL Bool Const z0 z0 INT Const z1 z1 INT Const z2 z2 INT Num 0 0 INT Num 1 1 INT App c0 >= z0 0 Assert c0 App c1 >= z1 0 Assert c1 App c2 >= z2 1 Assert c2 App c3 >= z1 z2 Assert c3 App c4 >= z2 z0 Assert c4 Check } Notice that the identifiers may be arbitrary strings, including numerals. So for instance, we used 1 to represent integer 1. \subsection z3nativebv Bit-vectors We can check whether 32-bit addition is commutative. Z3 reports \ty{unsat} in for the first check. The second satisfiable check illustrates the use of parameters (\ty{extract} takes two integer parameters for the range of bits extracted from the bit-vectors). \nicebox{ Type bool Bool Type bv32 bv [ 32 ] Type bv64 bv [ 64 ] Num 0 0 bv32 Num 1 1 bv32 Const x0 x0 bv32 Const x1 x1 bv32 Const x2 x2 bv64 App a bvadd x0 x1 App b bvadd x1 x0 App eq = a b App constraint1 not eq Push Assert constraint1 Check Pop App c extract [ 31 0 ] x2 App eq2 = a c App constraint2 not eq2 Push Assert constraint2 Check Pop } We added the declarations of bit-vector constants 0 and 1. Like integers, these are also numerals, but with bit-vector type. \subsection z3nativeexarray Arrays The low-level version of: \nicebox{ store(f1,i1,v1) = store(f2,i2,v2) && i1 != i3 && i2 != i3 && select(f1,i3) != select(f2,i3) } is: \nicebox{ Type Index Index Type Elem Elem Type Array array [ Index Elem ] Type bool Bool Const i1 i1 Index Const i2 i2 Index Const i3 i3 Index Const v1 v1 Elem Const v2 v2 Elem Const f1 f1 Array Const f2 f2 Array App n1 store f1 i1 v1 App n2 store f2 i2 v2 App n3 = n1 n2 App n4 = i1 i3 App n5 not n4 App n6 = i2 i3 App n7 not n6 App n8 select f1 i3 App n9 select f2 i3 App n10 = n8 n9 App n11 not n10 Assert n3 Assert n5 Assert n7 Assert n11 Check } \subsection z3nativeexdatatype Data-types To check projection over tuples \nicebox{ (= x (first (mk_tuple x y))) } we write: \nicebox{ Type int Int Type pair tuple [ mk_tuple first int second int ] Const x x int Const y y int Const p p pair App n1 mk_tuple x y App n2 first n1 App n3 = n2 x App n4 not n3 Assert n4 Check } */ /** \defgroup theories Z3 theories \section theorisbasics Basics There is a single basic sort, \ty{bool}, which has op-code 0. The basic operators are, listed with their codes in the table below.
Op-code Mnmonics Description
0 \ty{true} the constant \emph{true}
1 \ty{false} the constant \emph{false}
2 \ty{=} equality
3 \ty{distinct} distincinctness
4 \ty{ite} if-then-else
5 \ty{and} n-ary conjunction
6 \ty{or} n-ary disjunction
7 \ty{iff} bi-impliciation
8 \ty{xor} exclusive or
9 \ty{not} negation
10 \ty{implies} implication
\section theoriesarithmetic Arithmetic \subsection tharithbuiltin Built-in operators Arithmetical expression can be built from reals or integers. The arithmetical sorts are listed below and the supported operations are listed in the table thereafter.
Op-code Mnmonics Description
0 \ty{real} sort of reals
1 \ty{int} sort of integers
Op-code Mnmonics Description
0 \ty{<=} less-than or equal
1 \ty{>=} greater-than or equal
2 \ty{<} less-than
3 \ty{>} greater-than
4 \ty{+} n-ary addition
5 \ty{-} binary minus
6 \ty{~} unary minus
7 \ty{*} n-ary multiplication
8 \ty{/} rational division
9 \ty{div} integer division
10 \ty{rem} integer remainder
11 \ty{mod} integer modulus
\section theoriesbv Bit-vectors To indicate the bit-vector length one adds a numeral parameter with the number of bits the bit-vector holds. For instance, a declaration of the form: \nicebox{ Type $1 bv [ 32 ] } declares a 32-bit bit-vector type.
Op-code Mnmonics Parameters Description
0 \ty{bit1} constant comprising of a single bit set to 1
1 \ty{bit0} constant comprising of a single bit set to 0.
2 \ty{bvneg} Unary subtraction.
3 \ty{bvadd} addition.
4 \ty{bvsub} subtraction.
5 \ty{bvmul} multiplication.
6 \ty{bvsdiv} signed division.
7 \ty{bvudiv} unsigned division. The operands are treated as unsigned numbers.
8 \ty{bvsrem} signed remainder.
9 \ty{bvurem} unsigned remainder.
10 \ty{bvsmod} signed modulus.
11 \ty{bvule} unsigned \ty{<=}.
12 \ty{bvsle} signed \ty{<=}.
13 \ty{bvuge} unsigned \ty{>=}.
14 \ty{bvsge} signed \ty{>=}.
15 \ty{bvult} unsigned \ty{<}.
16 \ty{bvslt} signed \ty{<}.
17 \ty{bvugt} unsigned \ty{>}.
18 \ty{bvsgt} signed \ty{>}.
19 \ty{bvand} n-ary (associative/commutative) bit-wise and.
20 \ty{bvor} n-ary (associative/commutative) bit-wise or.
21 \ty{bvnot} bit-wise not.
22 \ty{bvxor} n-ary bit-wise xor.
23 \ty{bvnand} bit-wise nand.
24 \ty{bvnor} bit-wise nor.
25 \ty{bvxnor} bit-wise exclusive nor.
26 \ty{concat} bit-vector concatentaion.
27 \ty{sign\_extend} \emph{n} \emph{n}-bit sign extension.
28 \ty{zero\_extend} \emph{n} \emph{n}-bit zero extension.
29 \ty{extract} \emph{hi:low} \emph{hi}-\emph{low} bit-extraction.
30 \ty{repeat} \emph{n} repeat $n$ times.
31 \ty{bvredor} or-reduction.
32 \ty{bvredand} and-reducdtion.
33 \ty{bvcomp} bit-vector comparison.
34 \ty{bvshl} shift-left.
35 \ty{bvlshr} logical shift-right.
36 \ty{bvrshr} arithmetical shift-right.
37 \ty{bvrotate\_left} \emph{n} \emph{n}-bit left rotation.
38 \ty{bvrotate\_right} \emph{n} \emph{n}-bit right rotation.
\section theoriesarrays Arrays \subsection tharraybuiltinops Built-in operators There is a single built-in sort constructor for arrays with code 0. It is followed by a sequence of parameters indicating the domain sorts and the range of the array.
Op-code Mnmonics Description
0 \ty{store} array store
1 \ty{select} array select
In the low-level input format, array types are accompanied by a sequence of identifiers corresponding to the domain and range of the array the operations operate upon. In more detail, the contract is that the supplied parameters to the type declaration of an array are of the form: The constant array function symbol \ty{const} needs a parameter in order to infer the types of the indices of the constant array. We pass the array type as the parameter to \ty{const}. The other array operations do not need parameters. We summarize the arities and semantics of the operators: */ #ifndef _Z3_SOLVER_H_ #define _Z3_SOLVER_H_ #include "ast.h" #include "symbol_table.h" #include "stream_buffer.h" #include "warning.h" #include "front_end_params.h" #include "arith_decl_plugin.h" #include "bv_decl_plugin.h" #include "z3.h" class z3_solver { enum kind { T_NUM, T_VAR, T_DEC, T_FUNCTION_CONST, T_GET_IMPLIED_EQUALITIES, T_NULLARY_CONST, T_BUILTIN_CONST, T_TY, T_TYPE, T_QUA, T_LAB, T_CTX, T_PAT, T_SOLVER, T_SIMPLIFY, T_ASSERT, T_CHECK, T_CHECK_ASSUMPTIONS, T_DBG_SAT, T_DBG_UNSAT, T_PUSH, T_POP, T_RESET, T_ECHO, T_VERSION, T_COMMENT, T_EOF, T_ERR }; struct builtin_info { family_id m_fid; decl_kind m_kind; builtin_info(family_id fid, decl_kind k) : m_fid(fid), m_kind(k) {} builtin_info(): m_fid(null_family_id), m_kind(null_decl_kind) {} }; Z3_context m_context; bool m_owns_context; ast_manager& m_manager; front_end_params& m_params; symbol_table m_table; stream_buffer m_in; std::ostream& m_out; bool m_is_active; expr_ref_vector m_assumptions; unsigned_vector m_assumptions_lim; unsigned m_num_checks; std::string m_string; bool m_eof; unsigned m_line; symbol_table m_builtin_ops; symbol_table m_builtin_types; arith_util m_arith; bv_util m_bv; ast_ref_vector m_pinned; unsigned_vector m_pinned_lim; Z3_lbool m_last_check_result; public: z3_solver( Z3_context c, std::istream& is, std::ostream& os, front_end_params & params, bool is_active = true ); z3_solver( ast_manager& m, std::istream& is, std::ostream& os, front_end_params & params ); ~z3_solver(); bool parse(); void get_assumptions(expr_ref_vector& v) { v.append(m_assumptions); } void display_statistics(std::ostream& out, bool istats); void set_error_handler(Z3_error_handler h) { Z3_set_error_handler(m_context, h); } private: template struct coerce { virtual ~coerce() {} virtual T* operator()(ast* a) const = 0; }; struct sort_coerce : public coerce { virtual sort* operator()(ast* a) const { if (!a || a->get_kind() != AST_SORT) { return 0; } return to_sort(a); } }; struct func_decl_coerce : public coerce { virtual func_decl* operator()(ast* a) const { if (!a || a->get_kind() != AST_FUNC_DECL) { return 0; } return to_func_decl(a); } }; struct pattern_coerce : public coerce { ast_manager& m_manager; pattern_coerce(ast_manager& m): m_manager(m) {} virtual app* operator()(ast* a) const { if (!a || a->get_kind() != AST_APP) { return 0; } if (!m_manager.is_pattern(to_app(a))) { return 0; } return to_app(a); } }; struct expr_coerce : public coerce { virtual expr* operator()(ast* a) const { if (!a) { return 0; } ast_kind k = a->get_kind(); switch(k) { case AST_APP: case AST_QUANTIFIER: case AST_VAR: return reinterpret_cast(a); default: return 0; } } }; struct app_coerce : public coerce { virtual app* operator()(ast* a) const { if (!a) { return 0; } if (a->get_kind() == AST_APP) { return to_app(a); } return 0; } }; template bool parse_ast(symbol id, T*& n, const coerce& coerce) { ast* a; if (!m_table.find(id, a)) { warning_msg("line %d. Could not find id '%s'\n", m_line, id.str().c_str()); return false; } n = coerce(a); if (n == 0) { warning_msg("line %d. Wrong kind %d for %s\n", m_line, a->get_kind(), id.str().c_str()); return false; } return true; } template bool parse_ast(T*& n, const coerce& coerce) { symbol id; if (parse_id(id)) { return parse_ast(id, n, coerce); } return false; } template bool parse_asts(ref_vector& asts, const coerce& c) { symbol id; T* n; while (m_string[0] != '\n') { if (strcmp(m_string.c_str(), "BUILTIN") == 0) { return true; } if (!parse_ast(n,c)) { return false; } asts.push_back(n); } return true; } kind parse_kind(); bool next_token(); bool parse_id(symbol& id); bool parse_rational(rational& r); void skip_blank(); bool parse_eol(); bool parse_numeral(); bool parse_var(); bool parse_info(scoped_ptr& info); bool parse_info(scoped_ptr& info); bool parse_func_decl(); bool parse_func_decl(symbol& id, func_decl*& d); bool parse_nullary_const(); bool parse_const(); bool parse_builtin_const(); bool parse_type(); bool parse_type_new(); bool parse_label(); bool parse_quantifier(); bool parse_pattern(); bool parse_int(int& i); bool check_int(int& i); bool parse_unsigned(unsigned& i); bool check_unsigned(unsigned& i); bool try_parse(char const* token); bool parse_assert(); bool parse_simplify(); bool parse_check(); bool parse_check_assumptions(); bool parse_get_implied_equalities(); bool parse_dbg(bool expected_sat); bool parse_push(); bool parse_comment(); bool parse_pop(); bool parse_reset(); bool parse_echo(); bool parse_version(); bool parse_solver(); bool parse_parameter(vector& params); bool parse_params(vector& params); bool find_builtin_op(symbol name, family_id & fid, decl_kind& kind); bool find_builtin_type(symbol name, family_id & fid, decl_kind& kind); void add_builtins(family_id fid); void add_id(symbol const& id, ast* a); family_id get_family_id(char const* s); void dump_smtlib_benchmark(unsigned num_assumptions, expr* const* assumptions, Z3_lbool result); }; #endif