src/HOL/Tools/Sledgehammer/sledgehammer_fact_preprocessor.ML
author wenzelm
Sat May 15 21:50:05 2010 +0200 (2010-05-15)
changeset 36945 9bec62c10714
parent 36603 d5d6111761a6
child 37171 fc1e20373e6a
permissions -rw-r--r--
less pervasive names from structure Thm;
     1 (*  Title:      HOL/Tools/Sledgehammer/sledgehammer_fact_preprocessor.ML
     2     Author:     Jia Meng, Cambridge University Computer Laboratory
     3     Author:     Jasmin Blanchette, TU Muenchen
     4 
     5 Transformation of axiom rules (elim/intro/etc) into CNF forms.
     6 *)
     7 
     8 signature SLEDGEHAMMER_FACT_PREPROCESSOR =
     9 sig
    10   val trace: bool Unsynchronized.ref
    11   val trace_msg: (unit -> string) -> unit
    12   val skolem_prefix: string
    13   val skolem_infix: string
    14   val cnf_axiom: theory -> thm -> thm list
    15   val multi_base_blacklist: string list
    16   val bad_for_atp: thm -> bool
    17   val type_has_topsort: typ -> bool
    18   val cnf_rules_pairs: theory -> (string * thm) list -> (thm * (string * int)) list
    19   val suppress_endtheory: bool Unsynchronized.ref
    20     (*for emergency use where endtheory causes problems*)
    21   val strip_subgoal : thm -> int -> (string * typ) list * term list * term
    22   val neg_clausify: thm -> thm list
    23   val neg_conjecture_clauses:
    24     Proof.context -> thm -> int -> thm list list * (string * typ) list
    25   val neg_clausify_tac: Proof.context -> int -> tactic
    26   val setup: theory -> theory
    27 end;
    28 
    29 structure Sledgehammer_Fact_Preprocessor : SLEDGEHAMMER_FACT_PREPROCESSOR =
    30 struct
    31 
    32 open Sledgehammer_FOL_Clause
    33 
    34 val trace = Unsynchronized.ref false;
    35 fun trace_msg msg = if !trace then tracing (msg ()) else ();
    36 
    37 val skolem_prefix = "sko_"
    38 val skolem_infix = "$"
    39 
    40 fun freeze_thm th = #1 (Drule.legacy_freeze_thaw th);
    41 
    42 val type_has_topsort = Term.exists_subtype
    43   (fn TFree (_, []) => true
    44     | TVar (_, []) => true
    45     | _ => false);
    46 
    47 
    48 (**** Transformation of Elimination Rules into First-Order Formulas****)
    49 
    50 val cfalse = cterm_of @{theory HOL} HOLogic.false_const;
    51 val ctp_false = cterm_of @{theory HOL} (HOLogic.mk_Trueprop HOLogic.false_const);
    52 
    53 (*Converts an elim-rule into an equivalent theorem that does not have the
    54   predicate variable.  Leaves other theorems unchanged.  We simply instantiate the
    55   conclusion variable to False.*)
    56 fun transform_elim th =
    57   case concl_of th of    (*conclusion variable*)
    58        @{const Trueprop} $ (v as Var (_, @{typ bool})) =>
    59            Thm.instantiate ([], [(cterm_of @{theory HOL} v, cfalse)]) th
    60     | v as Var(_, @{typ prop}) =>
    61            Thm.instantiate ([], [(cterm_of @{theory HOL} v, ctp_false)]) th
    62     | _ => th;
    63 
    64 (*To enforce single-threading*)
    65 exception Clausify_failure of theory;
    66 
    67 
    68 (**** SKOLEMIZATION BY INFERENCE (lcp) ****)
    69 
    70 (*Keep the full complexity of the original name*)
    71 fun flatten_name s = space_implode "_X" (Long_Name.explode s);
    72 
    73 fun skolem_name thm_name nref var_name =
    74   skolem_prefix ^ thm_name ^ "_" ^ Int.toString (Unsynchronized.inc nref) ^
    75   skolem_infix ^ (if var_name = "" then "g" else flatten_name var_name)
    76 
    77 fun rhs_extra_types lhsT rhs =
    78   let val lhs_vars = Term.add_tfreesT lhsT []
    79       fun add_new_TFrees (TFree v) =
    80             if member (op =) lhs_vars v then I else insert (op =) (TFree v)
    81         | add_new_TFrees _ = I
    82       val rhs_consts = fold_aterms (fn Const c => insert (op =) c | _ => I) rhs []
    83   in fold (#2 #> Term.fold_atyps add_new_TFrees) rhs_consts [] end;
    84 
    85 (*Traverse a theorem, declaring Skolem function definitions. String s is the suggested
    86   prefix for the Skolem constant.*)
    87 fun declare_skofuns s th =
    88   let
    89     val nref = Unsynchronized.ref 0    (* FIXME ??? *)
    90     fun dec_sko (Const (@{const_name Ex}, _) $ (xtp as Abs (s', T, p))) (axs, thy) =
    91           (*Existential: declare a Skolem function, then insert into body and continue*)
    92           let
    93             val cname = skolem_name s nref s'
    94             val args0 = OldTerm.term_frees xtp  (*get the formal parameter list*)
    95             val Ts = map type_of args0
    96             val extraTs = rhs_extra_types (Ts ---> T) xtp
    97             val argsx = map (fn T => Free (gensym "vsk", T)) extraTs
    98             val args = argsx @ args0
    99             val cT = extraTs ---> Ts ---> T
   100             val rhs = list_abs_free (map dest_Free args, HOLogic.choice_const T $ xtp)
   101                     (*Forms a lambda-abstraction over the formal parameters*)
   102             val (c, thy') =
   103               Sign.declare_const ((Binding.conceal (Binding.name cname), cT), NoSyn) thy
   104             val cdef = cname ^ "_def"
   105             val ((_, ax), thy'') =
   106               Thm.add_def true false (Binding.name cdef, Logic.mk_equals (c, rhs)) thy'
   107             val ax' = Drule.export_without_context ax
   108           in dec_sko (subst_bound (list_comb (c, args), p)) (ax' :: axs, thy'') end
   109       | dec_sko (Const (@{const_name All}, _) $ (Abs (a, T, p))) thx =
   110           (*Universal quant: insert a free variable into body and continue*)
   111           let val fname = Name.variant (OldTerm.add_term_names (p, [])) a
   112           in dec_sko (subst_bound (Free (fname, T), p)) thx end
   113       | dec_sko (@{const "op &"} $ p $ q) thx = dec_sko q (dec_sko p thx)
   114       | dec_sko (@{const "op |"} $ p $ q) thx = dec_sko q (dec_sko p thx)
   115       | dec_sko (@{const Trueprop} $ p) thx = dec_sko p thx
   116       | dec_sko t thx = thx (*Do nothing otherwise*)
   117   in fn thy => dec_sko (Thm.prop_of th) ([], thy) end;
   118 
   119 (*Traverse a theorem, accumulating Skolem function definitions.*)
   120 fun assume_skofuns s th =
   121   let val sko_count = Unsynchronized.ref 0   (* FIXME ??? *)
   122       fun dec_sko (Const (@{const_name Ex}, _) $ (xtp as Abs (s', T, p))) defs =
   123             (*Existential: declare a Skolem function, then insert into body and continue*)
   124             let val skos = map (#1 o Logic.dest_equals) defs  (*existing sko fns*)
   125                 val args = subtract (op =) skos (OldTerm.term_frees xtp) (*the formal parameters*)
   126                 val Ts = map type_of args
   127                 val cT = Ts ---> T
   128                 val id = skolem_name s sko_count s'
   129                 val c = Free (id, cT)
   130                 val rhs = list_abs_free (map dest_Free args,
   131                                          HOLogic.choice_const T $ xtp)
   132                       (*Forms a lambda-abstraction over the formal parameters*)
   133                 val def = Logic.mk_equals (c, rhs)
   134             in dec_sko (subst_bound (list_comb(c,args), p))
   135                        (def :: defs)
   136             end
   137         | dec_sko (Const (@{const_name All},_) $ Abs (a, T, p)) defs =
   138             (*Universal quant: insert a free variable into body and continue*)
   139             let val fname = Name.variant (OldTerm.add_term_names (p,[])) a
   140             in dec_sko (subst_bound (Free(fname,T), p)) defs end
   141         | dec_sko (@{const "op &"} $ p $ q) defs = dec_sko q (dec_sko p defs)
   142         | dec_sko (@{const "op |"} $ p $ q) defs = dec_sko q (dec_sko p defs)
   143         | dec_sko (@{const Trueprop} $ p) defs = dec_sko p defs
   144         | dec_sko t defs = defs (*Do nothing otherwise*)
   145   in  dec_sko (prop_of th) []  end;
   146 
   147 
   148 (**** REPLACING ABSTRACTIONS BY COMBINATORS ****)
   149 
   150 (*Returns the vars of a theorem*)
   151 fun vars_of_thm th =
   152   map (Thm.cterm_of (theory_of_thm th) o Var) (Thm.fold_terms Term.add_vars th []);
   153 
   154 (*Make a version of fun_cong with a given variable name*)
   155 local
   156     val fun_cong' = fun_cong RS asm_rl; (*renumber f, g to prevent clashes with (a,0)*)
   157     val cx = hd (vars_of_thm fun_cong');
   158     val ty = typ_of (ctyp_of_term cx);
   159     val thy = theory_of_thm fun_cong;
   160     fun mkvar a = cterm_of thy (Var((a,0),ty));
   161 in
   162 fun xfun_cong x = Thm.instantiate ([], [(cx, mkvar x)]) fun_cong'
   163 end;
   164 
   165 (*Removes the lambdas from an equation of the form t = (%x. u).  A non-negative n,
   166   serves as an upper bound on how many to remove.*)
   167 fun strip_lambdas 0 th = th
   168   | strip_lambdas n th =
   169       case prop_of th of
   170           _ $ (Const (@{const_name "op ="}, _) $ _ $ Abs (x, _, _)) =>
   171               strip_lambdas (n-1) (freeze_thm (th RS xfun_cong x))
   172         | _ => th;
   173 
   174 val lambda_free = not o Term.has_abs;
   175 
   176 val [f_B,g_B] = map (cterm_of @{theory}) (OldTerm.term_vars (prop_of @{thm abs_B}));
   177 val [g_C,f_C] = map (cterm_of @{theory}) (OldTerm.term_vars (prop_of @{thm abs_C}));
   178 val [f_S,g_S] = map (cterm_of @{theory}) (OldTerm.term_vars (prop_of @{thm abs_S}));
   179 
   180 (*FIXME: requires more use of cterm constructors*)
   181 fun abstract ct =
   182   let
   183       val thy = theory_of_cterm ct
   184       val Abs(x,_,body) = term_of ct
   185       val Type(@{type_name fun}, [xT,bodyT]) = typ_of (ctyp_of_term ct)
   186       val cxT = ctyp_of thy xT and cbodyT = ctyp_of thy bodyT
   187       fun makeK() = instantiate' [SOME cxT, SOME cbodyT] [SOME (cterm_of thy body)] @{thm abs_K}
   188   in
   189       case body of
   190           Const _ => makeK()
   191         | Free _ => makeK()
   192         | Var _ => makeK()  (*though Var isn't expected*)
   193         | Bound 0 => instantiate' [SOME cxT] [] @{thm abs_I} (*identity: I*)
   194         | rator$rand =>
   195             if loose_bvar1 (rator,0) then (*C or S*)
   196                if loose_bvar1 (rand,0) then (*S*)
   197                  let val crator = cterm_of thy (Abs(x,xT,rator))
   198                      val crand = cterm_of thy (Abs(x,xT,rand))
   199                      val abs_S' = cterm_instantiate [(f_S,crator),(g_S,crand)] @{thm abs_S}
   200                      val (_,rhs) = Thm.dest_equals (cprop_of abs_S')
   201                  in
   202                    Thm.transitive abs_S' (Conv.binop_conv abstract rhs)
   203                  end
   204                else (*C*)
   205                  let val crator = cterm_of thy (Abs(x,xT,rator))
   206                      val abs_C' = cterm_instantiate [(f_C,crator),(g_C,cterm_of thy rand)] @{thm abs_C}
   207                      val (_,rhs) = Thm.dest_equals (cprop_of abs_C')
   208                  in
   209                    Thm.transitive abs_C' (Conv.fun_conv (Conv.arg_conv abstract) rhs)
   210                  end
   211             else if loose_bvar1 (rand,0) then (*B or eta*)
   212                if rand = Bound 0 then Thm.eta_conversion ct
   213                else (*B*)
   214                  let val crand = cterm_of thy (Abs(x,xT,rand))
   215                      val crator = cterm_of thy rator
   216                      val abs_B' = cterm_instantiate [(f_B,crator),(g_B,crand)] @{thm abs_B}
   217                      val (_,rhs) = Thm.dest_equals (cprop_of abs_B')
   218                  in
   219                    Thm.transitive abs_B' (Conv.arg_conv abstract rhs)
   220                  end
   221             else makeK()
   222         | _ => error "abstract: Bad term"
   223   end;
   224 
   225 (*Traverse a theorem, declaring abstraction function definitions. String s is the suggested
   226   prefix for the constants.*)
   227 fun combinators_aux ct =
   228   if lambda_free (term_of ct) then Thm.reflexive ct
   229   else
   230   case term_of ct of
   231       Abs _ =>
   232         let val (cv, cta) = Thm.dest_abs NONE ct
   233             val (v, _) = dest_Free (term_of cv)
   234             val u_th = combinators_aux cta
   235             val cu = Thm.rhs_of u_th
   236             val comb_eq = abstract (Thm.cabs cv cu)
   237         in Thm.transitive (Thm.abstract_rule v cv u_th) comb_eq end
   238     | _ $ _ =>
   239         let val (ct1, ct2) = Thm.dest_comb ct
   240         in  Thm.combination (combinators_aux ct1) (combinators_aux ct2)  end;
   241 
   242 fun combinators th =
   243   if lambda_free (prop_of th) then th
   244   else
   245     let val th = Drule.eta_contraction_rule th
   246         val eqth = combinators_aux (cprop_of th)
   247     in  Thm.equal_elim eqth th   end
   248     handle THM (msg,_,_) =>
   249       (warning (cat_lines
   250         ["Error in the combinator translation of " ^ Display.string_of_thm_without_context th,
   251           "  Exception message: " ^ msg]);
   252        TrueI);  (*A type variable of sort {} will cause make abstraction fail.*)
   253 
   254 (*cterms are used throughout for efficiency*)
   255 val cTrueprop = Thm.cterm_of @{theory HOL} HOLogic.Trueprop;
   256 
   257 (*cterm version of mk_cTrueprop*)
   258 fun c_mkTrueprop A = Thm.capply cTrueprop A;
   259 
   260 (*Given an abstraction over n variables, replace the bound variables by free
   261   ones. Return the body, along with the list of free variables.*)
   262 fun c_variant_abs_multi (ct0, vars) =
   263       let val (cv,ct) = Thm.dest_abs NONE ct0
   264       in  c_variant_abs_multi (ct, cv::vars)  end
   265       handle CTERM _ => (ct0, rev vars);
   266 
   267 (*Given the definition of a Skolem function, return a theorem to replace
   268   an existential formula by a use of that function.
   269    Example: "EX x. x : A & x ~: B ==> sko A B : A & sko A B ~: B"  [.] *)
   270 fun skolem_of_def def =
   271   let val (c,rhs) = Thm.dest_equals (cprop_of (freeze_thm def))
   272       val (ch, frees) = c_variant_abs_multi (rhs, [])
   273       val (chilbert,cabs) = Thm.dest_comb ch
   274       val thy = Thm.theory_of_cterm chilbert
   275       val t = Thm.term_of chilbert
   276       val T = case t of
   277                 Const (@{const_name Eps}, Type (@{type_name fun},[_,T])) => T
   278               | _ => raise THM ("skolem_of_def: expected Eps", 0, [def])
   279       val cex = Thm.cterm_of thy (HOLogic.exists_const T)
   280       val ex_tm = c_mkTrueprop (Thm.capply cex cabs)
   281       and conc =  c_mkTrueprop (Drule.beta_conv cabs (Drule.list_comb(c,frees)));
   282       fun tacf [prem] = rewrite_goals_tac [def] THEN rtac (prem RS @{thm someI_ex}) 1
   283   in  Goal.prove_internal [ex_tm] conc tacf
   284        |> forall_intr_list frees
   285        |> Thm.forall_elim_vars 0  (*Introduce Vars, but don't discharge defs.*)
   286        |> Thm.varifyT_global
   287   end;
   288 
   289 
   290 (*Converts an Isabelle theorem (intro, elim or simp format, even higher-order) into NNF.*)
   291 fun to_nnf th ctxt0 =
   292   let val th1 = th |> transform_elim |> zero_var_indexes
   293       val ((_, [th2]), ctxt) = Variable.import true [th1] ctxt0
   294       val th3 = th2
   295         |> Conv.fconv_rule Object_Logic.atomize
   296         |> Meson.make_nnf ctxt |> strip_lambdas ~1
   297   in  (th3, ctxt)  end;
   298 
   299 (*Generate Skolem functions for a theorem supplied in nnf*)
   300 fun assume_skolem_of_def s th =
   301   map (skolem_of_def o Thm.assume o (cterm_of (theory_of_thm th))) (assume_skofuns s th);
   302 
   303 
   304 (*** Blacklisting (FIXME: duplicated in "Sledgehammer_Fact_Filter"?) ***)
   305 
   306 val max_lambda_nesting = 3;
   307 
   308 fun excessive_lambdas (f$t, k) = excessive_lambdas (f,k) orelse excessive_lambdas (t,k)
   309   | excessive_lambdas (Abs(_,_,t), k) = k=0 orelse excessive_lambdas (t,k-1)
   310   | excessive_lambdas _ = false;
   311 
   312 fun is_formula_type T = (T = HOLogic.boolT orelse T = propT);
   313 
   314 (*Don't count nested lambdas at the level of formulas, as they are quantifiers*)
   315 fun excessive_lambdas_fm Ts (Abs(_,T,t)) = excessive_lambdas_fm (T::Ts) t
   316   | excessive_lambdas_fm Ts t =
   317       if is_formula_type (fastype_of1 (Ts, t))
   318       then exists (excessive_lambdas_fm Ts) (#2 (strip_comb t))
   319       else excessive_lambdas (t, max_lambda_nesting);
   320 
   321 (*The max apply_depth of any metis call in Metis_Examples (on 31-10-2007) was 11.*)
   322 val max_apply_depth = 15;
   323 
   324 fun apply_depth (f$t) = Int.max (apply_depth f, apply_depth t + 1)
   325   | apply_depth (Abs(_,_,t)) = apply_depth t
   326   | apply_depth _ = 0;
   327 
   328 fun too_complex t =
   329   apply_depth t > max_apply_depth orelse
   330   Meson.too_many_clauses NONE t orelse
   331   excessive_lambdas_fm [] t;
   332 
   333 fun is_strange_thm th =
   334   case head_of (concl_of th) of
   335       Const (a, _) => (a <> @{const_name Trueprop} andalso
   336                        a <> @{const_name "=="})
   337     | _ => false;
   338 
   339 fun bad_for_atp th =
   340   too_complex (prop_of th)
   341   orelse exists_type type_has_topsort (prop_of th)
   342   orelse is_strange_thm th;
   343 
   344 (* FIXME: put other record thms here, or declare as "no_atp" *)
   345 val multi_base_blacklist =
   346   ["defs", "select_defs", "update_defs", "induct", "inducts", "split", "splits",
   347    "split_asm", "cases", "ext_cases"];
   348 
   349 fun fake_name th =
   350   if Thm.has_name_hint th then flatten_name (Thm.get_name_hint th)
   351   else gensym "unknown_thm_";
   352 
   353 (*Skolemize a named theorem, with Skolem functions as additional premises.*)
   354 fun skolem_thm (s, th) =
   355   if member (op =) multi_base_blacklist (Long_Name.base_name s) orelse bad_for_atp th then []
   356   else
   357     let
   358       val ctxt0 = Variable.global_thm_context th
   359       val (nnfth, ctxt1) = to_nnf th ctxt0
   360       val (cnfs, ctxt2) = Meson.make_cnf (assume_skolem_of_def s nnfth) nnfth ctxt1
   361     in  cnfs |> map combinators |> Variable.export ctxt2 ctxt0 |> Meson.finish_cnf  end
   362     handle THM _ => [];
   363 
   364 (*The cache prevents repeated clausification of a theorem, and also repeated declaration of
   365   Skolem functions.*)
   366 structure ThmCache = Theory_Data
   367 (
   368   type T = thm list Thmtab.table * unit Symtab.table;
   369   val empty = (Thmtab.empty, Symtab.empty);
   370   val extend = I;
   371   fun merge ((cache1, seen1), (cache2, seen2)) : T =
   372     (Thmtab.merge (K true) (cache1, cache2), Symtab.merge (K true) (seen1, seen2));
   373 );
   374 
   375 val lookup_cache = Thmtab.lookup o #1 o ThmCache.get;
   376 val already_seen = Symtab.defined o #2 o ThmCache.get;
   377 
   378 val update_cache = ThmCache.map o apfst o Thmtab.update;
   379 fun mark_seen name = ThmCache.map (apsnd (Symtab.update (name, ())));
   380 
   381 (* Convert Isabelle theorems into axiom clauses. *)
   382 fun cnf_axiom thy th0 =
   383   let val th = Thm.transfer thy th0 in
   384     case lookup_cache thy th of
   385       NONE => map Thm.close_derivation (skolem_thm (fake_name th, th))
   386     | SOME cls => cls
   387   end;
   388 
   389 
   390 (**** Translate a set of theorems into CNF ****)
   391 
   392 fun pair_name_cls k (n, []) = []
   393   | pair_name_cls k (n, cls::clss) = (cls, (n,k)) :: pair_name_cls (k+1) (n, clss)
   394 
   395 fun cnf_rules_pairs_aux _ pairs [] = pairs
   396   | cnf_rules_pairs_aux thy pairs ((name,th)::ths) =
   397       let val pairs' = (pair_name_cls 0 (name, cnf_axiom thy th)) @ pairs
   398                        handle THM _ => pairs |
   399                               CLAUSE _ => pairs
   400       in  cnf_rules_pairs_aux thy pairs' ths  end;
   401 
   402 (*The combination of rev and tail recursion preserves the original order*)
   403 fun cnf_rules_pairs thy l = cnf_rules_pairs_aux thy [] (rev l);
   404 
   405 
   406 (**** Convert all facts of the theory into FOL or HOL clauses ****)
   407 
   408 local
   409 
   410 fun skolem_def (name, th) thy =
   411   let val ctxt0 = Variable.global_thm_context th in
   412     (case try (to_nnf th) ctxt0 of
   413       NONE => (NONE, thy)
   414     | SOME (nnfth, ctxt1) =>
   415         let val (defs, thy') = declare_skofuns (flatten_name name) nnfth thy
   416         in (SOME (th, ctxt0, ctxt1, nnfth, defs), thy') end)
   417   end;
   418 
   419 fun skolem_cnfs (th, ctxt0, ctxt1, nnfth, defs) =
   420   let
   421     val (cnfs, ctxt2) = Meson.make_cnf (map skolem_of_def defs) nnfth ctxt1;
   422     val cnfs' = cnfs
   423       |> map combinators
   424       |> Variable.export ctxt2 ctxt0
   425       |> Meson.finish_cnf
   426       |> map Thm.close_derivation;
   427     in (th, cnfs') end;
   428 
   429 in
   430 
   431 fun saturate_skolem_cache thy =
   432   let
   433     val facts = PureThy.facts_of thy;
   434     val new_facts = (facts, []) |-> Facts.fold_static (fn (name, ths) =>
   435       if Facts.is_concealed facts name orelse already_seen thy name then I
   436       else cons (name, ths));
   437     val new_thms = (new_facts, []) |-> fold (fn (name, ths) =>
   438       if member (op =) multi_base_blacklist (Long_Name.base_name name) then I
   439       else fold_index (fn (i, th) =>
   440         if bad_for_atp th orelse is_some (lookup_cache thy th) then I
   441         else cons (name ^ "_" ^ string_of_int (i + 1), Thm.transfer thy th)) ths);
   442   in
   443     if null new_facts then NONE
   444     else
   445       let
   446         val (defs, thy') = thy
   447           |> fold (mark_seen o #1) new_facts
   448           |> fold_map skolem_def (sort_distinct (Thm.thm_ord o pairself snd) new_thms)
   449           |>> map_filter I;
   450         val cache_entries = Par_List.map skolem_cnfs defs;
   451       in SOME (fold update_cache cache_entries thy') end
   452   end;
   453 
   454 end;
   455 
   456 val suppress_endtheory = Unsynchronized.ref false;
   457 
   458 fun clause_cache_endtheory thy =
   459   if ! suppress_endtheory then NONE
   460   else saturate_skolem_cache thy;
   461 
   462 
   463 (*The cache can be kept smaller by inspecting the prop of each thm. Can ignore all that are
   464   lambda_free, but then the individual theory caches become much bigger.*)
   465 
   466 
   467 fun strip_subgoal goal i =
   468   let
   469     val (t, frees) = Logic.goal_params (prop_of goal) i
   470     val hyp_ts = t |> Logic.strip_assums_hyp |> map (curry subst_bounds frees)
   471     val concl_t = t |> Logic.strip_assums_concl |> curry subst_bounds frees
   472   in (rev (map dest_Free frees), hyp_ts, concl_t) end
   473 
   474 (*** Converting a subgoal into negated conjecture clauses. ***)
   475 
   476 fun neg_skolemize_tac ctxt =
   477   EVERY' [rtac ccontr, Object_Logic.atomize_prems_tac, Meson.skolemize_tac ctxt];
   478 
   479 fun neg_skolemize_tac ctxt =
   480   EVERY' [rtac ccontr, Object_Logic.atomize_prems_tac, Meson.skolemize_tac ctxt];
   481 
   482 val neg_clausify =
   483   single #> Meson.make_clauses_unsorted #> map combinators #> Meson.finish_cnf
   484 
   485 fun neg_conjecture_clauses ctxt st0 n =
   486   let
   487     val st = Seq.hd (neg_skolemize_tac ctxt n st0)
   488     val ({params, prems, ...}, _) = Subgoal.focus (Variable.set_body false ctxt) n st
   489   in
   490     (map neg_clausify prems, map (Term.dest_Free o Thm.term_of o #2) params)
   491   end
   492 
   493 (*Conversion of a subgoal to conjecture clauses. Each clause has
   494   leading !!-bound universal variables, to express generality. *)
   495 fun neg_clausify_tac ctxt =
   496   neg_skolemize_tac ctxt THEN'
   497   SUBGOAL (fn (prop, i) =>
   498     let val ts = Logic.strip_assums_hyp prop in
   499       EVERY'
   500        [Subgoal.FOCUS
   501          (fn {prems, ...} =>
   502            (Method.insert_tac
   503              (map forall_intr_vars (maps neg_clausify prems)) i)) ctxt,
   504         REPEAT_DETERM_N (length ts) o etac thin_rl] i
   505      end);
   506 
   507 
   508 (** setup **)
   509 
   510 val setup =
   511   perhaps saturate_skolem_cache #>
   512   Theory.at_end clause_cache_endtheory;
   513 
   514 end;