src/HOL/Tools/res_axioms.ML
author paulson
Thu Jan 04 17:55:12 2007 +0100 (2007-01-04)
changeset 21999 0cf192e489e2
parent 21900 f386d7eb17d1
child 22130 0906fd95e0b5
permissions -rw-r--r--
improvements to proof reconstruction. Some files loaded in a different order
paulson@15347
     1
(*  Author: Jia Meng, Cambridge University Computer Laboratory
paulson@15347
     2
    ID: $Id$
paulson@15347
     3
    Copyright 2004 University of Cambridge
paulson@15347
     4
wenzelm@20461
     5
Transformation of axiom rules (elim/intro/etc) into CNF forms.
paulson@15347
     6
*)
paulson@15347
     7
paulson@15997
     8
signature RES_AXIOMS =
wenzelm@21505
     9
sig
wenzelm@21505
    10
  val trace_abs: bool ref
wenzelm@21505
    11
  val cnf_axiom : string * thm -> thm list
paulson@21071
    12
  val cnf_name : string -> thm list
paulson@15997
    13
  val meta_cnf_axiom : thm -> thm list
wenzelm@21505
    14
  val pairname : thm -> string * thm
paulson@18510
    15
  val skolem_thm : thm -> thm list
paulson@20419
    16
  val to_nnf : thm -> thm
wenzelm@21505
    17
  val cnf_rules_pairs : (string * thm) list -> (thm * (string * int)) list
wenzelm@18708
    18
  val meson_method_setup : theory -> theory
wenzelm@18708
    19
  val setup : theory -> theory
wenzelm@21505
    20
  val assume_abstract_list: thm list -> thm list
paulson@21999
    21
  val neg_conjecture_clauses: thm -> int -> thm list * (string * typ) list
paulson@21999
    22
  val claset_rules_of: Proof.context -> (string * thm) list   (*FIXME DELETE*)
paulson@21999
    23
  val simpset_rules_of: Proof.context -> (string * thm) list  (*FIXME DELETE*)
wenzelm@21505
    24
  val atpset_rules_of: Proof.context -> (string * thm) list
wenzelm@21505
    25
end;
mengj@19196
    26
paulson@21900
    27
structure ResAxioms =
paulson@15997
    28
struct
paulson@15347
    29
paulson@20996
    30
(*For running the comparison between combinators and abstractions.
paulson@20996
    31
  CANNOT be a ref, as the setting is used while Isabelle is built.
paulson@20996
    32
  Currently FALSE, i.e. all the "abstraction" code below is unused, but so far
paulson@20996
    33
  it seems to be inferior to combinators...*)
paulson@21900
    34
val abstract_lambdas = true;
paulson@20419
    35
paulson@20419
    36
val trace_abs = ref false;
mengj@18000
    37
wenzelm@20902
    38
(* FIXME legacy *)
paulson@20863
    39
fun freeze_thm th = #1 (Drule.freeze_thaw th);
paulson@20863
    40
wenzelm@20902
    41
val lhs_of = #1 o Logic.dest_equals o Thm.prop_of;
wenzelm@20902
    42
val rhs_of = #2 o Logic.dest_equals o Thm.prop_of;
paulson@20863
    43
paulson@20863
    44
paulson@20445
    45
(*Store definitions of abstraction functions, ensuring that identical right-hand
paulson@20445
    46
  sides are denoted by the same functions and thereby reducing the need for
paulson@20445
    47
  extensionality in proofs.
paulson@20445
    48
  FIXME!  Store in theory data!!*)
paulson@20863
    49
paulson@20867
    50
(*Populate the abstraction cache with common combinators.*)
paulson@20863
    51
fun seed th net =
wenzelm@20902
    52
  let val (_,ct) = Thm.dest_abs NONE (Drule.rhs_of th)
paulson@20867
    53
      val t = Logic.legacy_varify (term_of ct)
paulson@20867
    54
  in  Net.insert_term eq_thm (t, th) net end;
paulson@20863
    55
  
paulson@20863
    56
val abstraction_cache = ref 
wenzelm@21254
    57
      (seed (thm"ATP_Linkup.I_simp") 
wenzelm@21254
    58
       (seed (thm"ATP_Linkup.B_simp") 
wenzelm@21254
    59
	(seed (thm"ATP_Linkup.K_simp") Net.empty)));
paulson@20867
    60
paulson@20445
    61
paulson@15997
    62
(**** Transformation of Elimination Rules into First-Order Formulas****)
paulson@15347
    63
paulson@21430
    64
val cfalse = cterm_of HOL.thy HOLogic.false_const;
paulson@21430
    65
val ctp_false = cterm_of HOL.thy (HOLogic.mk_Trueprop HOLogic.false_const);
wenzelm@20461
    66
paulson@21430
    67
(*Converts an elim-rule into an equivalent theorem that does not have the
paulson@21430
    68
  predicate variable.  Leaves other theorems unchanged.  We simply instantiate the
paulson@21430
    69
  conclusion variable to False.*)
paulson@16009
    70
fun transform_elim th =
paulson@21430
    71
  case concl_of th of    (*conclusion variable*)
paulson@21430
    72
       Const("Trueprop",_) $ (v as Var(_,Type("bool",[]))) => 
paulson@21430
    73
           Thm.instantiate ([], [(cterm_of HOL.thy v, cfalse)]) th
paulson@21430
    74
    | v as Var(_, Type("prop",[])) => 
paulson@21430
    75
           Thm.instantiate ([], [(cterm_of HOL.thy v, ctp_false)]) th
paulson@21430
    76
    | _ => th;
paulson@15997
    77
paulson@15997
    78
(**** Transformation of Clasets and Simpsets into First-Order Axioms ****)
paulson@15997
    79
wenzelm@21254
    80
(*Transfer a theorem into theory ATP_Linkup.thy if it is not already
paulson@15359
    81
  inside that theory -- because it's needed for Skolemization *)
paulson@15359
    82
wenzelm@21254
    83
(*This will refer to the final version of theory ATP_Linkup.*)
wenzelm@20461
    84
val recon_thy_ref = Theory.self_ref (the_context ());
paulson@15359
    85
wenzelm@21254
    86
(*If called while ATP_Linkup is being created, it will transfer to the
paulson@16563
    87
  current version. If called afterward, it will transfer to the final version.*)
wenzelm@21254
    88
fun transfer_to_ATP_Linkup th =
paulson@16563
    89
    transfer (Theory.deref recon_thy_ref) th handle THM _ => th;
paulson@15347
    90
wenzelm@20461
    91
paulson@16009
    92
(**** SKOLEMIZATION BY INFERENCE (lcp) ****)
paulson@16009
    93
paulson@18141
    94
(*Traverse a theorem, declaring Skolem function definitions. String s is the suggested
paulson@18141
    95
  prefix for the Skolem constant. Result is a new theory*)
paulson@18141
    96
fun declare_skofuns s th thy =
paulson@21071
    97
  let val nref = ref 0
paulson@21071
    98
      fun dec_sko (Const ("Ex",_) $ (xtp as Abs(_,T,p))) (thy, axs) =
wenzelm@20461
    99
            (*Existential: declare a Skolem function, then insert into body and continue*)
paulson@21071
   100
            let val cname = Name.internal (s ^ "_sko" ^ Int.toString (inc nref))
wenzelm@20461
   101
                val args = term_frees xtp  (*get the formal parameter list*)
wenzelm@20461
   102
                val Ts = map type_of args
wenzelm@20461
   103
                val cT = Ts ---> T
wenzelm@20461
   104
                val c = Const (Sign.full_name thy cname, cT)
wenzelm@20461
   105
                val rhs = list_abs_free (map dest_Free args, HOLogic.choice_const T $ xtp)
wenzelm@20461
   106
                        (*Forms a lambda-abstraction over the formal parameters*)
wenzelm@20783
   107
                val thy' = Sign.add_consts_authentic [(cname, cT, NoSyn)] thy
wenzelm@20461
   108
                           (*Theory is augmented with the constant, then its def*)
wenzelm@20461
   109
                val cdef = cname ^ "_def"
wenzelm@20461
   110
                val thy'' = Theory.add_defs_i false false [(cdef, equals cT $ c $ rhs)] thy'
wenzelm@20461
   111
            in dec_sko (subst_bound (list_comb(c,args), p))
wenzelm@20461
   112
                       (thy'', get_axiom thy'' cdef :: axs)
wenzelm@20461
   113
            end
wenzelm@20461
   114
        | dec_sko (Const ("All",_) $ (xtp as Abs(a,T,p))) thx =
wenzelm@20461
   115
            (*Universal quant: insert a free variable into body and continue*)
wenzelm@20461
   116
            let val fname = Name.variant (add_term_names (p,[])) a
wenzelm@20461
   117
            in dec_sko (subst_bound (Free(fname,T), p)) thx end
wenzelm@20461
   118
        | dec_sko (Const ("op &", _) $ p $ q) thx = dec_sko q (dec_sko p thx)
wenzelm@20461
   119
        | dec_sko (Const ("op |", _) $ p $ q) thx = dec_sko q (dec_sko p thx)
wenzelm@20461
   120
        | dec_sko (Const ("Trueprop", _) $ p) thx = dec_sko p thx
wenzelm@20461
   121
        | dec_sko t thx = thx (*Do nothing otherwise*)
paulson@20419
   122
  in  dec_sko (prop_of th) (thy,[])  end;
paulson@18141
   123
paulson@18141
   124
(*Traverse a theorem, accumulating Skolem function definitions.*)
paulson@18141
   125
fun assume_skofuns th =
paulson@18141
   126
  let fun dec_sko (Const ("Ex",_) $ (xtp as Abs(_,T,p))) defs =
wenzelm@20461
   127
            (*Existential: declare a Skolem function, then insert into body and continue*)
wenzelm@20461
   128
            let val skos = map (#1 o Logic.dest_equals) defs  (*existing sko fns*)
wenzelm@20461
   129
                val args = term_frees xtp \\ skos  (*the formal parameters*)
wenzelm@20461
   130
                val Ts = map type_of args
wenzelm@20461
   131
                val cT = Ts ---> T
wenzelm@20461
   132
                val c = Free (gensym "sko_", cT)
wenzelm@20461
   133
                val rhs = list_abs_free (map dest_Free args,
wenzelm@20461
   134
                                         HOLogic.choice_const T $ xtp)
wenzelm@20461
   135
                      (*Forms a lambda-abstraction over the formal parameters*)
wenzelm@20461
   136
                val def = equals cT $ c $ rhs
wenzelm@20461
   137
            in dec_sko (subst_bound (list_comb(c,args), p))
wenzelm@20461
   138
                       (def :: defs)
wenzelm@20461
   139
            end
wenzelm@20461
   140
        | dec_sko (Const ("All",_) $ (xtp as Abs(a,T,p))) defs =
wenzelm@20461
   141
            (*Universal quant: insert a free variable into body and continue*)
wenzelm@20461
   142
            let val fname = Name.variant (add_term_names (p,[])) a
wenzelm@20461
   143
            in dec_sko (subst_bound (Free(fname,T), p)) defs end
wenzelm@20461
   144
        | dec_sko (Const ("op &", _) $ p $ q) defs = dec_sko q (dec_sko p defs)
wenzelm@20461
   145
        | dec_sko (Const ("op |", _) $ p $ q) defs = dec_sko q (dec_sko p defs)
wenzelm@20461
   146
        | dec_sko (Const ("Trueprop", _) $ p) defs = dec_sko p defs
wenzelm@20461
   147
        | dec_sko t defs = defs (*Do nothing otherwise*)
paulson@20419
   148
  in  dec_sko (prop_of th) []  end;
paulson@20419
   149
paulson@20419
   150
paulson@20419
   151
(**** REPLACING ABSTRACTIONS BY FUNCTION DEFINITIONS ****)
paulson@20419
   152
paulson@20419
   153
(*Returns the vars of a theorem*)
paulson@20419
   154
fun vars_of_thm th =
paulson@20445
   155
  map (Thm.cterm_of (theory_of_thm th) o Var) (Drule.fold_terms Term.add_vars th []);
paulson@20419
   156
paulson@20419
   157
(*Make a version of fun_cong with a given variable name*)
paulson@20419
   158
local
paulson@20419
   159
    val fun_cong' = fun_cong RS asm_rl; (*renumber f, g to prevent clashes with (a,0)*)
paulson@20419
   160
    val cx = hd (vars_of_thm fun_cong');
paulson@20419
   161
    val ty = typ_of (ctyp_of_term cx);
paulson@20445
   162
    val thy = theory_of_thm fun_cong;
paulson@20419
   163
    fun mkvar a = cterm_of thy (Var((a,0),ty));
paulson@20419
   164
in
paulson@20419
   165
fun xfun_cong x = Thm.instantiate ([], [(cx, mkvar x)]) fun_cong'
paulson@20419
   166
end;
paulson@20419
   167
paulson@20863
   168
(*Removes the lambdas from an equation of the form t = (%x. u).  A non-negative n,
paulson@20863
   169
  serves as an upper bound on how many to remove.*)
paulson@20863
   170
fun strip_lambdas 0 th = th
paulson@20863
   171
  | strip_lambdas n th = 
paulson@20863
   172
      case prop_of th of
paulson@20863
   173
	  _ $ (Const ("op =", _) $ _ $ Abs (x,_,_)) =>
paulson@20863
   174
	      strip_lambdas (n-1) (freeze_thm (th RS xfun_cong x))
paulson@20863
   175
	| _ => th;
paulson@20419
   176
wenzelm@20461
   177
(*Convert meta- to object-equality. Fails for theorems like split_comp_eq,
paulson@20419
   178
  where some types have the empty sort.*)
paulson@20863
   179
fun mk_object_eq th = th RS def_imp_eq
paulson@20419
   180
    handle THM _ => error ("Theorem contains empty sort: " ^ string_of_thm th);
wenzelm@20461
   181
paulson@20419
   182
(*Apply a function definition to an argument, beta-reducing the result.*)
paulson@20419
   183
fun beta_comb cf x =
paulson@20419
   184
  let val th1 = combination cf (reflexive x)
wenzelm@20902
   185
      val th2 = beta_conversion false (Drule.rhs_of th1)
paulson@20419
   186
  in  transitive th1 th2  end;
paulson@20419
   187
paulson@20419
   188
(*Apply a function definition to arguments, beta-reducing along the way.*)
paulson@20419
   189
fun list_combination cf [] = cf
paulson@20419
   190
  | list_combination cf (x::xs) = list_combination (beta_comb cf x) xs;
paulson@20419
   191
paulson@20419
   192
fun list_cabs ([] ,     t) = t
paulson@20419
   193
  | list_cabs (v::vars, t) = Thm.cabs v (list_cabs(vars,t));
paulson@20419
   194
wenzelm@20461
   195
fun assert_eta_free ct =
wenzelm@20461
   196
  let val t = term_of ct
wenzelm@20461
   197
  in if (t aconv Envir.eta_contract t) then ()
paulson@20419
   198
     else error ("Eta redex in term: " ^ string_of_cterm ct)
paulson@20419
   199
  end;
paulson@20419
   200
wenzelm@20461
   201
fun eq_absdef (th1, th2) =
paulson@20445
   202
    Context.joinable (theory_of_thm th1, theory_of_thm th2)  andalso
paulson@20445
   203
    rhs_of th1 aconv rhs_of th2;
paulson@20445
   204
paulson@20445
   205
fun lambda_free (Abs _) = false
paulson@20445
   206
  | lambda_free (t $ u) = lambda_free t andalso lambda_free u
paulson@20445
   207
  | lambda_free _ = true;
wenzelm@20461
   208
wenzelm@20461
   209
fun monomorphic t =
wenzelm@20461
   210
  Term.fold_types (Term.fold_atyps (fn TVar _ => K false | _ => I)) t true;
wenzelm@20461
   211
paulson@20710
   212
fun dest_abs_list ct =
paulson@20710
   213
  let val (cv,ct') = Thm.dest_abs NONE ct
paulson@20710
   214
      val (cvs,cu) = dest_abs_list ct'
paulson@20710
   215
  in (cv::cvs, cu) end
paulson@20710
   216
  handle CTERM _ => ([],ct);
paulson@20710
   217
paulson@20710
   218
fun lambda_list [] u = u
paulson@20710
   219
  | lambda_list (v::vs) u = lambda v (lambda_list vs u);
paulson@20710
   220
paulson@20710
   221
fun abstract_rule_list [] [] th = th
paulson@20710
   222
  | abstract_rule_list (v::vs) (ct::cts) th = abstract_rule v ct (abstract_rule_list vs cts th)
paulson@20710
   223
  | abstract_rule_list _ _ th = raise THM ("abstract_rule_list", 0, [th]);
paulson@20710
   224
paulson@20863
   225
paulson@20863
   226
val Envir.Envir {asol = tenv0, iTs = tyenv0, ...} = Envir.empty 0
paulson@20863
   227
paulson@20969
   228
(*Does an existing abstraction definition have an RHS that matches the one we need now?
paulson@20969
   229
  thy is the current theory, which must extend that of theorem th.*)
paulson@20969
   230
fun match_rhs thy t th =
paulson@20969
   231
  let val _ = if !trace_abs then warning ("match_rhs: " ^ string_of_cterm (cterm_of thy t) ^ 
paulson@20863
   232
                                          " against\n" ^ string_of_thm th) else ();
paulson@20867
   233
      val (tyenv,tenv) = Pattern.first_order_match thy (rhs_of th, t) (tyenv0,tenv0)
paulson@20863
   234
      val term_insts = map Meson.term_pair_of (Vartab.dest tenv)
paulson@20969
   235
      val ct_pairs = if subthy (theory_of_thm th, thy) andalso 
paulson@20969
   236
                        forall lambda_free (map #2 term_insts) 
paulson@20969
   237
                     then map (pairself (cterm_of thy)) term_insts
paulson@20863
   238
                     else raise Pattern.MATCH (*Cannot allow lambdas in the instantiation*)
paulson@20863
   239
      fun ctyp2 (ixn, (S, T)) = (ctyp_of thy (TVar (ixn, S)), ctyp_of thy T)
paulson@20863
   240
      val th' = cterm_instantiate ct_pairs th
paulson@20863
   241
  in  SOME (th, instantiate (map ctyp2 (Vartab.dest tyenv), []) th')  end
paulson@20863
   242
  handle _ => NONE;
paulson@20863
   243
paulson@20419
   244
(*Traverse a theorem, declaring abstraction function definitions. String s is the suggested
paulson@20419
   245
  prefix for the constants. Resulting theory is returned in the first theorem. *)
paulson@20419
   246
fun declare_absfuns th =
wenzelm@20461
   247
  let fun abstract thy ct =
paulson@20445
   248
        if lambda_free (term_of ct) then (transfer thy (reflexive ct), [])
paulson@20445
   249
        else
paulson@20445
   250
        case term_of ct of
paulson@20710
   251
          Abs _ =>
wenzelm@20624
   252
            let val cname = Name.internal (gensym "abs_");
wenzelm@20461
   253
                val _ = assert_eta_free ct;
paulson@20710
   254
                val (cvs,cta) = dest_abs_list ct
paulson@20710
   255
                val (vs,Tvs) = ListPair.unzip (map (dest_Free o term_of) cvs)
paulson@20863
   256
                val _ = if !trace_abs then warning ("Nested lambda: " ^ string_of_cterm cta) else ();
wenzelm@20461
   257
                val (u'_th,defs) = abstract thy cta
paulson@20863
   258
                val _ = if !trace_abs then warning ("Returned " ^ string_of_thm u'_th) else ();
wenzelm@20902
   259
                val cu' = Drule.rhs_of u'_th
paulson@20863
   260
                val u' = term_of cu'
paulson@20863
   261
                val abs_v_u = lambda_list (map term_of cvs) u'
wenzelm@20461
   262
                (*get the formal parameters: ALL variables free in the term*)
wenzelm@20461
   263
                val args = term_frees abs_v_u
paulson@20863
   264
                val _ = if !trace_abs then warning (Int.toString (length args) ^ " arguments") else ();
wenzelm@20461
   265
                val rhs = list_abs_free (map dest_Free args, abs_v_u)
wenzelm@20461
   266
                      (*Forms a lambda-abstraction over the formal parameters*)
paulson@20863
   267
                val _ = if !trace_abs then warning ("Looking up " ^ string_of_cterm cu') else ();
paulson@20969
   268
                val thy = theory_of_thm u'_th
paulson@20863
   269
                val (ax,ax',thy) =
paulson@20969
   270
                 case List.mapPartial (match_rhs thy abs_v_u) 
paulson@20969
   271
                         (Net.match_term (!abstraction_cache) u') of
paulson@20863
   272
                     (ax,ax')::_ => 
paulson@20863
   273
                       (if !trace_abs then warning ("Re-using axiom " ^ string_of_thm ax) else ();
paulson@20863
   274
                        (ax,ax',thy))
paulson@20863
   275
                   | [] =>
paulson@20863
   276
                      let val _ = if !trace_abs then warning "Lookup was empty" else ();
paulson@20863
   277
                          val Ts = map type_of args
paulson@20710
   278
                          val cT = Ts ---> (Tvs ---> typ_of (ctyp_of_term cu'))
wenzelm@20461
   279
                          val c = Const (Sign.full_name thy cname, cT)
wenzelm@20783
   280
                          val thy = Sign.add_consts_authentic [(cname, cT, NoSyn)] thy
wenzelm@20461
   281
                                     (*Theory is augmented with the constant,
wenzelm@20461
   282
                                       then its definition*)
wenzelm@20461
   283
                          val cdef = cname ^ "_def"
wenzelm@20461
   284
                          val thy = Theory.add_defs_i false false
wenzelm@20461
   285
                                       [(cdef, equals cT $ c $ rhs)] thy
paulson@20863
   286
                          val _ = if !trace_abs then (warning ("Definition is " ^ 
paulson@20863
   287
                                                      string_of_thm (get_axiom thy cdef))) 
paulson@20863
   288
                                  else ();
paulson@20863
   289
                          val ax = get_axiom thy cdef |> freeze_thm
paulson@20863
   290
                                     |> mk_object_eq |> strip_lambdas (length args)
paulson@20863
   291
                                     |> mk_meta_eq |> Meson.generalize
paulson@20969
   292
                          val (_,ax') = Option.valOf (match_rhs thy abs_v_u ax)
paulson@20863
   293
                          val _ = if !trace_abs then 
paulson@20863
   294
                                    (warning ("Declaring: " ^ string_of_thm ax);
paulson@20863
   295
                                     warning ("Instance: " ^ string_of_thm ax')) 
paulson@20863
   296
                                  else ();
paulson@20863
   297
                          val _ = abstraction_cache := Net.insert_term eq_absdef 
paulson@20863
   298
                                            ((Logic.varify u'), ax) (!abstraction_cache)
wenzelm@20461
   299
                            handle Net.INSERT =>
wenzelm@20461
   300
                              raise THM ("declare_absfuns: INSERT", 0, [th,u'_th,ax])
paulson@20863
   301
                       in  (ax,ax',thy)  end
paulson@20863
   302
            in if !trace_abs then warning ("Lookup result: " ^ string_of_thm ax') else ();
paulson@20863
   303
               (transitive (abstract_rule_list vs cvs u'_th) (symmetric ax'), ax::defs) end
wenzelm@20461
   304
        | (t1$t2) =>
wenzelm@20461
   305
            let val (ct1,ct2) = Thm.dest_comb ct
wenzelm@20461
   306
                val (th1,defs1) = abstract thy ct1
wenzelm@20461
   307
                val (th2,defs2) = abstract (theory_of_thm th1) ct2
wenzelm@20461
   308
            in  (combination th1 th2, defs1@defs2)  end
paulson@20863
   309
      val _ = if !trace_abs then warning ("declare_absfuns, Abstracting: " ^ string_of_thm th) else ();
paulson@20419
   310
      val (eqth,defs) = abstract (theory_of_thm th) (cprop_of th)
paulson@20863
   311
      val ths = equal_elim eqth th :: map (strip_lambdas ~1 o mk_object_eq o freeze_thm) defs
paulson@20863
   312
      val _ = if !trace_abs then warning ("declare_absfuns, Result: " ^ string_of_thm (hd ths)) else ();
paulson@20863
   313
  in  (theory_of_thm eqth, map Drule.eta_contraction_rule ths)  end;
paulson@20419
   314
wenzelm@20902
   315
fun name_of def = try (#1 o dest_Free o lhs_of) def;
paulson@20567
   316
paulson@20525
   317
(*A name is valid provided it isn't the name of a defined abstraction.*)
paulson@20567
   318
fun valid_name defs (Free(x,T)) = not (x mem_string (List.mapPartial name_of defs))
paulson@20525
   319
  | valid_name defs _ = false;
paulson@20525
   320
paulson@20419
   321
fun assume_absfuns th =
paulson@20445
   322
  let val thy = theory_of_thm th
paulson@20445
   323
      val cterm = cterm_of thy
paulson@20525
   324
      fun abstract ct =
paulson@20445
   325
        if lambda_free (term_of ct) then (reflexive ct, [])
paulson@20445
   326
        else
paulson@20445
   327
        case term_of ct of
paulson@20419
   328
          Abs (_,T,u) =>
paulson@20710
   329
            let val _ = assert_eta_free ct;
paulson@20710
   330
                val (cvs,cta) = dest_abs_list ct
paulson@20710
   331
                val (vs,Tvs) = ListPair.unzip (map (dest_Free o term_of) cvs)
paulson@20525
   332
                val (u'_th,defs) = abstract cta
wenzelm@20902
   333
                val cu' = Drule.rhs_of u'_th
paulson@20863
   334
                val u' = term_of cu'
paulson@20710
   335
                (*Could use Thm.cabs instead of lambda to work at level of cterms*)
paulson@20710
   336
                val abs_v_u = lambda_list (map term_of cvs) (term_of cu')
paulson@20525
   337
                (*get the formal parameters: free variables not present in the defs
paulson@20525
   338
                  (to avoid taking abstraction function names as parameters) *)
paulson@20710
   339
                val args = filter (valid_name defs) (term_frees abs_v_u)
paulson@20710
   340
                val crhs = list_cabs (map cterm args, cterm abs_v_u)
wenzelm@20461
   341
                      (*Forms a lambda-abstraction over the formal parameters*)
wenzelm@20461
   342
                val rhs = term_of crhs
paulson@20863
   343
                val (ax,ax') =
paulson@20969
   344
                 case List.mapPartial (match_rhs thy abs_v_u) 
paulson@20863
   345
                        (Net.match_term (!abstraction_cache) u') of
paulson@20863
   346
                     (ax,ax')::_ => 
paulson@20863
   347
                       (if !trace_abs then warning ("Re-using axiom " ^ string_of_thm ax) else ();
paulson@20863
   348
                        (ax,ax'))
paulson@20863
   349
                   | [] =>
wenzelm@20461
   350
                      let val Ts = map type_of args
paulson@20710
   351
                          val const_ty = Ts ---> (Tvs ---> typ_of (ctyp_of_term cu'))
wenzelm@20461
   352
                          val c = Free (gensym "abs_", const_ty)
wenzelm@20461
   353
                          val ax = assume (Thm.capply (cterm (equals const_ty $ c)) crhs)
paulson@20863
   354
                                     |> mk_object_eq |> strip_lambdas (length args)
paulson@20863
   355
                                     |> mk_meta_eq |> Meson.generalize
paulson@20969
   356
                          val (_,ax') = Option.valOf (match_rhs thy abs_v_u ax)
wenzelm@20461
   357
                          val _ = abstraction_cache := Net.insert_term eq_absdef (rhs,ax)
wenzelm@20461
   358
                                    (!abstraction_cache)
wenzelm@20461
   359
                            handle Net.INSERT =>
wenzelm@20461
   360
                              raise THM ("assume_absfuns: INSERT", 0, [th,u'_th,ax])
paulson@20863
   361
                      in (ax,ax') end
paulson@20863
   362
            in if !trace_abs then warning ("Lookup result: " ^ string_of_thm ax') else ();
paulson@20863
   363
               (transitive (abstract_rule_list vs cvs u'_th) (symmetric ax'), ax::defs) end
wenzelm@20461
   364
        | (t1$t2) =>
wenzelm@20461
   365
            let val (ct1,ct2) = Thm.dest_comb ct
paulson@20525
   366
                val (t1',defs1) = abstract ct1
paulson@20525
   367
                val (t2',defs2) = abstract ct2
wenzelm@20461
   368
            in  (combination t1' t2', defs1@defs2)  end
paulson@20863
   369
      val _ = if !trace_abs then warning ("assume_absfuns, Abstracting: " ^ string_of_thm th) else ();
paulson@20525
   370
      val (eqth,defs) = abstract (cprop_of th)
paulson@20863
   371
      val ths = equal_elim eqth th :: map (strip_lambdas ~1 o mk_object_eq o freeze_thm) defs
paulson@20863
   372
      val _ = if !trace_abs then warning ("assume_absfuns, Result: " ^ string_of_thm (hd ths)) else ();
paulson@20863
   373
  in  map Drule.eta_contraction_rule ths  end;
paulson@20419
   374
paulson@16009
   375
paulson@16009
   376
(*cterms are used throughout for efficiency*)
paulson@18141
   377
val cTrueprop = Thm.cterm_of HOL.thy HOLogic.Trueprop;
paulson@16009
   378
paulson@16009
   379
(*cterm version of mk_cTrueprop*)
paulson@16009
   380
fun c_mkTrueprop A = Thm.capply cTrueprop A;
paulson@16009
   381
paulson@16009
   382
(*Given an abstraction over n variables, replace the bound variables by free
paulson@16009
   383
  ones. Return the body, along with the list of free variables.*)
wenzelm@20461
   384
fun c_variant_abs_multi (ct0, vars) =
paulson@16009
   385
      let val (cv,ct) = Thm.dest_abs NONE ct0
paulson@16009
   386
      in  c_variant_abs_multi (ct, cv::vars)  end
paulson@16009
   387
      handle CTERM _ => (ct0, rev vars);
paulson@16009
   388
wenzelm@20461
   389
(*Given the definition of a Skolem function, return a theorem to replace
wenzelm@20461
   390
  an existential formula by a use of that function.
paulson@18141
   391
   Example: "EX x. x : A & x ~: B ==> sko A B : A & sko A B ~: B"  [.] *)
wenzelm@20461
   392
fun skolem_of_def def =
paulson@20863
   393
  let val (c,rhs) = Drule.dest_equals (cprop_of (freeze_thm def))
paulson@16009
   394
      val (ch, frees) = c_variant_abs_multi (rhs, [])
paulson@18141
   395
      val (chilbert,cabs) = Thm.dest_comb ch
paulson@18141
   396
      val {sign,t, ...} = rep_cterm chilbert
paulson@18141
   397
      val T = case t of Const ("Hilbert_Choice.Eps", Type("fun",[_,T])) => T
paulson@18141
   398
                      | _ => raise THM ("skolem_of_def: expected Eps", 0, [def])
paulson@16009
   399
      val cex = Thm.cterm_of sign (HOLogic.exists_const T)
paulson@16009
   400
      val ex_tm = c_mkTrueprop (Thm.capply cex cabs)
paulson@16009
   401
      and conc =  c_mkTrueprop (Drule.beta_conv cabs (Drule.list_comb(c,frees)));
paulson@18141
   402
      fun tacf [prem] = rewrite_goals_tac [def] THEN rtac (prem RS someI_ex) 1
wenzelm@20461
   403
  in  Goal.prove_raw [ex_tm] conc tacf
paulson@18141
   404
       |> forall_intr_list frees
paulson@18141
   405
       |> forall_elim_vars 0  (*Introduce Vars, but don't discharge defs.*)
paulson@18141
   406
       |> Thm.varifyT
paulson@18141
   407
  end;
paulson@16009
   408
paulson@20863
   409
(*Converts an Isabelle theorem (intro, elim or simp format, even higher-order) into NNF.*)
wenzelm@20461
   410
fun to_nnf th =
wenzelm@21254
   411
    th |> transfer_to_ATP_Linkup
paulson@20863
   412
       |> transform_elim |> zero_var_indexes |> freeze_thm
paulson@20863
   413
       |> ObjectLogic.atomize_thm |> make_nnf |> strip_lambdas ~1;
paulson@16009
   414
wenzelm@20461
   415
(*The cache prevents repeated clausification of a theorem,
wenzelm@20461
   416
  and also repeated declaration of Skolem functions*)
paulson@18510
   417
  (* FIXME better use Termtab!? No, we MUST use theory data!!*)
paulson@15955
   418
val clause_cache = ref (Symtab.empty : (thm * thm list) Symtab.table)
paulson@15955
   419
paulson@18141
   420
paulson@18141
   421
(*Generate Skolem functions for a theorem supplied in nnf*)
paulson@18141
   422
fun skolem_of_nnf th =
paulson@18141
   423
  map (skolem_of_def o assume o (cterm_of (theory_of_thm th))) (assume_skofuns th);
paulson@18141
   424
paulson@20863
   425
fun assert_lambda_free ths msg = 
paulson@20863
   426
  case filter (not o lambda_free o prop_of) ths of
paulson@20863
   427
      [] => ()
paulson@20863
   428
     | ths' => error (msg ^ "\n" ^ space_implode "\n" (map string_of_thm ths'));
paulson@20457
   429
paulson@20445
   430
fun assume_abstract th =
paulson@20457
   431
  if lambda_free (prop_of th) then [th]
paulson@20863
   432
  else th |> Drule.eta_contraction_rule |> assume_absfuns
paulson@20457
   433
          |> tap (fn ths => assert_lambda_free ths "assume_abstract: lambdas")
paulson@20445
   434
paulson@20419
   435
(*Replace lambdas by assumed function definitions in the theorems*)
paulson@20445
   436
fun assume_abstract_list ths =
paulson@20445
   437
  if abstract_lambdas then List.concat (map assume_abstract ths)
paulson@20863
   438
  else map Drule.eta_contraction_rule ths;
paulson@20419
   439
paulson@20419
   440
(*Replace lambdas by declared function definitions in the theorems*)
paulson@20419
   441
fun declare_abstract' (thy, []) = (thy, [])
paulson@20419
   442
  | declare_abstract' (thy, th::ths) =
wenzelm@20461
   443
      let val (thy', th_defs) =
paulson@20457
   444
            if lambda_free (prop_of th) then (thy, [th])
paulson@20445
   445
            else
paulson@20863
   446
                th |> zero_var_indexes |> freeze_thm
paulson@20863
   447
                   |> Drule.eta_contraction_rule |> transfer thy |> declare_absfuns
wenzelm@20461
   448
          val _ = assert_lambda_free th_defs "declare_abstract: lambdas"
wenzelm@20461
   449
          val (thy'', ths') = declare_abstract' (thy', ths)
paulson@20419
   450
      in  (thy'', th_defs @ ths')  end;
paulson@20419
   451
paulson@20419
   452
fun declare_abstract (thy, ths) =
paulson@20419
   453
  if abstract_lambdas then declare_abstract' (thy, ths)
paulson@20863
   454
  else (thy, map Drule.eta_contraction_rule ths);
paulson@20419
   455
paulson@18510
   456
(*Skolemize a named theorem, with Skolem functions as additional premises.*)
wenzelm@20461
   457
fun skolem_thm th =
paulson@18510
   458
  let val nnfth = to_nnf th
paulson@21470
   459
  in  Meson.make_cnf (skolem_of_nnf nnfth) nnfth |> assume_abstract_list |> Meson.finish_cnf
paulson@18510
   460
  end
paulson@18510
   461
  handle THM _ => [];
paulson@18141
   462
paulson@21071
   463
(*Keep the full complexity of the original name*)
wenzelm@21858
   464
fun flatten_name s = space_implode "_X" (NameSpace.explode s);
paulson@21071
   465
paulson@18510
   466
(*Declare Skolem functions for a theorem, supplied in nnf and with its name.
paulson@18510
   467
  It returns a modified theory, unless skolemization fails.*)
paulson@16009
   468
fun skolem thy (name,th) =
paulson@21071
   469
  let val cname = (case name of "" => gensym "" | s => flatten_name s)
paulson@20419
   470
      val _ = Output.debug ("skolemizing " ^ name ^ ": ")
wenzelm@20461
   471
  in Option.map
wenzelm@20461
   472
        (fn nnfth =>
paulson@18141
   473
          let val (thy',defs) = declare_skofuns cname nnfth thy
paulson@20419
   474
              val cnfs = Meson.make_cnf (map skolem_of_def defs) nnfth
paulson@20419
   475
              val (thy'',cnfs') = declare_abstract (thy',cnfs)
paulson@21470
   476
          in (thy'', Meson.finish_cnf cnfs')
paulson@20419
   477
          end)
wenzelm@20461
   478
      (SOME (to_nnf th)  handle THM _ => NONE)
paulson@18141
   479
  end;
paulson@16009
   480
paulson@18510
   481
(*Populate the clause cache using the supplied theorem. Return the clausal form
paulson@18510
   482
  and modified theory.*)
wenzelm@20461
   483
fun skolem_cache_thm (name,th) thy =
paulson@18144
   484
  case Symtab.lookup (!clause_cache) name of
wenzelm@20461
   485
      NONE =>
wenzelm@20461
   486
        (case skolem thy (name, Thm.transfer thy th) of
wenzelm@20461
   487
             NONE => ([th],thy)
paulson@20473
   488
           | SOME (thy',cls) => 
wenzelm@21602
   489
               let val cls = map Goal.close_result cls
paulson@20473
   490
               in
paulson@20473
   491
                  if null cls then warning ("skolem_cache: empty clause set for " ^ name)
paulson@20473
   492
                  else ();
paulson@20473
   493
                  change clause_cache (Symtab.update (name, (th, cls))); 
paulson@20473
   494
                  (cls,thy')
paulson@20473
   495
               end)
paulson@18144
   496
    | SOME (th',cls) =>
paulson@18510
   497
        if eq_thm(th,th') then (cls,thy)
wenzelm@20461
   498
        else (Output.debug ("skolem_cache: Ignoring variant of theorem " ^ name);
wenzelm@20461
   499
              Output.debug (string_of_thm th);
wenzelm@20461
   500
              Output.debug (string_of_thm th');
wenzelm@20461
   501
              ([th],thy));
wenzelm@20461
   502
wenzelm@20461
   503
(*Exported function to convert Isabelle theorems into axiom clauses*)
paulson@19894
   504
fun cnf_axiom (name,th) =
paulson@21071
   505
 (Output.debug ("cnf_axiom called, theorem name = " ^ name);
paulson@18144
   506
  case name of
wenzelm@20461
   507
        "" => skolem_thm th (*no name, so can't cache*)
paulson@18144
   508
      | s  => case Symtab.lookup (!clause_cache) s of
paulson@20473
   509
                NONE => 
wenzelm@21602
   510
                  let val cls = map Goal.close_result (skolem_thm th)
paulson@21071
   511
                  in Output.debug "inserted into cache";
paulson@21071
   512
                     change clause_cache (Symtab.update (s, (th, cls))); cls 
paulson@21071
   513
                  end
wenzelm@20461
   514
              | SOME(th',cls) =>
wenzelm@20461
   515
                  if eq_thm(th,th') then cls
wenzelm@20461
   516
                  else (Output.debug ("cnf_axiom: duplicate or variant of theorem " ^ name);
wenzelm@20461
   517
                        Output.debug (string_of_thm th);
wenzelm@20461
   518
                        Output.debug (string_of_thm th');
paulson@21071
   519
                        cls)
paulson@21071
   520
 );
paulson@15347
   521
wenzelm@21646
   522
fun pairname th = (PureThy.get_name_hint th, th);
paulson@18141
   523
paulson@21071
   524
(*Principally for debugging*)
paulson@21071
   525
fun cnf_name s = 
paulson@21071
   526
  let val th = thm s
wenzelm@21646
   527
  in cnf_axiom (PureThy.get_name_hint th, th) end;
paulson@15347
   528
paulson@15872
   529
(**** Extract and Clausify theorems from a theory's claset and simpset ****)
paulson@15347
   530
paulson@17484
   531
fun rules_of_claset cs =
paulson@17484
   532
  let val {safeIs,safeEs,hazIs,hazEs,...} = rep_cs cs
paulson@19175
   533
      val intros = safeIs @ hazIs
wenzelm@18532
   534
      val elims  = map Classical.classical_rule (safeEs @ hazEs)
paulson@17404
   535
  in
wenzelm@20461
   536
     Output.debug ("rules_of_claset intros: " ^ Int.toString(length intros) ^
paulson@17484
   537
            " elims: " ^ Int.toString(length elims));
paulson@20017
   538
     map pairname (intros @ elims)
paulson@17404
   539
  end;
paulson@15347
   540
paulson@17484
   541
fun rules_of_simpset ss =
paulson@17484
   542
  let val ({rules,...}, _) = rep_ss ss
paulson@17484
   543
      val simps = Net.entries rules
wenzelm@20461
   544
  in
wenzelm@18680
   545
      Output.debug ("rules_of_simpset: " ^ Int.toString(length simps));
paulson@17484
   546
      map (fn r => (#name r, #thm r)) simps
paulson@17484
   547
  end;
paulson@17484
   548
wenzelm@21505
   549
fun claset_rules_of ctxt = rules_of_claset (local_claset_of ctxt);
wenzelm@21505
   550
fun simpset_rules_of ctxt = rules_of_simpset (local_simpset_of ctxt);
mengj@19196
   551
wenzelm@21505
   552
fun atpset_rules_of ctxt = map pairname (ResAtpset.get_atpset ctxt);
wenzelm@20774
   553
paulson@15347
   554
paulson@15872
   555
(**** Translate a set of classical/simplifier rules into CNF (still as type "thm")  ****)
paulson@15347
   556
paulson@19894
   557
(* classical rules: works for both FOL and HOL *)
paulson@19894
   558
fun cnf_rules [] err_list = ([],err_list)
wenzelm@20461
   559
  | cnf_rules ((name,th) :: ths) err_list =
paulson@19894
   560
      let val (ts,es) = cnf_rules ths err_list
wenzelm@20461
   561
      in  (cnf_axiom (name,th) :: ts,es) handle  _ => (ts, (th::es))  end;
paulson@15347
   562
paulson@19894
   563
fun pair_name_cls k (n, []) = []
paulson@19894
   564
  | pair_name_cls k (n, cls::clss) = (cls, (n,k)) :: pair_name_cls (k+1) (n, clss)
wenzelm@20461
   565
paulson@19894
   566
fun cnf_rules_pairs_aux pairs [] = pairs
paulson@19894
   567
  | cnf_rules_pairs_aux pairs ((name,th)::ths) =
paulson@20457
   568
      let val pairs' = (pair_name_cls 0 (name, cnf_axiom(name,th))) @ pairs
wenzelm@20461
   569
                       handle THM _ => pairs | ResClause.CLAUSE _ => pairs
paulson@19894
   570
      in  cnf_rules_pairs_aux pairs' ths  end;
wenzelm@20461
   571
paulson@21290
   572
(*The combination of rev and tail recursion preserves the original order*)
paulson@21290
   573
fun cnf_rules_pairs l = cnf_rules_pairs_aux [] (rev l);
mengj@19353
   574
mengj@19196
   575
mengj@18198
   576
(**** Convert all theorems of a claset/simpset into clauses (ResClause.clause, or ResHolClause.clause) ****)
paulson@15347
   577
paulson@20419
   578
(*Setup function: takes a theory and installs ALL known theorems into the clause cache*)
paulson@20457
   579
wenzelm@20461
   580
fun skolem_cache (name,th) thy =
wenzelm@20461
   581
  let val prop = Thm.prop_of th
paulson@20457
   582
  in
paulson@21071
   583
      if lambda_free prop 
paulson@20969
   584
         (*Monomorphic theorems can be Skolemized on demand,
paulson@20867
   585
           but there are problems with re-use of abstraction functions if we don't
paulson@20867
   586
           do them now, even for monomorphic theorems.*)
paulson@20867
   587
      then thy  
wenzelm@20461
   588
      else #2 (skolem_cache_thm (name,th) thy)
paulson@20457
   589
  end;
paulson@20457
   590
paulson@21071
   591
(*The cache can be kept smaller by augmenting the condition above with 
paulson@21071
   592
    orelse (not abstract_lambdas andalso monomorphic prop).
paulson@21071
   593
  However, while this step does not reduce the time needed to build HOL, 
paulson@21071
   594
  it doubles the time taken by the first call to the ATP link-up.*)
paulson@21071
   595
wenzelm@20461
   596
fun clause_cache_setup thy = fold skolem_cache (PureThy.all_thms_of thy) thy;
wenzelm@20461
   597
paulson@16563
   598
paulson@16563
   599
(*** meson proof methods ***)
paulson@16563
   600
paulson@21071
   601
fun skolem_use_cache_thm th =
wenzelm@21646
   602
  case Symtab.lookup (!clause_cache) (PureThy.get_name_hint th) of
paulson@21071
   603
      NONE => skolem_thm th
paulson@21071
   604
    | SOME (th',cls) =>
paulson@21071
   605
        if eq_thm(th,th') then cls else skolem_thm th;
paulson@21071
   606
paulson@21071
   607
fun cnf_rules_of_ths ths = List.concat (map skolem_use_cache_thm ths);
paulson@16563
   608
wenzelm@21588
   609
val meson_method_setup = Method.add_methods
wenzelm@21588
   610
  [("meson", Method.thms_args (fn ths =>
wenzelm@21588
   611
      Method.SIMPLE_METHOD' (CHANGED_PROP o Meson.meson_claset_tac (cnf_rules_of_ths ths) HOL_cs)),
wenzelm@21588
   612
    "MESON resolution proof procedure")];
paulson@15347
   613
paulson@21102
   614
(** Attribute for converting a theorem into clauses **)
paulson@18510
   615
paulson@21102
   616
fun meta_cnf_axiom th = map Meson.make_meta_clause (cnf_axiom (pairname th));
paulson@18510
   617
paulson@21102
   618
fun clausify_rule (th,i) = List.nth (meta_cnf_axiom th, i)
paulson@21102
   619
paulson@21102
   620
val clausify = Attrib.syntax (Scan.lift Args.nat
paulson@21102
   621
  >> (fn i => Thm.rule_attribute (fn _ => fn th => clausify_rule (th, i))));
paulson@21102
   622
paulson@21999
   623
paulson@21999
   624
(*** Converting a subgoal into negated conjecture clauses. ***)
paulson@21999
   625
paulson@21999
   626
val neg_skolemize_tac = EVERY' [rtac ccontr, ObjectLogic.atomize_tac, skolemize_tac];
paulson@21999
   627
val neg_clausify = Meson.finish_cnf o assume_abstract_list o make_clauses;
paulson@21999
   628
paulson@21999
   629
fun neg_conjecture_clauses st0 n =
paulson@21999
   630
  let val st = Seq.hd (neg_skolemize_tac n st0)
paulson@21999
   631
      val (params,_,_) = strip_context (Logic.nth_prem (n, Thm.prop_of st))
paulson@21999
   632
  in (neg_clausify (Option.valOf (metahyps_thms n st)), params) end;
paulson@21999
   633
paulson@21999
   634
(*Conversion of a subgoal to conjecture clauses. Each clause has  
paulson@21999
   635
  leading !!-bound universal variables, to express generality. *)
paulson@21999
   636
val neg_clausify_tac = 
paulson@21999
   637
  neg_skolemize_tac THEN' 
paulson@21999
   638
  SUBGOAL
paulson@21999
   639
    (fn (prop,_) =>
paulson@21999
   640
     let val ts = Logic.strip_assums_hyp prop
paulson@21999
   641
     in EVERY1 
paulson@21999
   642
	 [METAHYPS
paulson@21999
   643
	    (fn hyps => 
paulson@21999
   644
              (Method.insert_tac
paulson@21999
   645
                (map forall_intr_vars (neg_clausify hyps)) 1)),
paulson@21999
   646
	  REPEAT_DETERM_N (length ts) o (etac thin_rl)]
paulson@21999
   647
     end);
paulson@21999
   648
paulson@21102
   649
(** The Skolemization attribute **)
paulson@18510
   650
paulson@18510
   651
fun conj2_rule (th1,th2) = conjI OF [th1,th2];
paulson@18510
   652
paulson@20457
   653
(*Conjoin a list of theorems to form a single theorem*)
paulson@20457
   654
fun conj_rule []  = TrueI
paulson@20445
   655
  | conj_rule ths = foldr1 conj2_rule ths;
paulson@18510
   656
paulson@20419
   657
fun skolem_attr (Context.Theory thy, th) =
wenzelm@21646
   658
      let val name = PureThy.get_name_hint th
wenzelm@20461
   659
          val (cls, thy') = skolem_cache_thm (name, th) thy
wenzelm@18728
   660
      in (Context.Theory thy', conj_rule cls) end
paulson@21071
   661
  | skolem_attr (context, th) = (context, conj_rule (skolem_use_cache_thm th));
paulson@18510
   662
paulson@18510
   663
val setup_attrs = Attrib.add_attributes
paulson@21102
   664
  [("skolem", Attrib.no_args skolem_attr, "skolemization of a theorem"),
paulson@21999
   665
   ("clausify", clausify, "conversion of theorem to clauses")];
paulson@21999
   666
paulson@21999
   667
val setup_methods = Method.add_methods
paulson@21999
   668
  [("neg_clausify", Method.no_args (Method.SIMPLE_METHOD' neg_clausify_tac), 
paulson@21999
   669
    "conversion of goal to conjecture clauses")];
paulson@21102
   670
     
paulson@21999
   671
val setup = clause_cache_setup #> setup_attrs #> setup_methods;
paulson@18510
   672
wenzelm@20461
   673
end;