src/HOL/Tools/SMT/z3_interface.ML
author boehmes
Tue, 07 Dec 2010 14:53:12 +0100
changeset 41307 d2b1fc1b8e19
parent 40929 872b08416fb4
child 41320 9f9bc1bdacef
permissions -rw-r--r--
centralized handling of built-in types and constants;
also store types and constants which are rewritten during preprocessing;
interfaces are identified by classes (supporting inheritance, at least on the level of built-in symbols);
removed term_eq in favor of type replacements: term-level occurrences of type bool are replaced by type term_bool (only for the translation)
boehmes@36890
     1
(*  Title:      HOL/Tools/SMT/z3_interface.ML
boehmes@36890
     2
    Author:     Sascha Boehme, TU Muenchen
boehmes@36890
     3
boehmes@36890
     4
Interface to Z3 based on a relaxed version of SMT-LIB.
boehmes@36890
     5
*)
boehmes@36890
     6
boehmes@36890
     7
signature Z3_INTERFACE =
boehmes@36890
     8
sig
boehmes@41307
     9
  val smtlib_z3C: SMT_Config.class
boehmes@41307
    10
  val setup: theory -> theory
boehmes@40403
    11
  val interface: SMT_Solver.interface
boehmes@36890
    12
boehmes@36891
    13
  datatype sym = Sym of string * sym list
boehmes@36891
    14
  type mk_builtins = {
boehmes@36891
    15
    mk_builtin_typ: sym -> typ option,
boehmes@36891
    16
    mk_builtin_num: theory -> int -> typ -> cterm option,
boehmes@36891
    17
    mk_builtin_fun: theory -> sym -> cterm list -> cterm option }
boehmes@36891
    18
  val add_mk_builtins: mk_builtins -> Context.generic -> Context.generic
boehmes@36891
    19
  val mk_builtin_typ: Proof.context -> sym -> typ option
boehmes@36891
    20
  val mk_builtin_num: Proof.context -> int -> typ -> cterm option
boehmes@36891
    21
  val mk_builtin_fun: Proof.context -> sym -> cterm list -> cterm option
boehmes@36891
    22
boehmes@36891
    23
  val is_builtin_theory_term: Proof.context -> term -> bool
boehmes@36890
    24
end
boehmes@36890
    25
boehmes@36890
    26
structure Z3_Interface: Z3_INTERFACE =
boehmes@36890
    27
struct
boehmes@36890
    28
boehmes@40910
    29
structure U = SMT_Utils
boehmes@41307
    30
structure B = SMT_Builtin
boehmes@40910
    31
boehmes@41307
    32
val smtlib_z3C = SMTLIB_Interface.smtlibC @ ["z3"]
boehmes@36890
    33
boehmes@36890
    34
boehmes@36891
    35
boehmes@41307
    36
(* interface *)
boehmes@36891
    37
boehmes@36891
    38
local
boehmes@41307
    39
  val {translate, extra_norm, ...} = SMTLIB_Interface.interface
boehmes@41307
    40
  val {prefixes, is_fol, header, serialize, ...} = translate
boehmes@36891
    41
boehmes@40817
    42
  fun is_int_div_mod @{const div (int)} = true
boehmes@40817
    43
    | is_int_div_mod @{const mod (int)} = true
boehmes@37146
    44
    | is_int_div_mod _ = false
boehmes@37146
    45
boehmes@40402
    46
  fun add_div_mod irules =
boehmes@40402
    47
    if exists (Term.exists_subterm is_int_div_mod o Thm.prop_of o snd) irules
boehmes@40402
    48
    then [(~1, @{thm div_by_z3div}), (~1, @{thm mod_by_z3mod})] @ irules
boehmes@40402
    49
    else irules
boehmes@37146
    50
boehmes@41307
    51
  fun extra_norm' has_datatypes = extra_norm has_datatypes o add_div_mod
boehmes@36891
    52
in
boehmes@36891
    53
boehmes@41307
    54
val setup =
boehmes@41307
    55
  B.add_builtin_fun' smtlib_z3C (@{const z3div}, "div") #>
boehmes@41307
    56
  B.add_builtin_fun' smtlib_z3C (@{const z3mod}, "mod")
boehmes@36890
    57
boehmes@40403
    58
val interface = {
boehmes@41307
    59
  class = smtlib_z3C,
boehmes@40403
    60
  extra_norm = extra_norm',
boehmes@36890
    61
  translate = {
boehmes@36890
    62
    prefixes = prefixes,
boehmes@41307
    63
    is_fol = is_fol,
boehmes@36891
    64
    header = header,
boehmes@41307
    65
    has_datatypes = true,
boehmes@36890
    66
    serialize = serialize}}
boehmes@36890
    67
boehmes@36890
    68
end
boehmes@36891
    69
boehmes@36891
    70
boehmes@36891
    71
boehmes@41307
    72
(* constructors *)
boehmes@36891
    73
boehmes@36891
    74
datatype sym = Sym of string * sym list
boehmes@36891
    75
boehmes@36891
    76
boehmes@41307
    77
(** additional constructors **)
boehmes@36891
    78
boehmes@36891
    79
type mk_builtins = {
boehmes@36891
    80
  mk_builtin_typ: sym -> typ option,
boehmes@36891
    81
  mk_builtin_num: theory -> int -> typ -> cterm option,
boehmes@36891
    82
  mk_builtin_fun: theory -> sym -> cterm list -> cterm option }
boehmes@36891
    83
boehmes@36891
    84
fun chained _ [] = NONE
boehmes@36891
    85
  | chained f (b :: bs) = (case f b of SOME y => SOME y | NONE => chained f bs)
boehmes@36891
    86
boehmes@36891
    87
fun chained_mk_builtin_typ bs sym =
boehmes@36891
    88
  chained (fn {mk_builtin_typ=mk, ...} : mk_builtins => mk sym) bs
boehmes@36891
    89
boehmes@36891
    90
fun chained_mk_builtin_num ctxt bs i T =
boehmes@36891
    91
  let val thy = ProofContext.theory_of ctxt
boehmes@36891
    92
  in chained (fn {mk_builtin_num=mk, ...} : mk_builtins => mk thy i T) bs end
boehmes@36891
    93
boehmes@36891
    94
fun chained_mk_builtin_fun ctxt bs s cts =
boehmes@36891
    95
  let val thy = ProofContext.theory_of ctxt
boehmes@36891
    96
  in chained (fn {mk_builtin_fun=mk, ...} : mk_builtins => mk thy s cts) bs end
boehmes@36891
    97
boehmes@41307
    98
fun fst_int_ord ((i1, _), (i2, _)) = int_ord (i1, i2)
boehmes@41307
    99
boehmes@36891
   100
structure Mk_Builtins = Generic_Data
boehmes@36891
   101
(
boehmes@36891
   102
  type T = (int * mk_builtins) list
boehmes@36891
   103
  val empty = []
boehmes@36891
   104
  val extend = I
wenzelm@39935
   105
  fun merge (bs1, bs2) = Ord_List.union fst_int_ord bs2 bs1
boehmes@36891
   106
)
boehmes@36891
   107
boehmes@36891
   108
fun add_mk_builtins mk =
wenzelm@39935
   109
  Mk_Builtins.map (Ord_List.insert fst_int_ord (serial (), mk))
boehmes@36891
   110
boehmes@36891
   111
fun get_mk_builtins ctxt = map snd (Mk_Builtins.get (Context.Proof ctxt))
boehmes@36891
   112
boehmes@36891
   113
boehmes@41307
   114
(** basic and additional constructors **)
boehmes@36891
   115
boehmes@36891
   116
fun mk_builtin_typ _ (Sym ("bool", _)) = SOME @{typ bool}
boehmes@40760
   117
  | mk_builtin_typ _ (Sym ("Int", _)) = SOME @{typ int}
boehmes@40760
   118
  | mk_builtin_typ _ (Sym ("int", _)) = SOME @{typ int}  (*FIXME: delete*)
boehmes@36891
   119
  | mk_builtin_typ ctxt sym = chained_mk_builtin_typ (get_mk_builtins ctxt) sym
boehmes@36891
   120
boehmes@36891
   121
fun mk_builtin_num _ i @{typ int} = SOME (Numeral.mk_cnumber @{ctyp int} i)
boehmes@36891
   122
  | mk_builtin_num ctxt i T =
boehmes@36891
   123
      chained_mk_builtin_num ctxt (get_mk_builtins ctxt) i T
boehmes@36891
   124
boehmes@40817
   125
val mk_true = Thm.cterm_of @{theory} (@{const Not} $ @{const False})
boehmes@40817
   126
val mk_false = Thm.cterm_of @{theory} @{const False}
boehmes@40817
   127
val mk_not = Thm.capply (Thm.cterm_of @{theory} @{const Not})
boehmes@40817
   128
val mk_implies = Thm.mk_binop (Thm.cterm_of @{theory} @{const HOL.implies})
boehmes@40817
   129
val mk_iff = Thm.mk_binop (Thm.cterm_of @{theory} @{const HOL.eq (bool)})
boehmes@40817
   130
val conj = Thm.cterm_of @{theory} @{const HOL.conj}
boehmes@40817
   131
val disj = Thm.cterm_of @{theory} @{const HOL.disj}
boehmes@36891
   132
boehmes@36891
   133
fun mk_nary _ cu [] = cu
boehmes@36891
   134
  | mk_nary ct _ cts = uncurry (fold_rev (Thm.mk_binop ct)) (split_last cts)
boehmes@36891
   135
boehmes@40910
   136
val eq = U.mk_const_pat @{theory} @{const_name HOL.eq} U.destT1
boehmes@40910
   137
fun mk_eq ct cu = Thm.mk_binop (U.instT' ct eq) ct cu
boehmes@36891
   138
boehmes@40910
   139
val if_term = U.mk_const_pat @{theory} @{const_name If} (U.destT1 o U.destT2)
boehmes@40910
   140
fun mk_if cc ct cu = Thm.mk_binop (Thm.capply (U.instT' ct if_term) cc) ct cu
boehmes@36891
   141
boehmes@40910
   142
val nil_term = U.mk_const_pat @{theory} @{const_name Nil} U.destT1
boehmes@40910
   143
val cons_term = U.mk_const_pat @{theory} @{const_name Cons} U.destT1
boehmes@36891
   144
fun mk_list cT cts =
boehmes@40910
   145
  fold_rev (Thm.mk_binop (U.instT cT cons_term)) cts (U.instT cT nil_term)
boehmes@36891
   146
boehmes@40929
   147
val distinct = U.mk_const_pat @{theory} @{const_name distinct}
boehmes@40910
   148
  (U.destT1 o U.destT1)
boehmes@36891
   149
fun mk_distinct [] = mk_true
boehmes@36891
   150
  | mk_distinct (cts as (ct :: _)) =
boehmes@40910
   151
      Thm.capply (U.instT' ct distinct) (mk_list (Thm.ctyp_of_term ct) cts)
boehmes@36891
   152
boehmes@40910
   153
val access = U.mk_const_pat @{theory} @{const_name fun_app}
boehmes@40910
   154
  (Thm.dest_ctyp o U.destT1)
boehmes@36891
   155
fun mk_access array index =
boehmes@36891
   156
  let val cTs = Thm.dest_ctyp (Thm.ctyp_of_term array)
boehmes@40910
   157
  in Thm.mk_binop (U.instTs cTs access) array index end
boehmes@36891
   158
boehmes@40910
   159
val update = U.mk_const_pat @{theory} @{const_name fun_upd}
boehmes@40910
   160
  (Thm.dest_ctyp o U.destT1)
boehmes@36891
   161
fun mk_update array index value =
boehmes@36891
   162
  let val cTs = Thm.dest_ctyp (Thm.ctyp_of_term array)
boehmes@40910
   163
  in Thm.capply (Thm.mk_binop (U.instTs cTs update) array index) value end
boehmes@36891
   164
boehmes@40817
   165
val mk_uminus = Thm.capply (Thm.cterm_of @{theory} @{const uminus (int)})
boehmes@40817
   166
val mk_add = Thm.mk_binop (Thm.cterm_of @{theory} @{const plus (int)})
boehmes@40817
   167
val mk_sub = Thm.mk_binop (Thm.cterm_of @{theory} @{const minus (int)})
boehmes@40817
   168
val mk_mul = Thm.mk_binop (Thm.cterm_of @{theory} @{const times (int)})
boehmes@40817
   169
val mk_div = Thm.mk_binop (Thm.cterm_of @{theory} @{const z3div})
boehmes@40817
   170
val mk_mod = Thm.mk_binop (Thm.cterm_of @{theory} @{const z3mod})
boehmes@40817
   171
val mk_lt = Thm.mk_binop (Thm.cterm_of @{theory} @{const less (int)})
boehmes@40817
   172
val mk_le = Thm.mk_binop (Thm.cterm_of @{theory} @{const less_eq (int)})
boehmes@36891
   173
boehmes@36891
   174
fun mk_builtin_fun ctxt sym cts =
boehmes@36891
   175
  (case (sym, cts) of
boehmes@36891
   176
    (Sym ("true", _), []) => SOME mk_true
boehmes@36891
   177
  | (Sym ("false", _), []) => SOME mk_false
boehmes@36891
   178
  | (Sym ("not", _), [ct]) => SOME (mk_not ct)
boehmes@40817
   179
  | (Sym ("and", _), _) => SOME (mk_nary conj mk_true cts)
boehmes@40817
   180
  | (Sym ("or", _), _) => SOME (mk_nary disj mk_false cts)
boehmes@36891
   181
  | (Sym ("implies", _), [ct, cu]) => SOME (mk_implies ct cu)
boehmes@36891
   182
  | (Sym ("iff", _), [ct, cu]) => SOME (mk_iff ct cu)
boehmes@36891
   183
  | (Sym ("~", _), [ct, cu]) => SOME (mk_iff ct cu)
boehmes@36891
   184
  | (Sym ("xor", _), [ct, cu]) => SOME (mk_not (mk_iff ct cu))
boehmes@36891
   185
  | (Sym ("ite", _), [ct1, ct2, ct3]) => SOME (mk_if ct1 ct2 ct3)
boehmes@36891
   186
  | (Sym ("=", _), [ct, cu]) => SOME (mk_eq ct cu)
boehmes@36891
   187
  | (Sym ("distinct", _), _) => SOME (mk_distinct cts)
boehmes@36891
   188
  | (Sym ("select", _), [ca, ck]) => SOME (mk_access ca ck)
boehmes@36891
   189
  | (Sym ("store", _), [ca, ck, cv]) => SOME (mk_update ca ck cv)
boehmes@36891
   190
  | _ =>
boehmes@36891
   191
    (case (sym, try (#T o Thm.rep_cterm o hd) cts, cts) of
boehmes@36891
   192
      (Sym ("+", _), SOME @{typ int}, [ct, cu]) => SOME (mk_add ct cu)
boehmes@36891
   193
    | (Sym ("-", _), SOME @{typ int}, [ct]) => SOME (mk_uminus ct)
boehmes@36891
   194
    | (Sym ("-", _), SOME @{typ int}, [ct, cu]) => SOME (mk_sub ct cu)
boehmes@36891
   195
    | (Sym ("*", _), SOME @{typ int}, [ct, cu]) => SOME (mk_mul ct cu)
boehmes@37146
   196
    | (Sym ("div", _), SOME @{typ int}, [ct, cu]) => SOME (mk_div ct cu)
boehmes@37146
   197
    | (Sym ("mod", _), SOME @{typ int}, [ct, cu]) => SOME (mk_mod ct cu)
boehmes@36891
   198
    | (Sym ("<", _), SOME @{typ int}, [ct, cu]) => SOME (mk_lt ct cu)
boehmes@36891
   199
    | (Sym ("<=", _), SOME @{typ int}, [ct, cu]) => SOME (mk_le ct cu)
boehmes@36891
   200
    | (Sym (">", _), SOME @{typ int}, [ct, cu]) => SOME (mk_lt cu ct)
boehmes@36891
   201
    | (Sym (">=", _), SOME @{typ int}, [ct, cu]) => SOME (mk_le cu ct)
boehmes@36891
   202
    | _ => chained_mk_builtin_fun ctxt (get_mk_builtins ctxt) sym cts))
boehmes@36891
   203
boehmes@36891
   204
boehmes@36891
   205
boehmes@41307
   206
(* abstraction *)
boehmes@36891
   207
boehmes@36891
   208
fun is_builtin_theory_term ctxt t =
boehmes@41307
   209
  if B.is_builtin_num ctxt t then true
boehmes@41307
   210
  else
boehmes@41307
   211
    (case Term.strip_comb t of
boehmes@41307
   212
      (Const c, ts) => B.is_builtin_fun ctxt c ts
boehmes@41307
   213
    | _ => false)
boehmes@36891
   214
boehmes@36891
   215
end