src/HOL/SMT/Tools/smt_translate.ML
author boehmes
Fri, 18 Sep 2009 18:13:19 +0200
changeset 32618 42865636d006
child 33017 4fb8a33f74d6
permissions -rw-r--r--
added new method "smt": an oracle-based connection to external SMT solvers
boehmes@32618
     1
(*  Title:      HOL/SMT/Tools/smt_translate.ML
boehmes@32618
     2
    Author:     Sascha Boehme, TU Muenchen
boehmes@32618
     3
boehmes@32618
     4
Translate theorems into an SMT intermediate format and serialize them,
boehmes@32618
     5
depending on an SMT interface.
boehmes@32618
     6
*)
boehmes@32618
     7
boehmes@32618
     8
signature SMT_TRANSLATE =
boehmes@32618
     9
sig
boehmes@32618
    10
  (* intermediate term structure *)
boehmes@32618
    11
  datatype sym =
boehmes@32618
    12
    SConst of string * typ |
boehmes@32618
    13
    SFree of string * typ |
boehmes@32618
    14
    SNum of int * typ
boehmes@32618
    15
  datatype squant = SForall | SExists
boehmes@32618
    16
  datatype 'a spattern = SPat of 'a list | SNoPat of 'a list
boehmes@32618
    17
  datatype ('a, 'b) sterm =
boehmes@32618
    18
    SVar of int |
boehmes@32618
    19
    SApp of 'a * ('a, 'b) sterm list |
boehmes@32618
    20
    SLet of (string * 'b) * ('a, 'b) sterm * ('a, 'b) sterm |
boehmes@32618
    21
    SQuant of squant * (string * 'b) list * ('a, 'b) sterm spattern list *
boehmes@32618
    22
      ('a, 'b) sterm
boehmes@32618
    23
boehmes@32618
    24
  (* table for built-in symbols *)
boehmes@32618
    25
  type builtin_fun = typ -> (sym, typ) sterm list ->
boehmes@32618
    26
    (string * (sym, typ) sterm list) option
boehmes@32618
    27
  type builtin_table = (typ * builtin_fun) list Symtab.table
boehmes@32618
    28
  val builtin_make: (term * string) list -> builtin_table
boehmes@32618
    29
  val builtin_add: term * builtin_fun -> builtin_table -> builtin_table
boehmes@32618
    30
  val builtin_lookup: builtin_table -> theory -> string * typ ->
boehmes@32618
    31
    (sym, typ) sterm list -> (string * (sym, typ) sterm list) option
boehmes@32618
    32
  val bv_rotate: (int -> string) -> builtin_fun
boehmes@32618
    33
  val bv_extend: (int -> string) -> builtin_fun
boehmes@32618
    34
  val bv_extract: (int -> int -> string) -> builtin_fun
boehmes@32618
    35
boehmes@32618
    36
  (* configuration options *)
boehmes@32618
    37
  datatype prefixes = Prefixes of {
boehmes@32618
    38
    var_prefix: string,
boehmes@32618
    39
    typ_prefix: string,
boehmes@32618
    40
    fun_prefix: string,
boehmes@32618
    41
    pred_prefix: string }
boehmes@32618
    42
  datatype markers = Markers of {
boehmes@32618
    43
    term_marker: string,
boehmes@32618
    44
    formula_marker: string }
boehmes@32618
    45
  datatype builtins = Builtins of {
boehmes@32618
    46
    builtin_typ: typ -> string option,
boehmes@32618
    47
    builtin_num: int * typ -> string option,
boehmes@32618
    48
    builtin_fun: bool -> builtin_table }
boehmes@32618
    49
  datatype sign = Sign of {
boehmes@32618
    50
    typs: string list,
boehmes@32618
    51
    funs: (string * (string list * string)) list,
boehmes@32618
    52
    preds: (string * string list) list }
boehmes@32618
    53
  datatype config = Config of {
boehmes@32618
    54
    strict: bool,
boehmes@32618
    55
    prefixes: prefixes,
boehmes@32618
    56
    markers: markers,
boehmes@32618
    57
    builtins: builtins,
boehmes@32618
    58
    serialize: sign -> (string, string) sterm list -> TextIO.outstream -> unit}
boehmes@32618
    59
  datatype recon = Recon of {typs: typ Symtab.table, terms: term Symtab.table}
boehmes@32618
    60
boehmes@32618
    61
  val translate: config -> theory -> thm list -> TextIO.outstream ->
boehmes@32618
    62
    recon * thm list
boehmes@32618
    63
boehmes@32618
    64
  val dest_binT: typ -> int
boehmes@32618
    65
  val dest_funT: int -> typ -> typ list * typ
boehmes@32618
    66
end
boehmes@32618
    67
boehmes@32618
    68
structure SMT_Translate: SMT_TRANSLATE =
boehmes@32618
    69
struct
boehmes@32618
    70
boehmes@32618
    71
(* Intermediate term structure *)
boehmes@32618
    72
boehmes@32618
    73
datatype sym =
boehmes@32618
    74
  SConst of string * typ |
boehmes@32618
    75
  SFree of string * typ |
boehmes@32618
    76
  SNum of int * typ
boehmes@32618
    77
datatype squant = SForall | SExists
boehmes@32618
    78
datatype 'a spattern = SPat of 'a list | SNoPat of 'a list
boehmes@32618
    79
datatype ('a, 'b) sterm =
boehmes@32618
    80
  SVar of int |
boehmes@32618
    81
  SApp of 'a * ('a, 'b) sterm list |
boehmes@32618
    82
  SLet of (string * 'b) * ('a, 'b) sterm * ('a, 'b) sterm |
boehmes@32618
    83
  SQuant of squant * (string * 'b) list * ('a, 'b) sterm spattern list *
boehmes@32618
    84
    ('a, 'b) sterm
boehmes@32618
    85
boehmes@32618
    86
fun app c ts = SApp (c, ts)
boehmes@32618
    87
boehmes@32618
    88
fun map_pat f (SPat ps) = SPat (map f ps)
boehmes@32618
    89
  | map_pat f (SNoPat ps) = SNoPat (map f ps)
boehmes@32618
    90
boehmes@32618
    91
fun fold_map_pat f (SPat ps) = fold_map f ps #>> SPat
boehmes@32618
    92
  | fold_map_pat f (SNoPat ps) = fold_map f ps #>> SNoPat
boehmes@32618
    93
boehmes@32618
    94
val make_sconst = SConst o Term.dest_Const
boehmes@32618
    95
boehmes@32618
    96
boehmes@32618
    97
(* General type destructors. *)
boehmes@32618
    98
boehmes@32618
    99
fun dest_binT T =
boehmes@32618
   100
  (case T of
boehmes@32618
   101
    Type (@{type_name "Numeral_Type.num0"}, _) => 0
boehmes@32618
   102
  | Type (@{type_name "Numeral_Type.num1"}, _) => 1
boehmes@32618
   103
  | Type (@{type_name "Numeral_Type.bit0"}, [T]) => 2 * dest_binT T
boehmes@32618
   104
  | Type (@{type_name "Numeral_Type.bit1"}, [T]) => 1 + 2 * dest_binT T
boehmes@32618
   105
  | _ => raise TYPE ("dest_binT", [T], []))
boehmes@32618
   106
boehmes@32618
   107
val dest_wordT = (fn
boehmes@32618
   108
    Type (@{type_name "word"}, [T]) => dest_binT T
boehmes@32618
   109
  | T => raise TYPE ("dest_wordT", [T], []))
boehmes@32618
   110
boehmes@32618
   111
val dest_funT =
boehmes@32618
   112
  let
boehmes@32618
   113
    fun dest Ts 0 T = (rev Ts, T)
boehmes@32618
   114
      | dest Ts i (Type ("fun", [T, U])) = dest (T::Ts) (i-1) U
boehmes@32618
   115
      | dest _ _ T = raise TYPE ("dest_funT", [T], [])
boehmes@32618
   116
  in dest [] end
boehmes@32618
   117
boehmes@32618
   118
boehmes@32618
   119
(* Table for built-in symbols *)
boehmes@32618
   120
boehmes@32618
   121
type builtin_fun = typ -> (sym, typ) sterm list ->
boehmes@32618
   122
  (string * (sym, typ) sterm list) option
boehmes@32618
   123
type builtin_table = (typ * builtin_fun) list Symtab.table
boehmes@32618
   124
boehmes@32618
   125
fun builtin_make entries =
boehmes@32618
   126
  let
boehmes@32618
   127
    fun dest (t, bn) =
boehmes@32618
   128
      let val (n, T) = Term.dest_Const t
boehmes@32618
   129
      in (n, (Logic.varifyT T, K (SOME o pair bn))) end
boehmes@32618
   130
  in Symtab.make (AList.group (op =) (map dest entries)) end
boehmes@32618
   131
boehmes@32618
   132
fun builtin_add (t, f) tab =
boehmes@32618
   133
  let val (n, T) = apsnd Logic.varifyT (Term.dest_Const t)
boehmes@32618
   134
  in Symtab.map_default (n, []) (AList.update (op =) (T, f)) tab end
boehmes@32618
   135
boehmes@32618
   136
fun builtin_lookup tab thy (n, T) ts =
boehmes@32618
   137
  AList.lookup (Sign.typ_instance thy) (Symtab.lookup_list tab n) T
boehmes@32618
   138
  |> (fn SOME f => f T ts | NONE => NONE)
boehmes@32618
   139
boehmes@32618
   140
local
boehmes@32618
   141
  val dest_nat = (fn
boehmes@32618
   142
      SApp (SConst (@{const_name nat}, _), [SApp (SNum (i, _), _)]) => SOME i
boehmes@32618
   143
    | _ => NONE)
boehmes@32618
   144
in
boehmes@32618
   145
fun bv_rotate mk_name T ts =
boehmes@32618
   146
  dest_nat (hd ts) |> Option.map (fn i => (mk_name i, tl ts))
boehmes@32618
   147
boehmes@32618
   148
fun bv_extend mk_name T ts =
boehmes@32618
   149
  (case (try dest_wordT (domain_type T), try dest_wordT (range_type T)) of
boehmes@32618
   150
    (SOME i, SOME j) => if j - i >= 0 then SOME (mk_name (j - i), ts) else NONE
boehmes@32618
   151
  | _ => NONE)
boehmes@32618
   152
boehmes@32618
   153
fun bv_extract mk_name T ts =
boehmes@32618
   154
  (case (try dest_wordT (body_type T), dest_nat (hd ts)) of
boehmes@32618
   155
    (SOME i, SOME lb) => SOME (mk_name (i + lb - 1) lb, tl ts)
boehmes@32618
   156
  | _ => NONE)
boehmes@32618
   157
end
boehmes@32618
   158
boehmes@32618
   159
boehmes@32618
   160
(* Configuration options *)
boehmes@32618
   161
boehmes@32618
   162
datatype prefixes = Prefixes of {
boehmes@32618
   163
  var_prefix: string,
boehmes@32618
   164
  typ_prefix: string,
boehmes@32618
   165
  fun_prefix: string,
boehmes@32618
   166
  pred_prefix: string }
boehmes@32618
   167
datatype markers = Markers of {
boehmes@32618
   168
  term_marker: string,
boehmes@32618
   169
  formula_marker: string }
boehmes@32618
   170
datatype builtins = Builtins of {
boehmes@32618
   171
  builtin_typ: typ -> string option,
boehmes@32618
   172
  builtin_num: int * typ -> string option,
boehmes@32618
   173
  builtin_fun: bool -> builtin_table }
boehmes@32618
   174
datatype sign = Sign of {
boehmes@32618
   175
  typs: string list,
boehmes@32618
   176
  funs: (string * (string list * string)) list,
boehmes@32618
   177
  preds: (string * string list) list }
boehmes@32618
   178
datatype config = Config of {
boehmes@32618
   179
  strict: bool,
boehmes@32618
   180
  prefixes: prefixes,
boehmes@32618
   181
  markers: markers,
boehmes@32618
   182
  builtins: builtins,
boehmes@32618
   183
  serialize: sign -> (string, string) sterm list -> TextIO.outstream -> unit}
boehmes@32618
   184
datatype recon = Recon of {typs: typ Symtab.table, terms: term Symtab.table}
boehmes@32618
   185
boehmes@32618
   186
boehmes@32618
   187
(* Translate Isabelle/HOL terms into SMT intermediate terms.
boehmes@32618
   188
   We assume that lambda-lifting has been performed before, i.e., lambda
boehmes@32618
   189
   abstractions occur only at quantifiers and let expressions.
boehmes@32618
   190
*)
boehmes@32618
   191
local
boehmes@32618
   192
  val quantifier = (fn
boehmes@32618
   193
      @{const_name All} => SOME SForall
boehmes@32618
   194
    | @{const_name Ex} => SOME SExists
boehmes@32618
   195
    | _ => NONE)
boehmes@32618
   196
boehmes@32618
   197
  fun group_quant qname vs (t as Const (q, _) $ Abs (n, T, u)) =
boehmes@32618
   198
        if q = qname then group_quant qname ((n, T) :: vs) u else (vs, t)
boehmes@32618
   199
    | group_quant qname vs t = (vs, t)
boehmes@32618
   200
boehmes@32618
   201
  fun dest_trigger (@{term trigger} $ tl $ t) = (HOLogic.dest_list tl, t)
boehmes@32618
   202
    | dest_trigger t = ([], t)
boehmes@32618
   203
boehmes@32618
   204
  fun pat f ps (Const (@{const_name pat}, _) $ p) = SPat (rev (f p :: ps))
boehmes@32618
   205
    | pat f ps (Const (@{const_name nopat}, _) $ p) = SNoPat (rev (f p :: ps))
boehmes@32618
   206
    | pat f ps (Const (@{const_name andpat}, _) $ p $ t) = pat f (f p :: ps) t
boehmes@32618
   207
    | pat _ _ t = raise TERM ("pat", [t])
boehmes@32618
   208
boehmes@32618
   209
  fun trans Ts t =
boehmes@32618
   210
    (case Term.strip_comb t of
boehmes@32618
   211
      (t1 as Const (qn, qT), [t2 as Abs (n, T, t3)]) =>
boehmes@32618
   212
        (case quantifier qn of
boehmes@32618
   213
          SOME q =>
boehmes@32618
   214
            let
boehmes@32618
   215
              val (vs, u) = group_quant qn [(n, T)] t3
boehmes@32618
   216
              val Us = map snd vs @ Ts
boehmes@32618
   217
              val (ps, b) = dest_trigger u
boehmes@32618
   218
            in SQuant (q, rev vs, map (pat (trans Us) []) ps, trans Us b) end
boehmes@32618
   219
        | NONE => raise TERM ("intermediate", [t]))
boehmes@32618
   220
    | (Const (@{const_name Let}, _), [t1, Abs (n, T, t2)]) =>
boehmes@32618
   221
        SLet ((n, T), trans Ts t1, trans (T :: Ts) t2)
boehmes@32618
   222
    | (Const (c as (@{const_name distinct}, _)), [t1]) =>
boehmes@32618
   223
        (* this is not type-correct, but will be corrected at a later stage *)
boehmes@32618
   224
        SApp (SConst c, map (trans Ts) (HOLogic.dest_list t1))
boehmes@32618
   225
    | (Const c, ts) =>
boehmes@32618
   226
        (case try HOLogic.dest_number t of
boehmes@32618
   227
          SOME (T, i) => SApp (SNum (i, T), [])
boehmes@32618
   228
        | NONE => SApp (SConst c, map (trans Ts) ts))
boehmes@32618
   229
    | (Free c, ts) => SApp (SFree c, map (trans Ts) ts)
boehmes@32618
   230
    | (Bound i, []) => SVar i
boehmes@32618
   231
    | _ => raise TERM ("intermediate", [t]))
boehmes@32618
   232
in
boehmes@32618
   233
fun intermediate ts = map (trans [] o HOLogic.dest_Trueprop) ts
boehmes@32618
   234
end
boehmes@32618
   235
boehmes@32618
   236
boehmes@32618
   237
(* Separate formulas from terms by adding special marker symbols ("term",
boehmes@32618
   238
   "formula"). Atoms "P" whose head symbol also occurs as function symbol are
boehmes@32618
   239
   rewritten to "term P = term True". Connectives and built-in predicates
boehmes@32618
   240
   occurring at term level are replaced by new constants, and theorems
boehmes@32618
   241
   specifying their meaning are added.
boehmes@32618
   242
*)
boehmes@32618
   243
local
boehmes@32618
   244
  (** Add the marker symbols "term" and "formulas" to separate formulas and
boehmes@32618
   245
      terms. **)
boehmes@32618
   246
boehmes@32618
   247
  val connectives = map make_sconst [@{term True}, @{term False},
boehmes@32618
   248
    @{term Not}, @{term "op &"}, @{term "op |"}, @{term "op -->"},
boehmes@32618
   249
    @{term "op = :: bool => _"}]
boehmes@32618
   250
boehmes@32618
   251
  fun note false c (ps, fs) = (insert (op =) c ps, fs)
boehmes@32618
   252
    | note true c (ps, fs) = (ps, insert (op =) c fs)
boehmes@32618
   253
boehmes@32618
   254
  val term_marker = SConst (@{const_name term}, Term.dummyT)
boehmes@32618
   255
  val formula_marker = SConst (@{const_name formula}, Term.dummyT)
boehmes@32618
   256
  fun mark f true t = f true t #>> app term_marker o single
boehmes@32618
   257
    | mark f false t = f false t #>> app formula_marker o single
boehmes@32618
   258
  fun mark' f false t = f true t #>> app term_marker o single
boehmes@32618
   259
    | mark' f true t = f true t
boehmes@32618
   260
  val mark_term = app term_marker o single
boehmes@32618
   261
  fun lift_term_marker c ts =
boehmes@32618
   262
    let val rem = (fn SApp (SConst (@{const_name term}, _), [t]) => t | t => t)
boehmes@32618
   263
    in mark_term (SApp (c, map rem ts)) end
boehmes@32618
   264
  fun is_term (SApp (SConst (@{const_name term}, _), _)) = true
boehmes@32618
   265
    | is_term _ = false
boehmes@32618
   266
boehmes@32618
   267
  fun either x = (fn y as SOME _ => y | _ => x)
boehmes@32618
   268
  fun get_loc loc i t =
boehmes@32618
   269
    (case t of
boehmes@32618
   270
      SVar j => if i = j then SOME loc else NONE
boehmes@32618
   271
    | SApp (SConst (@{const_name term}, _), us) => get_locs true i us
boehmes@32618
   272
    | SApp (SConst (@{const_name formula}, _), us) => get_locs false i us
boehmes@32618
   273
    | SApp (_, us) => get_locs loc i us
boehmes@32618
   274
    | SLet (_, u1, u2) => either (get_loc true i u1) (get_loc loc (i+1) u2)
boehmes@32618
   275
    | SQuant (_, vs, _, u) => get_loc loc (i + length vs) u)
boehmes@32618
   276
  and get_locs loc i ts = fold (either o get_loc loc i) ts NONE
boehmes@32618
   277
boehmes@32618
   278
  fun sep loc t =
boehmes@32618
   279
    (case t of
boehmes@32618
   280
      SVar i => pair t
boehmes@32618
   281
    | SApp (c as SConst (@{const_name If}, _), u :: us) =>
boehmes@32618
   282
        mark sep false u ##>> fold_map (sep loc) us #>> app c o (op ::)
boehmes@32618
   283
    | SApp (c, us) =>
boehmes@32618
   284
        if not loc andalso member (op =) connectives c
boehmes@32618
   285
        then fold_map (sep loc) us #>> app c
boehmes@32618
   286
        else note loc c #> fold_map (mark' sep loc) us #>> app c
boehmes@32618
   287
    | SLet (v, u1, u2) =>
boehmes@32618
   288
        sep loc u2 #-> (fn u2' =>
boehmes@32618
   289
        mark sep (the (get_loc loc 0 u2')) u1 #>> (fn u1' =>
boehmes@32618
   290
        SLet (v, u1', u2')))
boehmes@32618
   291
    | SQuant (q, vs, ps, u) =>
boehmes@32618
   292
        fold_map (fold_map_pat (mark sep true)) ps ##>>
boehmes@32618
   293
        sep loc u #>> (fn (ps', u') =>
boehmes@32618
   294
        SQuant (q, vs, ps', u')))
boehmes@32618
   295
boehmes@32618
   296
  (** Rewrite atoms. **)
boehmes@32618
   297
boehmes@32618
   298
  val unterm_rule = @{lemma "term x == x" by (simp add: term_def)}
boehmes@32618
   299
  val unterm_conv = More_Conv.top_sweep_conv (K (Conv.rewr_conv unterm_rule))
boehmes@32618
   300
boehmes@32618
   301
  val dest_word_type = (fn Type (@{type_name word}, [T]) => T | T => T)
boehmes@32618
   302
  fun instantiate [] _ = I
boehmes@32618
   303
    | instantiate (v :: _) T =
boehmes@32618
   304
        Term.subst_TVars [(v, dest_word_type (Term.domain_type T))]
boehmes@32618
   305
boehmes@32618
   306
  fun dest_alls (Const (@{const_name All}, _) $ Abs (_, _, t)) = dest_alls t
boehmes@32618
   307
    | dest_alls t = t
boehmes@32618
   308
  val dest_iff = (fn (Const (@{const_name iff}, _) $ t $ _ ) => t | t => t)
boehmes@32618
   309
  val dest_eq = (fn (Const (@{const_name "op ="}, _) $ t $ _ ) => t | t => t)
boehmes@32618
   310
  val dest_not = (fn (@{term Not} $ t) => t | t => t)
boehmes@32618
   311
  val head_of = HOLogic.dest_Trueprop #> dest_alls #> dest_iff #> dest_not #>
boehmes@32618
   312
    dest_eq #> Term.head_of
boehmes@32618
   313
boehmes@32618
   314
  fun prepare ctxt thm =
boehmes@32618
   315
    let
boehmes@32618
   316
      val rule = Conv.fconv_rule (unterm_conv ctxt) thm
boehmes@32618
   317
      val prop = Thm.prop_of thm
boehmes@32618
   318
      val inst = instantiate (Term.add_tvar_names prop [])
boehmes@32618
   319
      fun inst_for T = (singleton intermediate (inst T prop), rule)
boehmes@32618
   320
    in (make_sconst (head_of (Thm.prop_of rule)), inst_for) end
boehmes@32618
   321
boehmes@32618
   322
  val logicals = map (prepare @{context})
boehmes@32618
   323
    @{lemma 
boehmes@32618
   324
      "~ holds False"
boehmes@32618
   325
      "ALL p. holds (~ p) iff (~ holds p)"
boehmes@32618
   326
      "ALL p q. holds (p & q) iff (holds p & holds q)"
boehmes@32618
   327
      "ALL p q. holds (p | q) iff (holds p | holds q)"
boehmes@32618
   328
      "ALL p q. holds (p --> q) iff (holds p --> holds q)"
boehmes@32618
   329
      "ALL p q. holds (p iff q) iff (holds p iff holds q)"
boehmes@32618
   330
      "ALL p q. holds (p = q) iff (p = q)"
boehmes@32618
   331
      "ALL (a::int) b. holds (a < b) iff (a < b)"
boehmes@32618
   332
      "ALL (a::int) b. holds (a <= b) iff (a <= b)"
boehmes@32618
   333
      "ALL (a::real) b. holds (a < b) iff (a < b)"
boehmes@32618
   334
      "ALL (a::real) b. holds (a <= b) iff (a <= b)"
boehmes@32618
   335
      "ALL (a::'a::len0 word) b. holds (a < b) iff (a < b)"
boehmes@32618
   336
      "ALL (a::'a::len0 word) b. holds (a <= b) iff (a <= b)"
boehmes@32618
   337
      "ALL a b. holds (a <s b) iff (a <s b)"
boehmes@32618
   338
      "ALL a b. holds (a <=s b) iff (a <=s b)"
boehmes@32618
   339
      by (simp_all add: term_def iff_def)}
boehmes@32618
   340
boehmes@32618
   341
  fun is_instance thy (SConst (n, T), SConst (m, U)) =
boehmes@32618
   342
        (n = m) andalso Sign.typ_instance thy (T, U)
boehmes@32618
   343
    | is_instance _ _ = false
boehmes@32618
   344
boehmes@32618
   345
  fun lookup_logical thy (c as SConst (_, T)) =
boehmes@32618
   346
        AList.lookup (is_instance thy) logicals c
boehmes@32618
   347
        |> Option.map (fn inst_for => inst_for T)
boehmes@32618
   348
    | lookup_logical _ _ = NONE
boehmes@32618
   349
boehmes@32618
   350
  val s_eq = make_sconst @{term "op = :: bool => _"}
boehmes@32618
   351
  val s_True = mark_term (SApp (make_sconst @{term True}, []))
boehmes@32618
   352
  fun holds (SApp (c, ts)) = SApp (s_eq, [lift_term_marker c ts, s_True])
boehmes@32618
   353
    | holds t = SApp (s_eq, [mark_term t, s_True])
boehmes@32618
   354
boehmes@32618
   355
  val rewr_iff = (fn
boehmes@32618
   356
      SConst (@{const_name "op ="}, T as @{typ "bool => bool => bool"}) =>
boehmes@32618
   357
        SConst (@{const_name iff}, T)
boehmes@32618
   358
    | c => c)
boehmes@32618
   359
boehmes@32618
   360
  fun rewrite ls =
boehmes@32618
   361
    let
boehmes@32618
   362
      fun rewr env loc t =
boehmes@32618
   363
        (case t of
boehmes@32618
   364
          SVar i => if not loc andalso nth env i then holds t else t
boehmes@32618
   365
        | SApp (c as SConst (@{const_name term}, _), [u]) =>
boehmes@32618
   366
            SApp (c, [rewr env true u])
boehmes@32618
   367
        | SApp (c as SConst (@{const_name formula}, _), [u]) =>
boehmes@32618
   368
            SApp (c, [rewr env false u])
boehmes@32618
   369
        | SApp (c, us) =>
boehmes@32618
   370
            let val f = if not loc andalso member (op =) ls c then holds else I
boehmes@32618
   371
            in f (SApp (rewr_iff c, map (rewr env loc) us)) end
boehmes@32618
   372
        | SLet (v, u1, u2) =>
boehmes@32618
   373
            SLet (v, rewr env loc u1, rewr (is_term u1 :: env) loc u2)
boehmes@32618
   374
        | SQuant (q, vs, ps, u) =>
boehmes@32618
   375
            let val e = replicate (length vs) true @ env
boehmes@32618
   376
            in SQuant (q, vs, map (map_pat (rewr e loc)) ps, rewr e loc u) end)
boehmes@32618
   377
    in map (rewr [] false) end
boehmes@32618
   378
in
boehmes@32618
   379
fun separate thy ts =
boehmes@32618
   380
  let
boehmes@32618
   381
    val (ts', (ps, fs)) = fold_map (sep false) ts ([], [])
boehmes@32618
   382
    val eq_name = (fn
boehmes@32618
   383
        (SConst (n, _), SConst (m, _)) => n = m
boehmes@32618
   384
      | (SFree (n, _), SFree (m, _)) => n = m
boehmes@32618
   385
      | _ => false)
boehmes@32618
   386
    val ls = filter (member eq_name fs) ps
boehmes@32618
   387
    val (us, thms) = split_list (map_filter (lookup_logical thy) fs)
boehmes@32618
   388
  in (thms, us @ rewrite ls ts') end
boehmes@32618
   389
end
boehmes@32618
   390
boehmes@32618
   391
boehmes@32618
   392
(* Collect the signature of intermediate terms, identify built-in symbols,
boehmes@32618
   393
   rename uninterpreted symbols and types, make bound variables unique.
boehmes@32618
   394
   We require @{term distinct} to be a built-in constant of the SMT solver.
boehmes@32618
   395
*)
boehmes@32618
   396
local
boehmes@32618
   397
  fun empty_nctxt p = (p, 1)
boehmes@32618
   398
  fun make_nctxt (pT, pf, pp) = (empty_nctxt pT, empty_nctxt (pf, pp))
boehmes@32618
   399
  fun fresh_name (p, i) = (p ^ string_of_int i, (p, i+1))
boehmes@32618
   400
  fun fresh_typ (nT, nfp) = fresh_name nT ||> (fn nT' => (nT', nfp))
boehmes@32618
   401
  fun fresh_fun loc (nT, ((pf, pp), i)) =
boehmes@32618
   402
    let val p = if loc then pf else pp
boehmes@32618
   403
    in fresh_name (p, i) ||> (fn (_, i') => (nT, ((pf, pp), i'))) end
boehmes@32618
   404
boehmes@32618
   405
  val empty_sign = (Typtab.empty, Termtab.empty, Termtab.empty)
boehmes@32618
   406
  fun lookup_typ (typs, _, _) = Typtab.lookup typs
boehmes@32618
   407
  fun lookup_fun true (_, funs, _) = Termtab.lookup funs
boehmes@32618
   408
    | lookup_fun false (_, _, preds) = Termtab.lookup preds
boehmes@32618
   409
  fun add_typ x (typs, funs, preds) = (Typtab.update x typs, funs, preds)
boehmes@32618
   410
  fun add_fun true x (typs, funs, preds) = (typs, Termtab.update x funs, preds)
boehmes@32618
   411
    | add_fun false x (typs, funs, preds) = (typs, funs, Termtab.update x preds)
boehmes@32618
   412
  fun make_sign (typs, funs, preds) = Sign {
boehmes@32618
   413
    typs = map snd (Typtab.dest typs),
boehmes@32618
   414
    funs = map snd (Termtab.dest funs),
boehmes@32618
   415
    preds = map (apsnd fst o snd) (Termtab.dest preds) }
boehmes@32618
   416
  fun make_rtab (typs, funs, preds) =
boehmes@32618
   417
    let
boehmes@32618
   418
      val rTs = Typtab.dest typs |> map swap |> Symtab.make
boehmes@32618
   419
      val rts = Termtab.dest funs @ Termtab.dest preds
boehmes@32618
   420
        |> map (apfst fst o swap) |> Symtab.make
boehmes@32618
   421
    in Recon {typs=rTs, terms=rts} end
boehmes@32618
   422
boehmes@32618
   423
  fun either f g x = (case f x of NONE => g x | y => y)
boehmes@32618
   424
boehmes@32618
   425
  fun rep_typ (Builtins {builtin_typ, ...}) T (st as (vars, ns, sgn)) =
boehmes@32618
   426
    (case either builtin_typ (lookup_typ sgn) T of
boehmes@32618
   427
      SOME n => (n, st)
boehmes@32618
   428
    | NONE =>
boehmes@32618
   429
        let val (n, ns') = fresh_typ ns
boehmes@32618
   430
        in (n, (vars, ns', add_typ (T, n) sgn)) end)
boehmes@32618
   431
boehmes@32618
   432
  fun rep_var bs (n, T) (vars, ns, sgn) =
boehmes@32618
   433
    let val (n', vars') = fresh_name vars
boehmes@32618
   434
    in (vars', ns, sgn) |> rep_typ bs T |>> pair n' end
boehmes@32618
   435
boehmes@32618
   436
  fun rep_fun bs loc t T i (st as (_, _, sgn0)) =
boehmes@32618
   437
    (case lookup_fun loc sgn0 t of
boehmes@32618
   438
      SOME (n, _) => (n, st)
boehmes@32618
   439
    | NONE =>
boehmes@32618
   440
        let
boehmes@32618
   441
          val (Us, U) = dest_funT i T
boehmes@32618
   442
          val (uns, (vars, ns, sgn)) =
boehmes@32618
   443
            st |> fold_map (rep_typ bs) Us ||>> rep_typ bs U
boehmes@32618
   444
          val (n, ns') = fresh_fun loc ns
boehmes@32618
   445
        in (n, (vars, ns', add_fun loc (t, (n, uns)) sgn)) end)
boehmes@32618
   446
boehmes@32618
   447
  fun rep_num (bs as Builtins {builtin_num, ...}) (i, T) st =
boehmes@32618
   448
    (case builtin_num (i, T) of
boehmes@32618
   449
      SOME n => (n, st)
boehmes@32618
   450
    | NONE => rep_fun bs true (HOLogic.mk_number T i) T 0 st)
boehmes@32618
   451
in
boehmes@32618
   452
fun signature_of prefixes markers builtins thy ts =
boehmes@32618
   453
  let
boehmes@32618
   454
    val Prefixes {var_prefix, typ_prefix, fun_prefix, pred_prefix} = prefixes
boehmes@32618
   455
    val Markers {formula_marker, term_marker} = markers
boehmes@32618
   456
    val Builtins {builtin_fun, ...} = builtins
boehmes@32618
   457
boehmes@32618
   458
    fun sign loc t =
boehmes@32618
   459
      (case t of
boehmes@32618
   460
        SVar i => pair (SVar i)
boehmes@32618
   461
      | SApp (c as SConst (@{const_name term}, _), [u]) =>
boehmes@32618
   462
          sign true u #>> app term_marker o single
boehmes@32618
   463
      | SApp (c as SConst (@{const_name formula}, _), [u]) =>
boehmes@32618
   464
          sign false u #>> app formula_marker o single
boehmes@32618
   465
      | SApp (SConst (c as (_, T)), ts) =>
boehmes@32618
   466
          (case builtin_lookup (builtin_fun loc) thy c ts of
boehmes@32618
   467
            SOME (n, ts') => fold_map (sign loc) ts' #>> app n
boehmes@32618
   468
          | NONE =>
boehmes@32618
   469
              rep_fun builtins loc (Const c) T (length ts) ##>>
boehmes@32618
   470
              fold_map (sign loc) ts #>> SApp)
boehmes@32618
   471
      | SApp (SFree (c as (_, T)), ts) =>
boehmes@32618
   472
          rep_fun builtins loc (Free c) T (length ts) ##>>
boehmes@32618
   473
          fold_map (sign loc) ts #>> SApp
boehmes@32618
   474
      | SApp (SNum n, _) => rep_num builtins n #>> (fn n => SApp (n, []))
boehmes@32618
   475
      | SLet (v, u1, u2) =>
boehmes@32618
   476
          rep_var builtins v #-> (fn v' =>
boehmes@32618
   477
          sign loc u1 ##>> sign loc u2 #>> (fn (u1', u2') =>
boehmes@32618
   478
          SLet (v', u1', u2')))
boehmes@32618
   479
      | SQuant (q, vs, ps, u) =>
boehmes@32618
   480
          fold_map (rep_var builtins) vs ##>>
boehmes@32618
   481
          fold_map (fold_map_pat (sign loc)) ps ##>>
boehmes@32618
   482
          sign loc u #>> (fn ((vs', ps'), u') =>
boehmes@32618
   483
          SQuant (q, vs', ps', u')))
boehmes@32618
   484
  in
boehmes@32618
   485
    (empty_nctxt var_prefix, make_nctxt (typ_prefix, fun_prefix, pred_prefix),
boehmes@32618
   486
      empty_sign)
boehmes@32618
   487
    |> fold_map (sign false) ts
boehmes@32618
   488
    |> (fn (us, (_, _, sgn)) => (make_rtab sgn, (make_sign sgn, us)))
boehmes@32618
   489
  end
boehmes@32618
   490
end
boehmes@32618
   491
boehmes@32618
   492
boehmes@32618
   493
(* Combination of all translation functions and invocation of serialization. *)
boehmes@32618
   494
boehmes@32618
   495
fun translate config thy thms stream =
boehmes@32618
   496
  let val Config {strict, prefixes, markers, builtins, serialize} = config
boehmes@32618
   497
  in
boehmes@32618
   498
    map Thm.prop_of thms
boehmes@32618
   499
    |> SMT_Monomorph.monomorph thy
boehmes@32618
   500
    |> intermediate
boehmes@32618
   501
    |> (if strict then separate thy else pair [])
boehmes@32618
   502
    ||>> signature_of prefixes markers builtins thy
boehmes@32618
   503
    ||> (fn (sgn, ts) => serialize sgn ts stream)
boehmes@32618
   504
    |> (fn ((thms', rtab), _) => (rtab, thms' @ thms))
boehmes@32618
   505
  end
boehmes@32618
   506
boehmes@32618
   507
end