mirror of
https://github.com/Z3Prover/z3
synced 2025-04-06 17:44:08 +00:00
367 lines
12 KiB
OCaml
367 lines
12 KiB
OCaml
/* Copyright (c) Microsoft Corporation */
|
|
|
|
quote (ml,"
|
|
|
|
(* Internal auxiliary functions: *)
|
|
(*
|
|
(* Transform a pair of arrays into an array of pairs *)
|
|
let array_combine a b =
|
|
if Array.length a <> Array.length b then raise (Invalid_argument \"array_combine\");
|
|
Array.init (Array.length a) (fun i -> (a.(i), b.(i)))
|
|
|
|
(* [a |> b] is the pipeline operator for [b(a)] *)
|
|
let ( |> ) x f = f x
|
|
*)
|
|
|
|
(* Find the index of an element in an array, raises Not_found is missing *)
|
|
let find equal x a =
|
|
let len = Array.length a in
|
|
let rec find_ i =
|
|
if i >= len then
|
|
raise Not_found
|
|
else
|
|
if equal x a.(i) then
|
|
i
|
|
else
|
|
find_ (i+1)
|
|
in
|
|
find_ 0
|
|
|
|
|
|
(* Symbols *)
|
|
|
|
let symbol_refine c s =
|
|
match get_symbol_kind c s with
|
|
| INT_SYMBOL -> Symbol_int (get_symbol_int c s)
|
|
| STRING_SYMBOL -> Symbol_string (get_symbol_string c s)
|
|
|
|
let mk_symbol c = function
|
|
| Symbol_int(i) -> mk_int_symbol c i
|
|
| Symbol_string(s) -> mk_string_symbol c s
|
|
|
|
|
|
(* Sorts *)
|
|
|
|
let get_datatype_sort c s =
|
|
Array.init (get_datatype_sort_num_constructors c s) (fun i ->
|
|
let constructor = get_datatype_sort_constructor c s i in
|
|
let recognizer = get_datatype_sort_recognizer c s i in
|
|
let accessors =
|
|
Array.init (get_domain_size c constructor) (fun j ->
|
|
get_datatype_sort_constructor_accessor c s i j
|
|
) in
|
|
{constructor; recognizer; accessors}
|
|
)
|
|
|
|
let sort_refine c s =
|
|
match get_sort_kind c s with
|
|
| UNINTERPRETED_SORT -> Sort_uninterpreted (get_sort_name c s)
|
|
| BOOL_SORT -> Sort_bool
|
|
| INT_SORT -> Sort_int
|
|
| BV_SORT -> Sort_bv (get_bv_sort_size c s)
|
|
| FINITE_DOMAIN_SORT ->
|
|
(match get_finite_domain_sort_size c s with
|
|
| Some(sz) -> Sort_finite_domain (get_sort_name c s, sz)
|
|
| None -> failwith \"Z3.sort_refine: failed to get size of finite-domain sort\"
|
|
)
|
|
| REAL_SORT -> Sort_real
|
|
| ARRAY_SORT -> Sort_array (get_array_sort_domain c s, get_array_sort_range c s)
|
|
| DATATYPE_SORT -> Sort_datatype (get_datatype_sort c s)
|
|
| RELATION_SORT -> Sort_relation (Array.init (get_relation_arity c s) (fun i -> get_relation_column c s i))
|
|
| UNKNOWN_SORT -> Sort_unknown
|
|
|
|
let mk_sort c = function
|
|
| Sort_uninterpreted(s) -> mk_uninterpreted_sort c s
|
|
| Sort_bool -> mk_bool_sort c
|
|
| Sort_int -> mk_int_sort c
|
|
| Sort_bv(size) -> mk_bv_sort c size
|
|
| Sort_finite_domain(name,size) -> mk_finite_domain_sort c name size
|
|
| Sort_real -> mk_real_sort c
|
|
| Sort_array(domain,range) -> mk_array_sort c domain range
|
|
| Sort_datatype(constructors) -> get_range c constructors.(0).constructor
|
|
| Sort_relation(_) -> invalid_arg \"Z3.mk_sort: cannot construct relation sorts\"
|
|
| Sort_unknown(_) -> invalid_arg \"Z3.mk_sort: cannot construct unknown sorts\"
|
|
|
|
|
|
(* Replacement datatypes creation API *)
|
|
|
|
let mk_datatypes ctx generator =
|
|
let usort0 = mk_uninterpreted_sort ctx (mk_int_symbol ctx 0)
|
|
in
|
|
let rec find_num_sorts i =
|
|
if i = max_int then invalid_arg \"mk_datatypes: too many sorts\"
|
|
else
|
|
match generator (Array.make i usort0) with
|
|
| None -> find_num_sorts (i+1)
|
|
| Some(a) when Array.length a = i -> i
|
|
| Some _ -> invalid_arg \"mk_datatypes: number of sorts and datatype descriptors must be equal\"
|
|
in
|
|
let num_sorts = find_num_sorts 0
|
|
in
|
|
let sorts0 = Array.init num_sorts (fun i -> mk_uninterpreted_sort ctx (mk_int_symbol ctx i))
|
|
in
|
|
let ctorss_descriptors =
|
|
match generator sorts0 with
|
|
| Some(ctorss_descriptors) -> ctorss_descriptors
|
|
| None -> invalid_arg \"mk_datatypes: generator failed\"
|
|
in
|
|
let names = Array.map fst ctorss_descriptors
|
|
in
|
|
let ctorss =
|
|
Array.map (fun (_, ctors_descriptor) ->
|
|
Array.map (fun {constructor_desc; recognizer_desc; accessor_descs} ->
|
|
let field_names = Array.map fst accessor_descs
|
|
in
|
|
let sort_refs = Array.make (Array.length accessor_descs) 0
|
|
in
|
|
let field_sorts =
|
|
Array.mapi (fun i (_, sort) ->
|
|
try
|
|
let j = find (fun s t -> is_eq_sort ctx s t) sort sorts0 in
|
|
sort_refs.(i) <- j ;
|
|
None
|
|
with Not_found ->
|
|
Some(sort)
|
|
) accessor_descs
|
|
in
|
|
mk_constructor ctx constructor_desc recognizer_desc field_names field_sorts sort_refs
|
|
) ctors_descriptor
|
|
) ctorss_descriptors
|
|
in
|
|
let constructor_lists = Array.map (mk_constructor_list ctx) ctorss
|
|
in
|
|
let sorts,_ = mk_datatypes ctx names constructor_lists
|
|
in
|
|
let datatypes =
|
|
Array.mapi (fun i sort ->
|
|
(sort,
|
|
Array.mapi (fun j ctor ->
|
|
let num_fields = Array.length (snd ctorss_descriptors.(i)).(j).accessor_descs in
|
|
let constructor, recognizer, accessors = query_constructor ctx ctor num_fields in
|
|
{constructor; recognizer; accessors}
|
|
) ctorss.(i))
|
|
) sorts
|
|
in
|
|
Array.iter (fun ctor_list ->
|
|
del_constructor_list ctx ctor_list
|
|
) constructor_lists
|
|
;
|
|
Array.iter (fun ctors ->
|
|
Array.iter (fun ctor ->
|
|
del_constructor ctx ctor
|
|
) ctors
|
|
) ctorss
|
|
;
|
|
datatypes
|
|
|
|
|
|
(* Numerals *)
|
|
|
|
let rec numeral_refine c t =
|
|
assert( get_ast_kind c t = NUMERAL_AST );
|
|
let sort = get_sort c t in
|
|
let is_int, i = get_numeral_int c t in
|
|
if is_int then
|
|
Numeral_int (i, sort)
|
|
else
|
|
let is_int64, i = get_numeral_int64 c t in
|
|
if is_int64 then
|
|
Numeral_int64 (i, sort)
|
|
else
|
|
if get_sort_kind c sort <> REAL_SORT then
|
|
Numeral_large (get_numeral_string c t, sort)
|
|
else
|
|
let n = numeral_refine c (get_numerator c t) in
|
|
let d = numeral_refine c (get_denominator c t) in
|
|
Numeral_rational (n, d)
|
|
|
|
|
|
let to_real c x =
|
|
if get_sort_kind c (get_sort c x) = REAL_SORT then
|
|
x
|
|
else
|
|
mk_int2real c x
|
|
|
|
let rec embed_numeral c = function
|
|
| Numeral_int (i, s) -> mk_int c i s
|
|
| Numeral_int64 (i, s) -> mk_int64 c i s
|
|
| Numeral_large (l, s) -> mk_numeral c l s
|
|
| Numeral_rational (Numeral_int(n,_), Numeral_int(d,_)) -> mk_real c n d
|
|
| Numeral_rational (n, d) ->
|
|
mk_div c (to_real c (embed_numeral c n)) (to_real c (embed_numeral c d))
|
|
(* Or should the following be used instead?
|
|
let n_str = get_numeral_string c (embed_numeral c n) in
|
|
let d_str = get_numeral_string c (embed_numeral c d) in
|
|
mk_numeral c (n_str ^ \" / \" ^ d_str) (mk_real_sort c)
|
|
*)
|
|
|
|
(* Terms *)
|
|
|
|
let get_app_args c a =
|
|
Array.init (get_app_num_args c a) (get_app_arg c a);;
|
|
|
|
let get_domains c d =
|
|
Array.init (get_domain_size c d) (get_domain c d);;
|
|
|
|
|
|
let get_pattern_terms c p =
|
|
Array.init (get_pattern_num_terms c p) (get_pattern c p)
|
|
|
|
|
|
let term_refine c t =
|
|
match get_ast_kind c t with
|
|
| NUMERAL_AST ->
|
|
Term_numeral (numeral_refine c t)
|
|
| APP_AST ->
|
|
let t' = to_app c t in
|
|
let f = get_app_decl c t' in
|
|
let num_args = get_app_num_args c t' in
|
|
let args = Array.init num_args (get_app_arg c t') in
|
|
let k = get_decl_kind c f in
|
|
Term_app (k, f, args)
|
|
| QUANTIFIER_AST ->
|
|
let bt = if is_quantifier_forall c t then Forall else Exists in
|
|
let w = get_quantifier_weight c t in
|
|
let np = get_quantifier_num_patterns c t in
|
|
let pats = Array.init np (get_quantifier_pattern_ast c t) in
|
|
let pats = Array.map (get_pattern_terms c) pats in
|
|
let nb = get_quantifier_num_bound c t in
|
|
let bound =
|
|
Array.init nb (fun i ->
|
|
(get_quantifier_bound_name c t i, get_quantifier_bound_sort c t i)
|
|
) in
|
|
let body = get_quantifier_body c t in
|
|
Term_quantifier (bt, w, pats, bound, body)
|
|
| VAR_AST ->
|
|
Term_var (get_index_value c t, get_sort c t)
|
|
| _ ->
|
|
assert false
|
|
|
|
|
|
(* let mk_term c = function *)
|
|
(* | Term_numeral (numeral, sort) -> mk_numeral c numeral sort *)
|
|
(* | Term_app (kind, decl, args) -> *)
|
|
(* | Term_quantifier (strength, weight, pats, bound, body) -> *)
|
|
(* | Term_var (index, sort) -> *)
|
|
|
|
|
|
|
|
(* Refined model API *)
|
|
|
|
let model_refine c m =
|
|
let num_sorts = model_get_num_sorts c m in
|
|
let sorts = Hashtbl.create num_sorts in
|
|
for i = 0 to num_sorts - 1 do
|
|
let sort = model_get_sort c m i in
|
|
let universe = model_get_sort_universe c m sort in
|
|
Hashtbl.add sorts sort universe
|
|
done;
|
|
let num_consts = model_get_num_consts c m in
|
|
let consts = Hashtbl.create num_consts in
|
|
let arrays = Hashtbl.create 0 in
|
|
for i = 0 to num_consts - 1 do
|
|
let const_decl = model_get_const_decl c m i in
|
|
match model_get_const_interp c m const_decl with
|
|
| Some(const_interp) ->
|
|
if is_as_array c const_interp then
|
|
let array_decl = get_as_array_func_decl c const_interp in
|
|
match model_get_func_interp c m array_decl with
|
|
| Some(array_interp) ->
|
|
let num_entries = func_interp_get_num_entries c array_interp in
|
|
let tbl = Hashtbl.create num_entries in
|
|
for i = 0 to num_entries - 1 do
|
|
let entry = func_interp_get_entry c array_interp i in
|
|
assert( func_entry_get_num_args c entry = 1 );
|
|
let arg = func_entry_get_arg c entry 0 in
|
|
let value = func_entry_get_value c entry in
|
|
Hashtbl.add tbl arg value
|
|
done;
|
|
let default = func_interp_get_else c array_interp in
|
|
Hashtbl.add arrays const_decl (tbl, default)
|
|
| None ->
|
|
()
|
|
else
|
|
Hashtbl.add consts const_decl const_interp
|
|
| None ->
|
|
()
|
|
done;
|
|
let num_funcs = model_get_num_funcs c m in
|
|
let funcs = Hashtbl.create num_funcs in
|
|
for i = 0 to num_funcs - 1 do
|
|
let func_decl = model_get_func_decl c m i in
|
|
if not (Hashtbl.mem arrays func_decl) then
|
|
match model_get_func_interp c m func_decl with
|
|
| Some(func_interp) ->
|
|
let num_entries = func_interp_get_num_entries c func_interp in
|
|
let tbl = Hashtbl.create num_entries in
|
|
for i = 0 to num_entries - 1 do
|
|
let entry = func_interp_get_entry c func_interp i in
|
|
let num_args = func_entry_get_num_args c entry in
|
|
let args = Array.init num_args (fun i -> func_entry_get_arg c entry i) in
|
|
let value = func_entry_get_value c entry in
|
|
Hashtbl.add tbl args value
|
|
done;
|
|
let default = func_interp_get_else c func_interp in
|
|
Hashtbl.add funcs func_decl (tbl, default)
|
|
| None ->
|
|
()
|
|
done;
|
|
{sorts; consts; arrays; funcs}
|
|
|
|
|
|
(* Extended parser API *)
|
|
|
|
let get_smtlib_formulas c =
|
|
Array.init (get_smtlib_num_formulas c) (get_smtlib_formula c)
|
|
|
|
let get_smtlib_assumptions c =
|
|
Array.init (get_smtlib_num_assumptions c) (get_smtlib_assumption c)
|
|
|
|
let get_smtlib_decls c =
|
|
Array.init (get_smtlib_num_decls c) (get_smtlib_decl c)
|
|
|
|
let get_smtlib_parse_results c =
|
|
(get_smtlib_formulas c, get_smtlib_assumptions c, get_smtlib_decls c)
|
|
|
|
let parse_smtlib_string_x c a1 a2 a3 a4 a5 =
|
|
parse_smtlib_string c a1 a2 a3 a4 a5 ;
|
|
get_smtlib_parse_results c
|
|
|
|
let parse_smtlib_file_x c a1 a2 a3 a4 a5 =
|
|
parse_smtlib_file c a1 a2 a3 a4 a5 ;
|
|
get_smtlib_parse_results c
|
|
|
|
let parse_smtlib_string_formula c a1 a2 a3 a4 a5 =
|
|
parse_smtlib_string c a1 a2 a3 a4 a5 ;
|
|
match get_smtlib_formulas c with [|f|] -> f | _ -> failwith \"Z3: parse_smtlib_string_formula\"
|
|
|
|
let parse_smtlib_file_formula c a1 a2 a3 a4 a5 =
|
|
parse_smtlib_file c a1 a2 a3 a4 a5 ;
|
|
match get_smtlib_formulas c with [|f|] -> f | _ -> failwith \"Z3: parse_smtlib_file_formula\"
|
|
|
|
|
|
(* Error handling *)
|
|
|
|
let get_error_msg c e =
|
|
match e with
|
|
| PARSER_ERROR -> (get_error_msg_ex c e) ^ \": \" ^ (get_smtlib_error c)
|
|
| _ -> get_error_msg_ex c e
|
|
|
|
|
|
(* Refined stats API *)
|
|
|
|
let stats_refine c s =
|
|
let num_stats = stats_size c s in
|
|
let tbl = Hashtbl.create num_stats in
|
|
for i = 0 to num_stats - 1 do
|
|
let key = stats_get_key c s i in
|
|
let datum =
|
|
if stats_is_uint c s i then
|
|
Stat_int(stats_get_uint_value c s i)
|
|
else
|
|
Stat_float(stats_get_double_value c s i) in
|
|
Hashtbl.add tbl key datum
|
|
done;
|
|
tbl
|
|
");
|