src/HOL/Tools/meson.ML
author wenzelm
Wed, 31 Dec 2008 00:08:13 +0100
changeset 29267 8615b4f54047
parent 28397 389c5e494605
child 29684 40bf9f4e7a4e
permissions -rw-r--r--
use exists_subterm directly;
     1 (*  Title:      HOL/Tools/meson.ML
     2     Author:     Lawrence C Paulson, Cambridge University Computer Laboratory
     3 
     4 The MESON resolution proof procedure for HOL.
     5 When making clauses, avoids using the rewriter -- instead uses RS recursively.
     6 *)
     7 
     8 signature MESON =
     9 sig
    10   val term_pair_of: indexname * (typ * 'a) -> term * 'a
    11   val first_order_resolve: thm -> thm -> thm
    12   val flexflex_first_order: thm -> thm
    13   val size_of_subgoals: thm -> int
    14   val too_many_clauses: Proof.context option -> term -> bool
    15   val make_cnf: thm list -> thm -> Proof.context -> thm list * Proof.context
    16   val finish_cnf: thm list -> thm list
    17   val make_nnf: thm -> thm
    18   val make_nnf1: thm -> thm
    19   val skolemize: thm -> thm
    20   val is_fol_term: theory -> term -> bool
    21   val make_clauses: thm list -> thm list
    22   val make_horns: thm list -> thm list
    23   val best_prolog_tac: (thm -> int) -> thm list -> tactic
    24   val depth_prolog_tac: thm list -> tactic
    25   val gocls: thm list -> thm list
    26   val skolemize_prems_tac: thm list -> int -> tactic
    27   val MESON: (thm list -> thm list) -> (thm list -> tactic) -> int -> tactic
    28   val best_meson_tac: (thm -> int) -> int -> tactic
    29   val safe_best_meson_tac: int -> tactic
    30   val depth_meson_tac: int -> tactic
    31   val prolog_step_tac': thm list -> int -> tactic
    32   val iter_deepen_prolog_tac: thm list -> tactic
    33   val iter_deepen_meson_tac: thm list -> int -> tactic
    34   val make_meta_clause: thm -> thm
    35   val make_meta_clauses: thm list -> thm list
    36   val meson_claset_tac: thm list -> claset -> int -> tactic
    37   val meson_tac: int -> tactic
    38   val negate_head: thm -> thm
    39   val select_literal: int -> thm -> thm
    40   val skolemize_tac: int -> tactic
    41   val setup: Context.theory -> Context.theory
    42 end
    43 
    44 structure Meson: MESON =
    45 struct
    46 
    47 val max_clauses_default = 60;
    48 val (max_clauses, setup) = Attrib.config_int "max_clauses" max_clauses_default;
    49 
    50 val not_conjD = thm "meson_not_conjD";
    51 val not_disjD = thm "meson_not_disjD";
    52 val not_notD = thm "meson_not_notD";
    53 val not_allD = thm "meson_not_allD";
    54 val not_exD = thm "meson_not_exD";
    55 val imp_to_disjD = thm "meson_imp_to_disjD";
    56 val not_impD = thm "meson_not_impD";
    57 val iff_to_disjD = thm "meson_iff_to_disjD";
    58 val not_iffD = thm "meson_not_iffD";
    59 val conj_exD1 = thm "meson_conj_exD1";
    60 val conj_exD2 = thm "meson_conj_exD2";
    61 val disj_exD = thm "meson_disj_exD";
    62 val disj_exD1 = thm "meson_disj_exD1";
    63 val disj_exD2 = thm "meson_disj_exD2";
    64 val disj_assoc = thm "meson_disj_assoc";
    65 val disj_comm = thm "meson_disj_comm";
    66 val disj_FalseD1 = thm "meson_disj_FalseD1";
    67 val disj_FalseD2 = thm "meson_disj_FalseD2";
    68 
    69 
    70 (**** Operators for forward proof ****)
    71 
    72 
    73 (** First-order Resolution **)
    74 
    75 fun typ_pair_of (ix, (sort,ty)) = (TVar (ix,sort), ty);
    76 fun term_pair_of (ix, (ty,t)) = (Var (ix,ty), t);
    77 
    78 val Envir.Envir {asol = tenv0, iTs = tyenv0, ...} = Envir.empty 0
    79 
    80 (*FIXME: currently does not "rename variables apart"*)
    81 fun first_order_resolve thA thB =
    82   let val thy = theory_of_thm thA
    83       val tmA = concl_of thA
    84       val Const("==>",_) $ tmB $ _ = prop_of thB
    85       val (tyenv,tenv) = Pattern.first_order_match thy (tmB,tmA) (tyenv0,tenv0)
    86       val ct_pairs = map (pairself (cterm_of thy) o term_pair_of) (Vartab.dest tenv)
    87   in  thA RS (cterm_instantiate ct_pairs thB)  end
    88   handle _ => raise THM ("first_order_resolve", 0, [thA,thB]);  (* FIXME avoid handle _ *)
    89 
    90 fun flexflex_first_order th =
    91   case (tpairs_of th) of
    92       [] => th
    93     | pairs =>
    94         let val thy = theory_of_thm th
    95             val (tyenv,tenv) =
    96                   foldl (uncurry (Pattern.first_order_match thy)) (tyenv0,tenv0) pairs
    97             val t_pairs = map term_pair_of (Vartab.dest tenv)
    98             val th' = Thm.instantiate ([], map (pairself (cterm_of thy)) t_pairs) th
    99         in  th'  end
   100         handle THM _ => th;
   101 
   102 (*Forward proof while preserving bound variables names*)
   103 fun rename_bvs_RS th rl =
   104   let val th' = th RS rl
   105   in  Thm.rename_boundvars (concl_of th') (concl_of th) th' end;
   106 
   107 (*raises exception if no rules apply*)
   108 fun tryres (th, rls) =
   109   let fun tryall [] = raise THM("tryres", 0, th::rls)
   110         | tryall (rl::rls) = (rename_bvs_RS th rl handle THM _ => tryall rls)
   111   in  tryall rls  end;
   112 
   113 (*Permits forward proof from rules that discharge assumptions. The supplied proof state st,
   114   e.g. from conj_forward, should have the form
   115     "[| P' ==> ?P; Q' ==> ?Q |] ==> ?P & ?Q"
   116   and the effect should be to instantiate ?P and ?Q with normalized versions of P' and Q'.*)
   117 fun forward_res nf st =
   118   let fun forward_tacf [prem] = rtac (nf prem) 1
   119         | forward_tacf prems =
   120             error ("Bad proof state in forward_res, please inform lcp@cl.cam.ac.uk:\n" ^
   121                    Display.string_of_thm st ^
   122                    "\nPremises:\n" ^
   123                    ML_Syntax.print_list Display.string_of_thm prems)
   124   in
   125     case Seq.pull (ALLGOALS (METAHYPS forward_tacf) st)
   126     of SOME(th,_) => th
   127      | NONE => raise THM("forward_res", 0, [st])
   128   end;
   129 
   130 (*Are any of the logical connectives in "bs" present in the term?*)
   131 fun has_conns bs =
   132   let fun has (Const(a,_)) = false
   133         | has (Const("Trueprop",_) $ p) = has p
   134         | has (Const("Not",_) $ p) = has p
   135         | has (Const("op |",_) $ p $ q) = member (op =) bs "op |" orelse has p orelse has q
   136         | has (Const("op &",_) $ p $ q) = member (op =) bs "op &" orelse has p orelse has q
   137         | has (Const("All",_) $ Abs(_,_,p)) = member (op =) bs "All" orelse has p
   138         | has (Const("Ex",_) $ Abs(_,_,p)) = member (op =) bs "Ex" orelse has p
   139         | has _ = false
   140   in  has  end;
   141 
   142 
   143 (**** Clause handling ****)
   144 
   145 fun literals (Const("Trueprop",_) $ P) = literals P
   146   | literals (Const("op |",_) $ P $ Q) = literals P @ literals Q
   147   | literals (Const("Not",_) $ P) = [(false,P)]
   148   | literals P = [(true,P)];
   149 
   150 (*number of literals in a term*)
   151 val nliterals = length o literals;
   152 
   153 
   154 (*** Tautology Checking ***)
   155 
   156 fun signed_lits_aux (Const ("op |", _) $ P $ Q) (poslits, neglits) =
   157       signed_lits_aux Q (signed_lits_aux P (poslits, neglits))
   158   | signed_lits_aux (Const("Not",_) $ P) (poslits, neglits) = (poslits, P::neglits)
   159   | signed_lits_aux P (poslits, neglits) = (P::poslits, neglits);
   160 
   161 fun signed_lits th = signed_lits_aux (HOLogic.dest_Trueprop (concl_of th)) ([],[]);
   162 
   163 (*Literals like X=X are tautologous*)
   164 fun taut_poslit (Const("op =",_) $ t $ u) = t aconv u
   165   | taut_poslit (Const("True",_)) = true
   166   | taut_poslit _ = false;
   167 
   168 fun is_taut th =
   169   let val (poslits,neglits) = signed_lits th
   170   in  exists taut_poslit poslits
   171       orelse
   172       exists (member (op aconv) neglits) (HOLogic.false_const :: poslits)
   173   end
   174   handle TERM _ => false;       (*probably dest_Trueprop on a weird theorem*)
   175 
   176 
   177 (*** To remove trivial negated equality literals from clauses ***)
   178 
   179 (*They are typically functional reflexivity axioms and are the converses of
   180   injectivity equivalences*)
   181 
   182 val not_refl_disj_D = thm"meson_not_refl_disj_D";
   183 
   184 (*Is either term a Var that does not properly occur in the other term?*)
   185 fun eliminable (t as Var _, u) = t aconv u orelse not (Logic.occs(t,u))
   186   | eliminable (u, t as Var _) = t aconv u orelse not (Logic.occs(t,u))
   187   | eliminable _ = false;
   188 
   189 fun refl_clause_aux 0 th = th
   190   | refl_clause_aux n th =
   191        case HOLogic.dest_Trueprop (concl_of th) of
   192           (Const ("op |", _) $ (Const ("op |", _) $ _ $ _) $ _) =>
   193             refl_clause_aux n (th RS disj_assoc)    (*isolate an atom as first disjunct*)
   194         | (Const ("op |", _) $ (Const("Not",_) $ (Const("op =",_) $ t $ u)) $ _) =>
   195             if eliminable(t,u)
   196             then refl_clause_aux (n-1) (th RS not_refl_disj_D)  (*Var inequation: delete*)
   197             else refl_clause_aux (n-1) (th RS disj_comm)  (*not between Vars: ignore*)
   198         | (Const ("op |", _) $ _ $ _) => refl_clause_aux n (th RS disj_comm)
   199         | _ => (*not a disjunction*) th;
   200 
   201 fun notequal_lits_count (Const ("op |", _) $ P $ Q) =
   202       notequal_lits_count P + notequal_lits_count Q
   203   | notequal_lits_count (Const("Not",_) $ (Const("op =",_) $ _ $ _)) = 1
   204   | notequal_lits_count _ = 0;
   205 
   206 (*Simplify a clause by applying reflexivity to its negated equality literals*)
   207 fun refl_clause th =
   208   let val neqs = notequal_lits_count (HOLogic.dest_Trueprop (concl_of th))
   209   in  zero_var_indexes (refl_clause_aux neqs th)  end
   210   handle TERM _ => th;  (*probably dest_Trueprop on a weird theorem*)
   211 
   212 
   213 (*** Removal of duplicate literals ***)
   214 
   215 (*Forward proof, passing extra assumptions as theorems to the tactic*)
   216 fun forward_res2 nf hyps st =
   217   case Seq.pull
   218         (REPEAT
   219          (METAHYPS (fn major::minors => rtac (nf (minors@hyps) major) 1) 1)
   220          st)
   221   of SOME(th,_) => th
   222    | NONE => raise THM("forward_res2", 0, [st]);
   223 
   224 (*Remove duplicates in P|Q by assuming ~P in Q
   225   rls (initially []) accumulates assumptions of the form P==>False*)
   226 fun nodups_aux rls th = nodups_aux rls (th RS disj_assoc)
   227     handle THM _ => tryres(th,rls)
   228     handle THM _ => tryres(forward_res2 nodups_aux rls (th RS disj_forward2),
   229                            [disj_FalseD1, disj_FalseD2, asm_rl])
   230     handle THM _ => th;
   231 
   232 (*Remove duplicate literals, if there are any*)
   233 fun nodups th =
   234   if has_duplicates (op =) (literals (prop_of th))
   235     then nodups_aux [] th
   236     else th;
   237 
   238 
   239 (*** The basic CNF transformation ***)
   240 
   241 fun too_many_clauses ctxto t = 
   242  let
   243   val max_cl = case ctxto of SOME ctxt => Config.get ctxt max_clauses
   244                            | NONE => max_clauses_default
   245   
   246   fun sum x y = if x < max_cl andalso y < max_cl then x+y else max_cl;
   247   fun prod x y = if x < max_cl andalso y < max_cl then x*y else max_cl;
   248   
   249   (*Estimate the number of clauses in order to detect infeasible theorems*)
   250   fun signed_nclauses b (Const("Trueprop",_) $ t) = signed_nclauses b t
   251     | signed_nclauses b (Const("Not",_) $ t) = signed_nclauses (not b) t
   252     | signed_nclauses b (Const("op &",_) $ t $ u) =
   253 	if b then sum (signed_nclauses b t) (signed_nclauses b u)
   254 	     else prod (signed_nclauses b t) (signed_nclauses b u)
   255     | signed_nclauses b (Const("op |",_) $ t $ u) =
   256 	if b then prod (signed_nclauses b t) (signed_nclauses b u)
   257 	     else sum (signed_nclauses b t) (signed_nclauses b u)
   258     | signed_nclauses b (Const("op -->",_) $ t $ u) =
   259 	if b then prod (signed_nclauses (not b) t) (signed_nclauses b u)
   260 	     else sum (signed_nclauses (not b) t) (signed_nclauses b u)
   261     | signed_nclauses b (Const("op =", Type ("fun", [T, _])) $ t $ u) =
   262 	if T = HOLogic.boolT then (*Boolean equality is if-and-only-if*)
   263 	    if b then sum (prod (signed_nclauses (not b) t) (signed_nclauses b u))
   264 			  (prod (signed_nclauses (not b) u) (signed_nclauses b t))
   265 		 else sum (prod (signed_nclauses b t) (signed_nclauses b u))
   266 			  (prod (signed_nclauses (not b) t) (signed_nclauses (not b) u))
   267 	else 1
   268     | signed_nclauses b (Const("Ex", _) $ Abs (_,_,t)) = signed_nclauses b t
   269     | signed_nclauses b (Const("All",_) $ Abs (_,_,t)) = signed_nclauses b t
   270     | signed_nclauses _ _ = 1; (* literal *)
   271  in 
   272   signed_nclauses true t >= max_cl
   273  end;
   274 
   275 (*Replaces universally quantified variables by FREE variables -- because
   276   assumptions may not contain scheme variables.  Later, generalize using Variable.export. *)
   277 local  
   278   val spec_var = Thm.dest_arg (Thm.dest_arg (#2 (Thm.dest_implies (Thm.cprop_of spec))));
   279   val spec_varT = #T (Thm.rep_cterm spec_var);
   280   fun name_of (Const ("All", _) $ Abs(x,_,_)) = x | name_of _ = Name.uu;
   281 in  
   282   fun freeze_spec th ctxt =
   283     let
   284       val cert = Thm.cterm_of (ProofContext.theory_of ctxt);
   285       val ([x], ctxt') = Variable.variant_fixes [name_of (HOLogic.dest_Trueprop (concl_of th))] ctxt;
   286       val spec' = Thm.instantiate ([], [(spec_var, cert (Free (x, spec_varT)))]) spec;
   287     in (th RS spec', ctxt') end
   288 end;
   289 
   290 (*Used with METAHYPS below. There is one assumption, which gets bound to prem
   291   and then normalized via function nf. The normal form is given to resolve_tac,
   292   instantiate a Boolean variable created by resolution with disj_forward. Since
   293   (nf prem) returns a LIST of theorems, we can backtrack to get all combinations.*)
   294 fun resop nf [prem] = resolve_tac (nf prem) 1;
   295 
   296 (*Any need to extend this list with
   297   "HOL.type_class","HOL.eq_class","Pure.term"?*)
   298 val has_meta_conn =
   299     exists_Const (member (op =) ["==", "==>", "all", "prop"] o #1);
   300 
   301 fun apply_skolem_ths (th, rls) =
   302   let fun tryall [] = raise THM("apply_skolem_ths", 0, th::rls)
   303         | tryall (rl::rls) = (first_order_resolve th rl handle THM _ => tryall rls)
   304   in  tryall rls  end;
   305 
   306 (*Conjunctive normal form, adding clauses from th in front of ths (for foldr).
   307   Strips universal quantifiers and breaks up conjunctions.
   308   Eliminates existential quantifiers using skoths: Skolemization theorems.*)
   309 fun cnf skoths ctxt (th,ths) =
   310   let val ctxtr = ref ctxt
   311       fun cnf_aux (th,ths) =
   312         if not (can HOLogic.dest_Trueprop (prop_of th)) then ths (*meta-level: ignore*)
   313         else if not (has_conns ["All","Ex","op &"] (prop_of th))
   314         then nodups th :: ths (*no work to do, terminate*)
   315         else case head_of (HOLogic.dest_Trueprop (concl_of th)) of
   316             Const ("op &", _) => (*conjunction*)
   317                 cnf_aux (th RS conjunct1, cnf_aux (th RS conjunct2, ths))
   318           | Const ("All", _) => (*universal quantifier*)
   319                 let val (th',ctxt') = freeze_spec th (!ctxtr)
   320                 in  ctxtr := ctxt'; cnf_aux (th', ths) end
   321           | Const ("Ex", _) =>
   322               (*existential quantifier: Insert Skolem functions*)
   323               cnf_aux (apply_skolem_ths (th,skoths), ths)
   324           | Const ("op |", _) =>
   325               (*Disjunction of P, Q: Create new goal of proving ?P | ?Q and solve it using
   326                 all combinations of converting P, Q to CNF.*)
   327               let val tac =
   328                   (METAHYPS (resop cnf_nil) 1) THEN
   329                    (fn st' => st' |> METAHYPS (resop cnf_nil) 1)
   330               in  Seq.list_of (tac (th RS disj_forward)) @ ths  end
   331           | _ => nodups th :: ths  (*no work to do*)
   332       and cnf_nil th = cnf_aux (th,[])
   333       val cls = 
   334 	    if too_many_clauses (SOME ctxt) (concl_of th)
   335 	    then (warning ("cnf is ignoring: " ^ Display.string_of_thm th); ths)
   336 	    else cnf_aux (th,ths)
   337   in  (cls, !ctxtr)  end;
   338 
   339 fun make_cnf skoths th ctxt = cnf skoths ctxt (th, []);
   340 
   341 (*Generalization, removal of redundant equalities, removal of tautologies.*)
   342 fun finish_cnf ths = filter (not o is_taut) (map refl_clause ths);
   343 
   344 
   345 (**** Generation of contrapositives ****)
   346 
   347 fun is_left (Const ("Trueprop", _) $
   348                (Const ("op |", _) $ (Const ("op |", _) $ _ $ _) $ _)) = true
   349   | is_left _ = false;
   350 
   351 (*Associate disjuctions to right -- make leftmost disjunct a LITERAL*)
   352 fun assoc_right th =
   353   if is_left (prop_of th) then assoc_right (th RS disj_assoc)
   354   else th;
   355 
   356 (*Must check for negative literal first!*)
   357 val clause_rules = [disj_assoc, make_neg_rule, make_pos_rule];
   358 
   359 (*For ordinary resolution. *)
   360 val resolution_clause_rules = [disj_assoc, make_neg_rule', make_pos_rule'];
   361 
   362 (*Create a goal or support clause, conclusing False*)
   363 fun make_goal th =   (*Must check for negative literal first!*)
   364     make_goal (tryres(th, clause_rules))
   365   handle THM _ => tryres(th, [make_neg_goal, make_pos_goal]);
   366 
   367 (*Sort clauses by number of literals*)
   368 fun fewerlits(th1,th2) = nliterals(prop_of th1) < nliterals(prop_of th2);
   369 
   370 fun sort_clauses ths = sort (make_ord fewerlits) ths;
   371 
   372 (*True if the given type contains bool anywhere*)
   373 fun has_bool (Type("bool",_)) = true
   374   | has_bool (Type(_, Ts)) = exists has_bool Ts
   375   | has_bool _ = false;
   376 
   377 (*Is the string the name of a connective? Really only | and Not can remain,
   378   since this code expects to be called on a clause form.*)
   379 val is_conn = member (op =)
   380     ["Trueprop", "op &", "op |", "op -->", "Not",
   381      "All", "Ex", "Ball", "Bex"];
   382 
   383 (*True if the term contains a function--not a logical connective--where the type
   384   of any argument contains bool.*)
   385 val has_bool_arg_const =
   386     exists_Const
   387       (fn (c,T) => not(is_conn c) andalso exists (has_bool) (binder_types T));
   388 
   389 (*A higher-order instance of a first-order constant? Example is the definition of
   390   HOL.one, 1, at a function type in theory SetsAndFunctions.*)
   391 fun higher_inst_const thy (c,T) =
   392   case binder_types T of
   393       [] => false (*not a function type, OK*)
   394     | Ts => length (binder_types (Sign.the_const_type thy c)) <> length Ts;
   395 
   396 (*Returns false if any Vars in the theorem mention type bool.
   397   Also rejects functions whose arguments are Booleans or other functions.*)
   398 fun is_fol_term thy t =
   399     Term.is_first_order ["all","All","Ex"] t andalso
   400     not (exists_subterm (fn Var (_, T) => has_bool T | _ => false) t  orelse
   401          has_bool_arg_const t  orelse
   402          exists_Const (higher_inst_const thy) t orelse
   403          has_meta_conn t);
   404 
   405 fun rigid t = not (is_Var (head_of t));
   406 
   407 fun ok4horn (Const ("Trueprop",_) $ (Const ("op |", _) $ t $ _)) = rigid t
   408   | ok4horn (Const ("Trueprop",_) $ t) = rigid t
   409   | ok4horn _ = false;
   410 
   411 (*Create a meta-level Horn clause*)
   412 fun make_horn crules th =
   413   if ok4horn (concl_of th)
   414   then make_horn crules (tryres(th,crules)) handle THM _ => th
   415   else th;
   416 
   417 (*Generate Horn clauses for all contrapositives of a clause. The input, th,
   418   is a HOL disjunction.*)
   419 fun add_contras crules (th,hcs) =
   420   let fun rots (0,th) = hcs
   421         | rots (k,th) = zero_var_indexes (make_horn crules th) ::
   422                         rots(k-1, assoc_right (th RS disj_comm))
   423   in case nliterals(prop_of th) of
   424         1 => th::hcs
   425       | n => rots(n, assoc_right th)
   426   end;
   427 
   428 (*Use "theorem naming" to label the clauses*)
   429 fun name_thms label =
   430     let fun name1 (th, (k,ths)) =
   431           (k-1, Thm.put_name_hint (label ^ string_of_int k) th :: ths)
   432     in  fn ths => #2 (foldr name1 (length ths, []) ths)  end;
   433 
   434 (*Is the given disjunction an all-negative support clause?*)
   435 fun is_negative th = forall (not o #1) (literals (prop_of th));
   436 
   437 val neg_clauses = List.filter is_negative;
   438 
   439 
   440 (***** MESON PROOF PROCEDURE *****)
   441 
   442 fun rhyps (Const("==>",_) $ (Const("Trueprop",_) $ A) $ phi,
   443            As) = rhyps(phi, A::As)
   444   | rhyps (_, As) = As;
   445 
   446 (** Detecting repeated assumptions in a subgoal **)
   447 
   448 (*The stringtree detects repeated assumptions.*)
   449 fun ins_term (net,t) = Net.insert_term (op aconv) (t,t) net;
   450 
   451 (*detects repetitions in a list of terms*)
   452 fun has_reps [] = false
   453   | has_reps [_] = false
   454   | has_reps [t,u] = (t aconv u)
   455   | has_reps ts = (Library.foldl ins_term (Net.empty, ts);  false)
   456                   handle Net.INSERT => true;
   457 
   458 (*Like TRYALL eq_assume_tac, but avoids expensive THEN calls*)
   459 fun TRYING_eq_assume_tac 0 st = Seq.single st
   460   | TRYING_eq_assume_tac i st =
   461        TRYING_eq_assume_tac (i-1) (eq_assumption i st)
   462        handle THM _ => TRYING_eq_assume_tac (i-1) st;
   463 
   464 fun TRYALL_eq_assume_tac st = TRYING_eq_assume_tac (nprems_of st) st;
   465 
   466 (*Loop checking: FAIL if trying to prove the same thing twice
   467   -- if *ANY* subgoal has repeated literals*)
   468 fun check_tac st =
   469   if exists (fn prem => has_reps (rhyps(prem,[]))) (prems_of st)
   470   then  Seq.empty  else  Seq.single st;
   471 
   472 
   473 (* net_resolve_tac actually made it slower... *)
   474 fun prolog_step_tac horns i =
   475     (assume_tac i APPEND resolve_tac horns i) THEN check_tac THEN
   476     TRYALL_eq_assume_tac;
   477 
   478 (*Sums the sizes of the subgoals, ignoring hypotheses (ancestors)*)
   479 fun addconcl(prem,sz) = size_of_term(Logic.strip_assums_concl prem) + sz
   480 
   481 fun size_of_subgoals st = foldr addconcl 0 (prems_of st);
   482 
   483 
   484 (*Negation Normal Form*)
   485 val nnf_rls = [imp_to_disjD, iff_to_disjD, not_conjD, not_disjD,
   486                not_impD, not_iffD, not_allD, not_exD, not_notD];
   487 
   488 fun ok4nnf (Const ("Trueprop",_) $ (Const ("Not", _) $ t)) = rigid t
   489   | ok4nnf (Const ("Trueprop",_) $ t) = rigid t
   490   | ok4nnf _ = false;
   491 
   492 fun make_nnf1 th =
   493   if ok4nnf (concl_of th)
   494   then make_nnf1 (tryres(th, nnf_rls))
   495     handle THM ("tryres", _, _) =>
   496         forward_res make_nnf1
   497            (tryres(th, [conj_forward,disj_forward,all_forward,ex_forward]))
   498     handle THM ("tryres", _, _) => th
   499   else th;
   500 
   501 (*The simplification removes defined quantifiers and occurrences of True and False.
   502   nnf_ss also includes the one-point simprocs,
   503   which are needed to avoid the various one-point theorems from generating junk clauses.*)
   504 val nnf_simps =
   505      [simp_implies_def, Ex1_def, Ball_def, Bex_def, if_True,
   506       if_False, if_cancel, if_eq_cancel, cases_simp];
   507 val nnf_extra_simps =
   508       thms"split_ifs" @ ex_simps @ all_simps @ simp_thms;
   509 
   510 val nnf_ss =
   511   HOL_basic_ss addsimps nnf_extra_simps
   512     addsimprocs [defALL_regroup,defEX_regroup, @{simproc neq}, @{simproc let_simp}];
   513 
   514 fun make_nnf th = case prems_of th of
   515     [] => th |> rewrite_rule (map safe_mk_meta_eq nnf_simps)
   516              |> simplify nnf_ss
   517              |> make_nnf1
   518   | _ => raise THM ("make_nnf: premises in argument", 0, [th]);
   519 
   520 (*Pull existential quantifiers to front. This accomplishes Skolemization for
   521   clauses that arise from a subgoal.*)
   522 fun skolemize th =
   523   if not (has_conns ["Ex"] (prop_of th)) then th
   524   else (skolemize (tryres(th, [choice, conj_exD1, conj_exD2,
   525                               disj_exD, disj_exD1, disj_exD2])))
   526     handle THM ("tryres", _, _) =>
   527         skolemize (forward_res skolemize
   528                    (tryres (th, [conj_forward, disj_forward, all_forward])))
   529     handle THM ("tryres", _, _) => 
   530         forward_res skolemize (rename_bvs_RS th ex_forward);
   531 
   532 fun skolemize_nnf_list [] = []
   533   | skolemize_nnf_list (th::ths) = 
   534       skolemize (make_nnf th) :: skolemize_nnf_list ths
   535       handle THM _ => (*RS can fail if Unify.search_bound is too small*)
   536        (warning ("Failed to Skolemize " ^ Display.string_of_thm th);
   537         skolemize_nnf_list ths);
   538 
   539 fun add_clauses (th,cls) =
   540   let val ctxt0 = Variable.thm_context th
   541       val (cnfs,ctxt) = make_cnf [] th ctxt0
   542   in Variable.export ctxt ctxt0 cnfs @ cls end;
   543 
   544 (*Make clauses from a list of theorems, previously Skolemized and put into nnf.
   545   The resulting clauses are HOL disjunctions.*)
   546 fun make_clauses ths = sort_clauses (foldr add_clauses [] ths);
   547 
   548 (*Convert a list of clauses (disjunctions) to Horn clauses (contrapositives)*)
   549 fun make_horns ths =
   550     name_thms "Horn#"
   551       (distinct Thm.eq_thm_prop (foldr (add_contras clause_rules) [] ths));
   552 
   553 (*Could simply use nprems_of, which would count remaining subgoals -- no
   554   discrimination as to their size!  With BEST_FIRST, fails for problem 41.*)
   555 
   556 fun best_prolog_tac sizef horns =
   557     BEST_FIRST (has_fewer_prems 1, sizef) (prolog_step_tac horns 1);
   558 
   559 fun depth_prolog_tac horns =
   560     DEPTH_FIRST (has_fewer_prems 1) (prolog_step_tac horns 1);
   561 
   562 (*Return all negative clauses, as possible goal clauses*)
   563 fun gocls cls = name_thms "Goal#" (map make_goal (neg_clauses cls));
   564 
   565 fun skolemize_prems_tac prems =
   566     cut_facts_tac (skolemize_nnf_list prems) THEN'
   567     REPEAT o (etac exE);
   568 
   569 (*Basis of all meson-tactics.  Supplies cltac with clauses: HOL disjunctions.
   570   Function mkcl converts theorems to clauses.*)
   571 fun MESON mkcl cltac i st =
   572   SELECT_GOAL
   573     (EVERY [ObjectLogic.atomize_prems_tac 1,
   574             rtac ccontr 1,
   575             METAHYPS (fn negs =>
   576                       EVERY1 [skolemize_prems_tac negs,
   577                               METAHYPS (cltac o mkcl)]) 1]) i st
   578   handle THM _ => no_tac st;    (*probably from make_meta_clause, not first-order*)
   579 
   580 (** Best-first search versions **)
   581 
   582 (*ths is a list of additional clauses (HOL disjunctions) to use.*)
   583 fun best_meson_tac sizef =
   584   MESON make_clauses
   585     (fn cls =>
   586          THEN_BEST_FIRST (resolve_tac (gocls cls) 1)
   587                          (has_fewer_prems 1, sizef)
   588                          (prolog_step_tac (make_horns cls) 1));
   589 
   590 (*First, breaks the goal into independent units*)
   591 val safe_best_meson_tac =
   592      SELECT_GOAL (TRY (CLASET safe_tac) THEN
   593                   TRYALL (best_meson_tac size_of_subgoals));
   594 
   595 (** Depth-first search version **)
   596 
   597 val depth_meson_tac =
   598   MESON make_clauses
   599     (fn cls => EVERY [resolve_tac (gocls cls) 1, depth_prolog_tac (make_horns cls)]);
   600 
   601 
   602 (** Iterative deepening version **)
   603 
   604 (*This version does only one inference per call;
   605   having only one eq_assume_tac speeds it up!*)
   606 fun prolog_step_tac' horns =
   607     let val (horn0s, hornps) = (*0 subgoals vs 1 or more*)
   608             take_prefix Thm.no_prems horns
   609         val nrtac = net_resolve_tac horns
   610     in  fn i => eq_assume_tac i ORELSE
   611                 match_tac horn0s i ORELSE  (*no backtracking if unit MATCHES*)
   612                 ((assume_tac i APPEND nrtac i) THEN check_tac)
   613     end;
   614 
   615 fun iter_deepen_prolog_tac horns =
   616     ITER_DEEPEN (has_fewer_prems 1) (prolog_step_tac' horns);
   617 
   618 fun iter_deepen_meson_tac ths = MESON make_clauses
   619  (fn cls =>
   620       case (gocls (cls@ths)) of
   621            [] => no_tac  (*no goal clauses*)
   622          | goes =>
   623              let val horns = make_horns (cls@ths)
   624                  val _ =
   625                      Output.debug (fn () => ("meson method called:\n" ^
   626                                   ML_Syntax.print_list Display.string_of_thm (cls@ths) ^
   627                                   "\nclauses:\n" ^
   628                                   ML_Syntax.print_list Display.string_of_thm horns))
   629              in THEN_ITER_DEEPEN (resolve_tac goes 1) (has_fewer_prems 1) (prolog_step_tac' horns)
   630              end
   631  );
   632 
   633 fun meson_claset_tac ths cs =
   634   SELECT_GOAL (TRY (safe_tac cs) THEN TRYALL (iter_deepen_meson_tac ths));
   635 
   636 val meson_tac = CLASET' (meson_claset_tac []);
   637 
   638 
   639 (**** Code to support ordinary resolution, rather than Model Elimination ****)
   640 
   641 (*Convert a list of clauses (disjunctions) to meta-level clauses (==>),
   642   with no contrapositives, for ordinary resolution.*)
   643 
   644 (*Rules to convert the head literal into a negated assumption. If the head
   645   literal is already negated, then using notEfalse instead of notEfalse'
   646   prevents a double negation.*)
   647 val notEfalse = read_instantiate @{context} [(("R", 0), "False")] notE;
   648 val notEfalse' = rotate_prems 1 notEfalse;
   649 
   650 fun negated_asm_of_head th =
   651     th RS notEfalse handle THM _ => th RS notEfalse';
   652 
   653 (*Converting one theorem from a disjunction to a meta-level clause*)
   654 fun make_meta_clause th =
   655   let val (fth,thaw) = Drule.freeze_thaw_robust th
   656   in  
   657       (zero_var_indexes o Thm.varifyT o thaw 0 o 
   658        negated_asm_of_head o make_horn resolution_clause_rules) fth
   659   end;
   660 
   661 fun make_meta_clauses ths =
   662     name_thms "MClause#"
   663       (distinct Thm.eq_thm_prop (map make_meta_clause ths));
   664 
   665 (*Permute a rule's premises to move the i-th premise to the last position.*)
   666 fun make_last i th =
   667   let val n = nprems_of th
   668   in  if 1 <= i andalso i <= n
   669       then Thm.permute_prems (i-1) 1 th
   670       else raise THM("select_literal", i, [th])
   671   end;
   672 
   673 (*Maps a rule that ends "... ==> P ==> False" to "... ==> ~P" while suppressing
   674   double-negations.*)
   675 val negate_head = rewrite_rule [atomize_not, not_not RS eq_reflection];
   676 
   677 (*Maps the clause  [P1,...Pn]==>False to [P1,...,P(i-1),P(i+1),...Pn] ==> ~P*)
   678 fun select_literal i cl = negate_head (make_last i cl);
   679 
   680 
   681 (*Top-level Skolemization. Allows part of the conversion to clauses to be
   682   expressed as a tactic (or Isar method).  Each assumption of the selected
   683   goal is converted to NNF and then its existential quantifiers are pulled
   684   to the front. Finally, all existential quantifiers are eliminated,
   685   leaving !!-quantified variables. Perhaps Safe_tac should follow, but it
   686   might generate many subgoals.*)
   687 
   688 fun skolemize_tac i st =
   689   let val ts = Logic.strip_assums_hyp (List.nth (prems_of st, i-1))
   690   in
   691      EVERY' [METAHYPS
   692             (fn hyps => (cut_facts_tac (skolemize_nnf_list hyps) 1
   693                          THEN REPEAT (etac exE 1))),
   694             REPEAT_DETERM_N (length ts) o (etac thin_rl)] i st
   695   end
   696   handle Subscript => Seq.empty;
   697 
   698 end;