src/HOL/Tools/Metis/metis_reconstruct.ML
author blanchet
Mon, 06 Jun 2011 20:36:35 +0200
changeset 44015 f497a1e97d37
parent 44003 9a8acc5adfa3
child 44018 5017d436a572
permissions -rw-r--r--
skip "hBOOL" in new Metis path finder
     1 (*  Title:      HOL/Tools/Metis/metis_reconstruct.ML
     2     Author:     Kong W. Susanto, Cambridge University Computer Laboratory
     3     Author:     Lawrence C. Paulson, Cambridge University Computer Laboratory
     4     Author:     Jasmin Blanchette, TU Muenchen
     5     Copyright   Cambridge University 2007
     6 
     7 Proof reconstruction for Metis.
     8 *)
     9 
    10 signature METIS_RECONSTRUCT =
    11 sig
    12   type mode = Metis_Translate.mode
    13 
    14   exception METIS of string * string
    15 
    16   val trace : bool Config.T
    17   val trace_msg : Proof.context -> (unit -> string) -> unit
    18   val verbose : bool Config.T
    19   val verbose_warning : Proof.context -> string -> unit
    20   val hol_clause_from_metis :
    21     Proof.context -> int Symtab.table -> Metis_Thm.thm -> term
    22   val lookth : (Metis_Thm.thm * 'a) list -> Metis_Thm.thm -> 'a
    23   val untyped_aconv : term * term -> bool
    24   val replay_one_inference :
    25     Proof.context -> mode -> (string * term) list -> int Symtab.table
    26     -> Metis_Thm.thm * Metis_Proof.inference -> (Metis_Thm.thm * thm) list
    27     -> (Metis_Thm.thm * thm) list
    28   val discharge_skolem_premises :
    29     Proof.context -> (thm * term) option list -> thm -> thm
    30 end;
    31 
    32 structure Metis_Reconstruct : METIS_RECONSTRUCT =
    33 struct
    34 
    35 open ATP_Problem
    36 open ATP_Translate
    37 open ATP_Reconstruct
    38 open Metis_Translate
    39 
    40 exception METIS of string * string
    41 
    42 val trace = Attrib.setup_config_bool @{binding metis_trace} (K false)
    43 val verbose = Attrib.setup_config_bool @{binding metis_verbose} (K true)
    44 
    45 fun trace_msg ctxt msg = if Config.get ctxt trace then tracing (msg ()) else ()
    46 fun verbose_warning ctxt msg =
    47   if Config.get ctxt verbose then warning ("Metis: " ^ msg) else ()
    48 
    49 datatype term_or_type = SomeTerm of term | SomeType of typ
    50 
    51 fun terms_of [] = []
    52   | terms_of (SomeTerm t :: tts) = t :: terms_of tts
    53   | terms_of (SomeType _ :: tts) = terms_of tts;
    54 
    55 fun types_of [] = []
    56   | types_of (SomeTerm (Var ((a, idx), _)) :: tts) =
    57     types_of tts
    58     |> (if String.isPrefix metis_generated_var_prefix a then
    59           (* Variable generated by Metis, which might have been a type
    60              variable. *)
    61           cons (TVar (("'" ^ a, idx), HOLogic.typeS))
    62         else
    63           I)
    64   | types_of (SomeTerm _ :: tts) = types_of tts
    65   | types_of (SomeType T :: tts) = T :: types_of tts
    66 
    67 fun apply_list rator nargs rands =
    68   let val trands = terms_of rands
    69   in  if length trands = nargs then SomeTerm (list_comb(rator, trands))
    70       else raise Fail
    71         ("apply_list: wrong number of arguments: " ^ Syntax.string_of_term_global Pure.thy rator ^
    72           " expected " ^ string_of_int nargs ^
    73           " received " ^ commas (map (Syntax.string_of_term_global Pure.thy) trands))
    74   end;
    75 
    76 fun infer_types ctxt =
    77   Syntax.check_terms (Proof_Context.set_mode Proof_Context.mode_pattern ctxt);
    78 
    79 (* We use 1 rather than 0 because variable references in clauses may otherwise
    80    conflict with variable constraints in the goal...at least, type inference
    81    often fails otherwise. See also "axiom_inf" below. *)
    82 fun make_var (w, T) = Var ((w, 1), T)
    83 
    84 (*Remove the "apply" operator from an HO term*)
    85 fun strip_happ args (Metis_Term.Fn (".", [t, u])) = strip_happ (u :: args) t
    86   | strip_happ args x = (x, args)
    87 
    88 fun hol_type_from_metis_term _ (Metis_Term.Var v) =
    89      (case strip_prefix_and_unascii tvar_prefix v of
    90           SOME w => make_tvar w
    91         | NONE   => make_tvar v)
    92   | hol_type_from_metis_term ctxt (Metis_Term.Fn(x, tys)) =
    93      (case strip_prefix_and_unascii type_const_prefix x of
    94           SOME tc => Type (invert_const tc,
    95                            map (hol_type_from_metis_term ctxt) tys)
    96         | NONE    =>
    97       case strip_prefix_and_unascii tfree_prefix x of
    98           SOME tf => make_tfree ctxt tf
    99         | NONE    => raise Fail ("hol_type_from_metis_term: " ^ x));
   100 
   101 (*Maps metis terms to isabelle terms*)
   102 fun hol_term_from_metis_PT ctxt fol_tm =
   103   let val thy = Proof_Context.theory_of ctxt
   104       val _ = trace_msg ctxt (fn () => "hol_term_from_metis_PT: " ^
   105                                        Metis_Term.toString fol_tm)
   106       fun tm_to_tt (Metis_Term.Var v) =
   107              (case strip_prefix_and_unascii tvar_prefix v of
   108                   SOME w => SomeType (make_tvar w)
   109                 | NONE =>
   110               case strip_prefix_and_unascii schematic_var_prefix v of
   111                   SOME w => SomeTerm (make_var (w, HOLogic.typeT))
   112                 | NONE   => SomeTerm (make_var (v, HOLogic.typeT)))
   113                     (*Var from Metis with a name like _nnn; possibly a type variable*)
   114         | tm_to_tt (Metis_Term.Fn ("{}", [arg])) = tm_to_tt arg   (*hBOOL*)
   115         | tm_to_tt (t as Metis_Term.Fn (".", _)) =
   116             let val (rator,rands) = strip_happ [] t in
   117               case rator of
   118                 Metis_Term.Fn(fname,ts) => applic_to_tt (fname, ts @ rands)
   119               | _ => case tm_to_tt rator of
   120                          SomeTerm t => SomeTerm (list_comb(t, terms_of (map tm_to_tt rands)))
   121                        | _ => raise Fail "tm_to_tt: HO application"
   122             end
   123         | tm_to_tt (Metis_Term.Fn (fname, args)) = applic_to_tt (fname,args)
   124       and applic_to_tt ("=",ts) =
   125             SomeTerm (list_comb(Const (@{const_name HOL.eq}, HOLogic.typeT), terms_of (map tm_to_tt ts)))
   126         | applic_to_tt (a,ts) =
   127             case strip_prefix_and_unascii const_prefix a of
   128                 SOME b =>
   129                   let
   130                     val c = b |> invert_const |> unproxify_const
   131                     val ntypes = num_type_args thy c
   132                     val nterms = length ts - ntypes
   133                     val tts = map tm_to_tt ts
   134                     val tys = types_of (List.take(tts,ntypes))
   135                     val t =
   136                       if String.isPrefix new_skolem_const_prefix c then
   137                         Var ((new_skolem_var_name_from_const c, 1),
   138                              Type_Infer.paramify_vars (tl tys ---> hd tys))
   139                       else
   140                         Const (c, dummyT)
   141                   in if length tys = ntypes then
   142                          apply_list t nterms (List.drop(tts,ntypes))
   143                      else
   144                        raise Fail ("Constant " ^ c ^ " expects " ^ string_of_int ntypes ^
   145                                    " but gets " ^ string_of_int (length tys) ^
   146                                    " type arguments\n" ^
   147                                    cat_lines (map (Syntax.string_of_typ ctxt) tys) ^
   148                                    " the terms are \n" ^
   149                                    cat_lines (map (Syntax.string_of_term ctxt) (terms_of tts)))
   150                      end
   151               | NONE => (*Not a constant. Is it a type constructor?*)
   152             case strip_prefix_and_unascii type_const_prefix a of
   153                 SOME b =>
   154                 SomeType (Type (invert_const b, types_of (map tm_to_tt ts)))
   155               | NONE => (*Maybe a TFree. Should then check that ts=[].*)
   156             case strip_prefix_and_unascii tfree_prefix a of
   157                 SOME b => SomeType (make_tfree ctxt b)
   158               | NONE => (*a fixed variable? They are Skolem functions.*)
   159             case strip_prefix_and_unascii fixed_var_prefix a of
   160                 SOME b =>
   161                   let val opr = Free (b, HOLogic.typeT)
   162                   in  apply_list opr (length ts) (map tm_to_tt ts)  end
   163               | NONE => raise Fail ("unexpected metis function: " ^ a)
   164   in
   165     case tm_to_tt fol_tm of
   166       SomeTerm t => t
   167     | SomeType T => raise TYPE ("fol_tm_to_tt: Term expected", [T], [])
   168   end
   169 
   170 (*Maps fully-typed metis terms to isabelle terms*)
   171 fun hol_term_from_metis_FT ctxt fol_tm =
   172   let val _ = trace_msg ctxt (fn () => "hol_term_from_metis_FT: " ^
   173                                        Metis_Term.toString fol_tm)
   174       fun do_const c =
   175         let val c = c |> invert_const |> unproxify_const in
   176           if String.isPrefix new_skolem_const_prefix c then
   177             Var ((new_skolem_var_name_from_const c, 1), dummyT)
   178           else
   179             Const (c, dummyT)
   180         end
   181       fun cvt (Metis_Term.Fn (":", [Metis_Term.Var v, _])) =
   182              (case strip_prefix_and_unascii schematic_var_prefix v of
   183                   SOME w =>  make_var (w, dummyT)
   184                 | NONE   => make_var (v, dummyT))
   185         | cvt (Metis_Term.Fn (":", [Metis_Term.Fn ("=",[]), _])) =
   186             Const (@{const_name HOL.eq}, HOLogic.typeT)
   187         | cvt (Metis_Term.Fn (":", [Metis_Term.Fn (x,[]), ty])) =
   188            (case strip_prefix_and_unascii const_prefix x of
   189                 SOME c => do_const c
   190               | NONE => (*Not a constant. Is it a fixed variable??*)
   191             case strip_prefix_and_unascii fixed_var_prefix x of
   192                 SOME v => Free (v, hol_type_from_metis_term ctxt ty)
   193               | NONE => raise Fail ("hol_term_from_metis_FT bad constant: " ^ x))
   194         | cvt (Metis_Term.Fn (":", [Metis_Term.Fn (".", [tm1,tm2]), _])) =
   195             cvt tm1 $ cvt tm2
   196         | cvt (Metis_Term.Fn (".",[tm1,tm2])) = (*untyped application*)
   197             cvt tm1 $ cvt tm2
   198         | cvt (Metis_Term.Fn ("{}", [arg])) = cvt arg   (*hBOOL*)
   199         | cvt (Metis_Term.Fn ("=", [tm1,tm2])) =
   200             list_comb(Const (@{const_name HOL.eq}, HOLogic.typeT), map cvt [tm1,tm2])
   201         | cvt (t as Metis_Term.Fn (x, [])) =
   202            (case strip_prefix_and_unascii const_prefix x of
   203                 SOME c => do_const c
   204               | NONE => (*Not a constant. Is it a fixed variable??*)
   205             case strip_prefix_and_unascii fixed_var_prefix x of
   206                 SOME v => Free (v, dummyT)
   207               | NONE => (trace_msg ctxt (fn () =>
   208                                       "hol_term_from_metis_FT bad const: " ^ x);
   209                          hol_term_from_metis_PT ctxt t))
   210         | cvt t = (trace_msg ctxt (fn () =>
   211                    "hol_term_from_metis_FT bad term: " ^ Metis_Term.toString t);
   212                    hol_term_from_metis_PT ctxt t)
   213   in fol_tm |> cvt end
   214 
   215 fun atp_name_from_metis s =
   216   case find_first (fn (_, (s', _)) => s' = s) metis_name_table of
   217     SOME ((s, _), (_, swap)) => (s, swap)
   218   | _ => (s, false)
   219 fun atp_term_from_metis (Metis_Term.Fn (s, tms)) =
   220     let val (s, swap) = atp_name_from_metis s in
   221       ATerm (s, tms |> map atp_term_from_metis |> swap ? rev)
   222     end
   223   | atp_term_from_metis (Metis_Term.Var s) = ATerm (s, [])
   224 
   225 fun hol_term_from_metis_MX ctxt sym_tab =
   226   atp_term_from_metis #> term_from_atp ctxt false sym_tab NONE
   227 
   228 fun hol_term_from_metis ctxt FO _ = hol_term_from_metis_PT ctxt
   229   | hol_term_from_metis ctxt HO _ = hol_term_from_metis_PT ctxt
   230   | hol_term_from_metis ctxt FT _ = hol_term_from_metis_FT ctxt
   231   | hol_term_from_metis ctxt MX sym_tab = hol_term_from_metis_MX ctxt sym_tab
   232 
   233 fun atp_literal_from_metis (pos, atom) =
   234   atom |> Metis_Term.Fn |> atp_term_from_metis |> AAtom |> not pos ? mk_anot
   235 fun atp_clause_from_metis [] = AAtom (ATerm (tptp_false, []))
   236   | atp_clause_from_metis lits =
   237     lits |> map atp_literal_from_metis |> mk_aconns AOr
   238 
   239 fun hol_clause_from_metis ctxt sym_tab =
   240   Metis_Thm.clause
   241   #> Metis_LiteralSet.toList
   242   #> atp_clause_from_metis
   243   #> prop_from_atp ctxt false sym_tab
   244 
   245 fun hol_terms_from_metis ctxt mode old_skolems sym_tab fol_tms =
   246   let val ts = map (hol_term_from_metis ctxt mode sym_tab) fol_tms
   247       val _ = trace_msg ctxt (fn () => "  calling type inference:")
   248       val _ = app (fn t => trace_msg ctxt
   249                                      (fn () => Syntax.string_of_term ctxt t)) ts
   250       val ts' = ts |> map (reveal_old_skolem_terms old_skolems)
   251                    |> infer_types ctxt
   252       val _ = app (fn t => trace_msg ctxt
   253                     (fn () => "  final term: " ^ Syntax.string_of_term ctxt t ^
   254                               " of type " ^ Syntax.string_of_typ ctxt (type_of t)))
   255                   ts'
   256   in  ts'  end;
   257 
   258 (* ------------------------------------------------------------------------- *)
   259 (* FOL step Inference Rules                                                  *)
   260 (* ------------------------------------------------------------------------- *)
   261 
   262 (*for debugging only*)
   263 (*
   264 fun print_thpair ctxt (fth,th) =
   265   (trace_msg ctxt (fn () => "=============================================");
   266    trace_msg ctxt (fn () => "Metis: " ^ Metis_Thm.toString fth);
   267    trace_msg ctxt (fn () => "Isabelle: " ^ Display.string_of_thm_without_context th));
   268 *)
   269 
   270 fun lookth th_pairs fth =
   271   the (AList.lookup (uncurry Metis_Thm.equal) th_pairs fth)
   272   handle Option.Option =>
   273          raise Fail ("Failed to find Metis theorem " ^ Metis_Thm.toString fth)
   274 
   275 fun cterm_incr_types thy idx = cterm_of thy o (map_types (Logic.incr_tvar idx));
   276 
   277 (* INFERENCE RULE: AXIOM *)
   278 
   279 (* This causes variables to have an index of 1 by default. See also "make_var"
   280    above. *)
   281 fun axiom_inf th_pairs th = Thm.incr_indexes 1 (lookth th_pairs th)
   282 
   283 (* INFERENCE RULE: ASSUME *)
   284 
   285 val EXCLUDED_MIDDLE = @{lemma "P ==> ~ P ==> False" by (rule notE)}
   286 
   287 fun inst_excluded_middle thy i_atm =
   288   let val th = EXCLUDED_MIDDLE
   289       val [vx] = Term.add_vars (prop_of th) []
   290       val substs = [(cterm_of thy (Var vx), cterm_of thy i_atm)]
   291   in  cterm_instantiate substs th  end;
   292 
   293 fun assume_inf ctxt mode old_skolems sym_tab atm =
   294   inst_excluded_middle
   295       (Proof_Context.theory_of ctxt)
   296       (singleton (hol_terms_from_metis ctxt mode old_skolems sym_tab)
   297                  (Metis_Term.Fn atm))
   298 
   299 (* INFERENCE RULE: INSTANTIATE (SUBST). Type instantiations are ignored. Trying
   300    to reconstruct them admits new possibilities of errors, e.g. concerning
   301    sorts. Instead we try to arrange that new TVars are distinct and that types
   302    can be inferred from terms. *)
   303 
   304 fun inst_inf ctxt mode old_skolems sym_tab th_pairs fsubst th =
   305   let val thy = Proof_Context.theory_of ctxt
   306       val i_th = lookth th_pairs th
   307       val i_th_vars = Term.add_vars (prop_of i_th) []
   308       fun find_var x = the (List.find (fn ((a,_),_) => a=x) i_th_vars)
   309       fun subst_translation (x,y) =
   310         let val v = find_var x
   311             (* We call "reveal_old_skolem_terms" and "infer_types" below. *)
   312             val t = hol_term_from_metis ctxt mode sym_tab y
   313         in  SOME (cterm_of thy (Var v), t)  end
   314         handle Option.Option =>
   315                (trace_msg ctxt (fn () => "\"find_var\" failed for " ^ x ^
   316                                          " in " ^ Display.string_of_thm ctxt i_th);
   317                 NONE)
   318              | TYPE _ =>
   319                (trace_msg ctxt (fn () => "\"hol_term_from_metis\" failed for " ^ x ^
   320                                          " in " ^ Display.string_of_thm ctxt i_th);
   321                 NONE)
   322       fun remove_typeinst (a, t) =
   323             case strip_prefix_and_unascii schematic_var_prefix a of
   324                 SOME b => SOME (b, t)
   325               | NONE => case strip_prefix_and_unascii tvar_prefix a of
   326                 SOME _ => NONE          (*type instantiations are forbidden!*)
   327               | NONE => SOME (a,t)    (*internal Metis var?*)
   328       val _ = trace_msg ctxt (fn () => "  isa th: " ^ Display.string_of_thm ctxt i_th)
   329       val substs = map_filter remove_typeinst (Metis_Subst.toList fsubst)
   330       val (vars,rawtms) = ListPair.unzip (map_filter subst_translation substs)
   331       val tms = rawtms |> map (reveal_old_skolem_terms old_skolems)
   332                        |> infer_types ctxt
   333       val ctm_of = cterm_incr_types thy (1 + Thm.maxidx_of i_th)
   334       val substs' = ListPair.zip (vars, map ctm_of tms)
   335       val _ = trace_msg ctxt (fn () =>
   336         cat_lines ("subst_translations:" ::
   337           (substs' |> map (fn (x, y) =>
   338             Syntax.string_of_term ctxt (term_of x) ^ " |-> " ^
   339             Syntax.string_of_term ctxt (term_of y)))));
   340   in cterm_instantiate substs' i_th end
   341   handle THM (msg, _, _) => raise METIS ("inst_inf", msg)
   342        | ERROR msg => raise METIS ("inst_inf", msg)
   343 
   344 (* INFERENCE RULE: RESOLVE *)
   345 
   346 (* Like RSN, but we rename apart only the type variables. Vars here typically
   347    have an index of 1, and the use of RSN would increase this typically to 3.
   348    Instantiations of those Vars could then fail. See comment on "make_var". *)
   349 fun resolve_inc_tyvars thy tha i thb =
   350   let
   351     val tha = Drule.incr_type_indexes (1 + Thm.maxidx_of thb) tha
   352     fun aux tha thb =
   353       case Thm.bicompose false (false, tha, nprems_of tha) i thb
   354            |> Seq.list_of |> distinct Thm.eq_thm of
   355         [th] => th
   356       | _ => raise THM ("resolve_inc_tyvars: unique result expected", i,
   357                         [tha, thb])
   358   in
   359     aux tha thb
   360     handle TERM z =>
   361            (* The unifier, which is invoked from "Thm.bicompose", will sometimes
   362               refuse to unify "?a::?'a" with "?a::?'b" or "?a::nat" and throw a
   363               "TERM" exception (with "add_ffpair" as first argument). We then
   364               perform unification of the types of variables by hand and try
   365               again. We could do this the first time around but this error
   366               occurs seldom and we don't want to break existing proofs in subtle
   367               ways or slow them down needlessly. *)
   368            case [] |> fold (Term.add_vars o prop_of) [tha, thb]
   369                    |> AList.group (op =)
   370                    |> maps (fn ((s, _), T :: Ts) =>
   371                                map (fn T' => (Free (s, T), Free (s, T'))) Ts)
   372                    |> rpair (Envir.empty ~1)
   373                    |-> fold (Pattern.unify thy)
   374                    |> Envir.type_env |> Vartab.dest
   375                    |> map (fn (x, (S, T)) =>
   376                               pairself (ctyp_of thy) (TVar (x, S), T)) of
   377              [] => raise TERM z
   378            | ps => aux (instantiate (ps, []) tha) (instantiate (ps, []) thb)
   379   end
   380 
   381 fun s_not (@{const Not} $ t) = t
   382   | s_not t = HOLogic.mk_not t
   383 fun simp_not_not (@{const Not} $ t) = s_not (simp_not_not t)
   384   | simp_not_not t = t
   385 
   386 (* Match untyped terms. *)
   387 fun untyped_aconv (Const (a, _), Const(b, _)) = (a = b)
   388   | untyped_aconv (Free (a, _), Free (b, _)) = (a = b)
   389   | untyped_aconv (Var ((a, _), _), Var ((b, _), _)) = (a = b)
   390   | untyped_aconv (Bound i, Bound j) = (i = j)
   391   | untyped_aconv (Abs (_, _, t), Abs (_, _, u)) = untyped_aconv (t, u)
   392   | untyped_aconv (t1 $ t2, u1 $ u2) =
   393     untyped_aconv (t1, u1) andalso untyped_aconv (t2, u2)
   394   | untyped_aconv _ = false
   395 
   396 (* Finding the relative location of an untyped term within a list of terms *)
   397 fun index_of_literal lit haystack =
   398   let
   399     val normalize = simp_not_not o Envir.eta_contract
   400     val match_lit =
   401       HOLogic.dest_Trueprop #> normalize
   402       #> curry untyped_aconv (lit |> normalize)
   403   in case find_index match_lit haystack of ~1 => raise Empty | n => n + 1 end
   404 
   405 (* Permute a rule's premises to move the i-th premise to the last position. *)
   406 fun make_last i th =
   407   let val n = nprems_of th
   408   in  if 1 <= i andalso i <= n
   409       then Thm.permute_prems (i-1) 1 th
   410       else raise THM("select_literal", i, [th])
   411   end;
   412 
   413 (* Maps a rule that ends "... ==> P ==> False" to "... ==> ~ P" while avoiding
   414    to create double negations. The "select" wrapper is a trick to ensure that
   415    "P ==> ~ False ==> False" is rewritten to "P ==> False", not to "~ P". We
   416    don't use this trick in general because it makes the proof object uglier than
   417    necessary. FIXME. *)
   418 fun negate_head th =
   419   if exists (fn t => t aconv @{prop "~ False"}) (prems_of th) then
   420     (th RS @{thm select_FalseI})
   421     |> fold (rewrite_rule o single)
   422             @{thms not_atomize_select atomize_not_select}
   423   else
   424     th |> fold (rewrite_rule o single) @{thms not_atomize atomize_not}
   425 
   426 (* Maps the clause  [P1,...Pn]==>False to [P1,...,P(i-1),P(i+1),...Pn] ==> ~P *)
   427 val select_literal = negate_head oo make_last
   428 
   429 fun resolve_inf ctxt mode old_skolems sym_tab th_pairs atm th1 th2 =
   430   let
   431     val thy = Proof_Context.theory_of ctxt
   432     val (i_th1, i_th2) = pairself (lookth th_pairs) (th1, th2)
   433     val _ = trace_msg ctxt (fn () => "  isa th1 (pos): " ^ Display.string_of_thm ctxt i_th1)
   434     val _ = trace_msg ctxt (fn () => "  isa th2 (neg): " ^ Display.string_of_thm ctxt i_th2)
   435   in
   436     (* Trivial cases where one operand is type info *)
   437     if Thm.eq_thm (TrueI, i_th1) then
   438       i_th2
   439     else if Thm.eq_thm (TrueI, i_th2) then
   440       i_th1
   441     else
   442       let
   443         val i_atm =
   444           singleton (hol_terms_from_metis ctxt mode old_skolems sym_tab)
   445                     (Metis_Term.Fn atm)
   446         val _ = trace_msg ctxt (fn () => "  atom: " ^ Syntax.string_of_term ctxt i_atm)
   447         val prems_th1 = prems_of i_th1
   448         val prems_th2 = prems_of i_th2
   449         val index_th1 =
   450           index_of_literal (s_not i_atm) prems_th1
   451           handle Empty => raise Fail "Failed to find literal in th1"
   452         val _ = trace_msg ctxt (fn () => "  index_th1: " ^ string_of_int index_th1)
   453         val index_th2 =
   454           index_of_literal i_atm prems_th2
   455           handle Empty => raise Fail "Failed to find literal in th2"
   456         val _ = trace_msg ctxt (fn () => "  index_th2: " ^ string_of_int index_th2)
   457     in
   458       resolve_inc_tyvars thy (select_literal index_th1 i_th1) index_th2 i_th2
   459       handle TERM (s, _) => raise METIS ("resolve_inf", s)
   460     end
   461   end;
   462 
   463 (* INFERENCE RULE: REFL *)
   464 
   465 val REFL_THM = Thm.incr_indexes 2 @{lemma "t ~= t ==> False" by simp}
   466 
   467 val refl_x = cterm_of @{theory} (Var (hd (Term.add_vars (prop_of REFL_THM) [])));
   468 val refl_idx = 1 + Thm.maxidx_of REFL_THM;
   469 
   470 fun refl_inf ctxt mode old_skolems sym_tab t =
   471   let
   472     val thy = Proof_Context.theory_of ctxt
   473     val i_t = singleton (hol_terms_from_metis ctxt mode old_skolems sym_tab) t
   474     val _ = trace_msg ctxt (fn () => "  term: " ^ Syntax.string_of_term ctxt i_t)
   475     val c_t = cterm_incr_types thy refl_idx i_t
   476   in cterm_instantiate [(refl_x, c_t)] REFL_THM end
   477 
   478 (* INFERENCE RULE: EQUALITY *)
   479 
   480 val subst_em = @{lemma "s = t ==> P s ==> ~ P t ==> False" by simp}
   481 val ssubst_em = @{lemma "s = t ==> P t ==> ~ P s ==> False" by simp}
   482 
   483 val metis_eq = Metis_Term.Fn ("=", []);
   484 
   485 (* Equality has no type arguments *)
   486 fun get_ty_arg_size _ (Const (@{const_name HOL.eq}, _)) = 0
   487   | get_ty_arg_size thy (Const (s, _)) =
   488     (num_type_args thy s handle TYPE _ => 0)
   489   | get_ty_arg_size _ _ = 0
   490 
   491 fun equality_inf ctxt mode old_skolems sym_tab (pos, atm) fp fr =
   492   let val thy = Proof_Context.theory_of ctxt
   493       val m_tm = Metis_Term.Fn atm
   494       val [i_atm, i_tm] =
   495         hol_terms_from_metis ctxt mode old_skolems sym_tab [m_tm, fr]
   496       val _ = trace_msg ctxt (fn () => "sign of the literal: " ^ Bool.toString pos)
   497       fun replace_item_list lx 0 (_::ls) = lx::ls
   498         | replace_item_list lx i (l::ls) = l :: replace_item_list lx (i-1) ls
   499       fun path_finder_fail mode tm ps t =
   500         raise Fail ("Cannot replay Metis proof in Isabelle:\n" ^
   501                     "equality_inf, path_finder_" ^ string_of_mode mode ^
   502                     ": path = " ^ space_implode " " (map string_of_int ps) ^
   503                     " isa-term: " ^ Syntax.string_of_term ctxt tm ^
   504                     (case t of
   505                        SOME t => " fol-term: " ^ Metis_Term.toString t
   506                      | NONE => ""))
   507       fun path_finder_FO tm [] = (tm, Bound 0)
   508         | path_finder_FO tm (p::ps) =
   509             let val (tm1,args) = strip_comb tm
   510                 val adjustment = get_ty_arg_size thy tm1
   511                 val p' = if adjustment > p then p else p - adjustment
   512                 val tm_p = nth args p'
   513                   handle Subscript =>
   514                          raise METIS ("equality_inf",
   515                                       string_of_int p ^ " adj " ^
   516                                       string_of_int adjustment ^ " term " ^
   517                                       Syntax.string_of_term ctxt tm)
   518                 val _ = trace_msg ctxt (fn () => "path_finder: " ^ string_of_int p ^
   519                                       "  " ^ Syntax.string_of_term ctxt tm_p)
   520                 val (r,t) = path_finder_FO tm_p ps
   521             in
   522                 (r, list_comb (tm1, replace_item_list t p' args))
   523             end
   524       fun path_finder_HO tm [] = (tm, Bound 0)
   525         | path_finder_HO (t$u) (0::ps) = (fn(x,y) => (x, y$u)) (path_finder_HO t ps)
   526         | path_finder_HO (t$u) (_::ps) = (fn(x,y) => (x, t$y)) (path_finder_HO u ps)
   527         | path_finder_HO tm ps = path_finder_fail HO tm ps NONE
   528       fun path_finder_FT tm [] _ = (tm, Bound 0)
   529         | path_finder_FT tm (0::ps) (Metis_Term.Fn (":", [t1, _])) =
   530             path_finder_FT tm ps t1
   531         | path_finder_FT (t$u) (0::ps) (Metis_Term.Fn (".", [t1, _])) =
   532             (fn(x,y) => (x, y$u)) (path_finder_FT t ps t1)
   533         | path_finder_FT (t$u) (1::ps) (Metis_Term.Fn (".", [_, t2])) =
   534             (fn(x,y) => (x, t$y)) (path_finder_FT u ps t2)
   535         | path_finder_FT tm ps t = path_finder_fail FT tm ps (SOME t)
   536       fun path_finder_MX tm [] _ = (tm, Bound 0)
   537         | path_finder_MX tm (p :: ps) (t as Metis_Term.Fn (s, ts)) =
   538           let val s = s |> unmangled_const_name in
   539             if s = metis_predicator orelse s = prefixed_predicator_name orelse
   540                s = metis_type_tag orelse s = prefixed_type_tag_name then
   541               path_finder_MX tm ps (nth ts p)
   542             else if s = metis_app_op orelse s = prefixed_app_op_name then
   543               let
   544                 val (tm1, tm2) = dest_comb tm
   545                 val p' = p - (length ts - 2)
   546               in
   547                 if p' = 0 then
   548                   path_finder_MX tm1 ps (nth ts p) ||> (fn y => y $ tm2)
   549                 else
   550                   path_finder_MX tm2 ps (nth ts p) ||> (fn y => tm1 $ y)
   551               end
   552             else
   553               let
   554                 val (tm1, args) = strip_comb tm
   555                 val adjustment = length ts - length args
   556                 val p' = if adjustment > p then p else p - adjustment
   557                 val tm_p = nth args p'
   558                   handle Subscript =>
   559                          path_finder_fail MX tm (p :: ps) (SOME t)
   560                 val _ = trace_msg ctxt (fn () =>
   561                     "path_finder: " ^ string_of_int p ^ "  " ^
   562                     Syntax.string_of_term ctxt tm_p)
   563                 val (r, t) = path_finder_MX tm_p ps (nth ts p)
   564               in (r, list_comb (tm1, replace_item_list t p' args)) end
   565           end
   566         | path_finder_MX tm ps t = path_finder_fail MX tm ps (SOME t)
   567       fun path_finder FO tm ps _ = path_finder_FO tm ps
   568         | path_finder HO (tm as Const(@{const_name HOL.eq},_) $ _ $ _) (p::ps) _ =
   569              (*equality: not curried, as other predicates are*)
   570              if p=0 then path_finder_HO tm (0::1::ps)  (*select first operand*)
   571              else path_finder_HO tm (p::ps)        (*1 selects second operand*)
   572         | path_finder HO tm (_ :: ps) (Metis_Term.Fn ("{}", [_])) =
   573              path_finder_HO tm ps      (*if not equality, ignore head to skip hBOOL*)
   574         | path_finder FT (tm as Const(@{const_name HOL.eq}, _) $ _ $ _) (p::ps)
   575                             (Metis_Term.Fn ("=", [t1,t2])) =
   576              (*equality: not curried, as other predicates are*)
   577              if p=0 then path_finder_FT tm (0::1::ps)
   578                           (Metis_Term.Fn (metis_app_op, [Metis_Term.Fn (metis_app_op, [metis_eq,t1]), t2]))
   579                           (*select first operand*)
   580              else path_finder_FT tm (p::ps)
   581                    (Metis_Term.Fn (metis_app_op, [metis_eq, t2]))
   582                    (*1 selects second operand*)
   583         | path_finder FT tm (_ :: ps) (Metis_Term.Fn ("{}", [t1])) = path_finder_FT tm ps t1
   584              (*if not equality, ignore head to skip the hBOOL predicate*)
   585         | path_finder FT tm ps t = path_finder_FT tm ps t  (*really an error case!*)
   586         | path_finder MX tm ps t = path_finder_MX tm ps t
   587       fun path_finder_lit ((nt as Const (@{const_name Not}, _)) $ tm_a) idx =
   588             let val (tm, tm_rslt) = path_finder mode tm_a idx m_tm
   589             in (tm, nt $ tm_rslt) end
   590         | path_finder_lit tm_a idx = path_finder mode tm_a idx m_tm
   591       val (tm_subst, body) = path_finder_lit i_atm fp
   592       val tm_abs = Abs ("x", type_of tm_subst, body)
   593       val _ = trace_msg ctxt (fn () => "abstraction: " ^ Syntax.string_of_term ctxt tm_abs)
   594       val _ = trace_msg ctxt (fn () => "i_tm: " ^ Syntax.string_of_term ctxt i_tm)
   595       val _ = trace_msg ctxt (fn () => "located term: " ^ Syntax.string_of_term ctxt tm_subst)
   596       val imax = maxidx_of_term (i_tm $ tm_abs $ tm_subst)  (*ill typed but gives right max*)
   597       val subst' = Thm.incr_indexes (imax+1) (if pos then subst_em else ssubst_em)
   598       val _ = trace_msg ctxt (fn () => "subst' " ^ Display.string_of_thm ctxt subst')
   599       val eq_terms = map (pairself (cterm_of thy))
   600         (ListPair.zip (OldTerm.term_vars (prop_of subst'), [tm_abs, tm_subst, i_tm]))
   601   in  cterm_instantiate eq_terms subst'  end;
   602 
   603 val factor = Seq.hd o distinct_subgoals_tac
   604 
   605 fun one_step ctxt mode old_skolems sym_tab th_pairs p =
   606   case p of
   607     (fol_th, Metis_Proof.Axiom _) => axiom_inf th_pairs fol_th |> factor
   608   | (_, Metis_Proof.Assume f_atm) =>
   609     assume_inf ctxt mode old_skolems sym_tab f_atm
   610   | (_, Metis_Proof.Metis_Subst (f_subst, f_th1)) =>
   611     inst_inf ctxt mode old_skolems sym_tab th_pairs f_subst f_th1 |> factor
   612   | (_, Metis_Proof.Resolve(f_atm, f_th1, f_th2)) =>
   613     resolve_inf ctxt mode old_skolems sym_tab th_pairs f_atm f_th1 f_th2
   614     |> factor
   615   | (_, Metis_Proof.Refl f_tm) => refl_inf ctxt mode old_skolems sym_tab f_tm
   616   | (_, Metis_Proof.Equality (f_lit, f_p, f_r)) =>
   617     equality_inf ctxt mode old_skolems sym_tab f_lit f_p f_r
   618 
   619 fun flexflex_first_order th =
   620   case Thm.tpairs_of th of
   621       [] => th
   622     | pairs =>
   623         let val thy = theory_of_thm th
   624             val (_, tenv) =
   625               fold (Pattern.first_order_match thy) pairs (Vartab.empty, Vartab.empty)
   626             val t_pairs = map Meson.term_pair_of (Vartab.dest tenv)
   627             val th' = Thm.instantiate ([], map (pairself (cterm_of thy)) t_pairs) th
   628         in  th'  end
   629         handle THM _ => th;
   630 
   631 fun is_metis_literal_genuine (_, (s, _)) = not (String.isPrefix class_prefix s)
   632 fun is_isabelle_literal_genuine t =
   633   case t of _ $ (Const (@{const_name Meson.skolem}, _) $ _) => false | _ => true
   634 
   635 fun count p xs = fold (fn x => if p x then Integer.add 1 else I) xs 0
   636 
   637 (* Seldomly needed hack. A Metis clause is represented as a set, so duplicate
   638    disjuncts are impossible. In the Isabelle proof, in spite of efforts to
   639    eliminate them, duplicates sometimes appear with slightly different (but
   640    unifiable) types. *)
   641 fun resynchronize ctxt fol_th th =
   642   let
   643     val num_metis_lits =
   644       count is_metis_literal_genuine
   645             (Metis_LiteralSet.toList (Metis_Thm.clause fol_th))
   646     val num_isabelle_lits = count is_isabelle_literal_genuine (prems_of th)
   647   in
   648     if num_metis_lits >= num_isabelle_lits then
   649       th
   650     else
   651       let
   652         val (prems0, concl) = th |> prop_of |> Logic.strip_horn
   653         val prems = prems0 |> distinct untyped_aconv
   654         val goal = Logic.list_implies (prems, concl)
   655       in
   656         if length prems = length prems0 then
   657           raise METIS ("resynchronize", "Out of sync")
   658         else
   659           Goal.prove ctxt [] [] goal (K (cut_rules_tac [th] 1
   660                                          THEN ALLGOALS assume_tac))
   661           |> resynchronize ctxt fol_th
   662       end
   663   end
   664 
   665 fun replay_one_inference ctxt mode old_skolems sym_tab (fol_th, inf) th_pairs =
   666   if not (null th_pairs) andalso
   667      prop_of (snd (hd th_pairs)) aconv @{prop False} then
   668     (* Isabelle sometimes identifies literals (premises) that are distinct in
   669        Metis (e.g., because of type variables). We give the Isabelle proof the
   670        benefice of the doubt. *)
   671     th_pairs
   672   else
   673     let
   674       val _ = trace_msg ctxt
   675                   (fn () => "=============================================")
   676       val _ = trace_msg ctxt
   677                   (fn () => "METIS THM: " ^ Metis_Thm.toString fol_th)
   678       val _ = trace_msg ctxt
   679                   (fn () => "INFERENCE: " ^ Metis_Proof.inferenceToString inf)
   680       val th = one_step ctxt mode old_skolems sym_tab th_pairs (fol_th, inf)
   681                |> flexflex_first_order
   682                |> resynchronize ctxt fol_th
   683       val _ = trace_msg ctxt
   684                   (fn () => "ISABELLE THM: " ^ Display.string_of_thm ctxt th)
   685       val _ = trace_msg ctxt
   686                   (fn () => "=============================================")
   687     in (fol_th, th) :: th_pairs end
   688 
   689 (* It is normally sufficient to apply "assume_tac" to unify the conclusion with
   690    one of the premises. Unfortunately, this sometimes yields "Variable
   691    ?SK_a_b_c_x has two distinct types" errors. To avoid this, we instantiate the
   692    variables before applying "assume_tac". Typical constraints are of the form
   693      ?SK_a_b_c_x SK_d_e_f_y ... SK_a_b_c_x ... SK_g_h_i_z =?= SK_a_b_c_x,
   694    where the nonvariables are goal parameters. *)
   695 fun unify_first_prem_with_concl thy i th =
   696   let
   697     val goal = Logic.get_goal (prop_of th) i |> Envir.beta_eta_contract
   698     val prem = goal |> Logic.strip_assums_hyp |> hd
   699     val concl = goal |> Logic.strip_assums_concl
   700     fun pair_untyped_aconv (t1, t2) (u1, u2) =
   701       untyped_aconv (t1, u1) andalso untyped_aconv (t2, u2)
   702     fun add_terms tp inst =
   703       if exists (pair_untyped_aconv tp) inst then inst
   704       else tp :: map (apsnd (subst_atomic [tp])) inst
   705     fun is_flex t =
   706       case strip_comb t of
   707         (Var _, args) => forall is_Bound args
   708       | _ => false
   709     fun unify_flex flex rigid =
   710       case strip_comb flex of
   711         (Var (z as (_, T)), args) =>
   712         add_terms (Var z,
   713           fold_rev (curry absdummy) (take (length args) (binder_types T)) rigid)
   714       | _ => I
   715     fun unify_potential_flex comb atom =
   716       if is_flex comb then unify_flex comb atom
   717       else if is_Var atom then add_terms (atom, comb)
   718       else I
   719     fun unify_terms (t, u) =
   720       case (t, u) of
   721         (t1 $ t2, u1 $ u2) =>
   722         if is_flex t then unify_flex t u
   723         else if is_flex u then unify_flex u t
   724         else fold unify_terms [(t1, u1), (t2, u2)]
   725       | (_ $ _, _) => unify_potential_flex t u
   726       | (_, _ $ _) => unify_potential_flex u t
   727       | (Var _, _) => add_terms (t, u)
   728       | (_, Var _) => add_terms (u, t)
   729       | _ => I
   730     val t_inst =
   731       [] |> try (unify_terms (prem, concl) #> map (pairself (cterm_of thy)))
   732          |> the_default [] (* FIXME *)
   733   in th |> cterm_instantiate t_inst end
   734 
   735 val copy_prem = @{lemma "P ==> (P ==> P ==> Q) ==> Q" by fast}
   736 
   737 fun copy_prems_tac [] ns i =
   738     if forall (curry (op =) 1) ns then all_tac else copy_prems_tac (rev ns) [] i
   739   | copy_prems_tac (1 :: ms) ns i =
   740     rotate_tac 1 i THEN copy_prems_tac ms (1 :: ns) i
   741   | copy_prems_tac (m :: ms) ns i =
   742     etac copy_prem i THEN copy_prems_tac ms (m div 2 :: (m + 1) div 2 :: ns) i
   743 
   744 (* Metis generates variables of the form _nnn. *)
   745 val is_metis_fresh_variable = String.isPrefix "_"
   746 
   747 fun instantiate_forall_tac thy t i st =
   748   let
   749     val params = Logic.strip_params (Logic.get_goal (prop_of st) i) |> rev
   750     fun repair (t as (Var ((s, _), _))) =
   751         (case find_index (fn (s', _) => s' = s) params of
   752            ~1 => t
   753          | j => Bound j)
   754       | repair (t $ u) =
   755         (case (repair t, repair u) of
   756            (t as Bound j, u as Bound k) =>
   757            (* This is a rather subtle trick to repair the discrepancy between
   758               the fully skolemized term that MESON gives us (where existentials
   759               were pulled out) and the reality. *)
   760            if k > j then t else t $ u
   761          | (t, u) => t $ u)
   762       | repair t = t
   763     val t' = t |> repair |> fold (curry absdummy) (map snd params)
   764     fun do_instantiate th =
   765       case Term.add_vars (prop_of th) []
   766            |> filter_out ((Meson_Clausify.is_zapped_var_name orf
   767                            is_metis_fresh_variable) o fst o fst) of
   768         [] => th
   769       | [var as (_, T)] =>
   770         let
   771           val var_binder_Ts = T |> binder_types |> take (length params) |> rev
   772           val var_body_T = T |> funpow (length params) range_type
   773           val tyenv =
   774             Vartab.empty |> Type.raw_unifys (fastype_of t :: map snd params,
   775                                              var_body_T :: var_binder_Ts)
   776           val env =
   777             Envir.Envir {maxidx = Vartab.fold (Integer.max o snd o fst) tyenv 0,
   778                          tenv = Vartab.empty, tyenv = tyenv}
   779           val ty_inst =
   780             Vartab.fold (fn (x, (S, T)) =>
   781                             cons (pairself (ctyp_of thy) (TVar (x, S), T)))
   782                         tyenv []
   783           val t_inst =
   784             [pairself (cterm_of thy o Envir.norm_term env) (Var var, t')]
   785         in th |> instantiate (ty_inst, t_inst) end
   786       | _ => raise Fail "expected a single non-zapped, non-Metis Var"
   787   in
   788     (DETERM (etac @{thm allE} i THEN rotate_tac ~1 i)
   789      THEN PRIMITIVE do_instantiate) st
   790   end
   791 
   792 fun fix_exists_tac t =
   793   etac @{thm exE} THEN' rename_tac [t |> dest_Var |> fst |> fst]
   794 
   795 fun release_quantifier_tac thy (skolem, t) =
   796   (if skolem then fix_exists_tac else instantiate_forall_tac thy) t
   797 
   798 fun release_clusters_tac _ _ _ [] = K all_tac
   799   | release_clusters_tac thy ax_counts substs
   800                          ((ax_no, cluster_no) :: clusters) =
   801     let
   802       val cluster_of_var =
   803         Meson_Clausify.cluster_of_zapped_var_name o fst o fst o dest_Var
   804       fun in_right_cluster ((_, (cluster_no', _)), _) = cluster_no' = cluster_no
   805       val cluster_substs =
   806         substs
   807         |> map_filter (fn (ax_no', (_, (_, tsubst))) =>
   808                           if ax_no' = ax_no then
   809                             tsubst |> map (apfst cluster_of_var)
   810                                    |> filter (in_right_cluster o fst)
   811                                    |> map (apfst snd)
   812                                    |> SOME
   813                           else
   814                             NONE)
   815       fun do_cluster_subst cluster_subst =
   816         map (release_quantifier_tac thy) cluster_subst @ [rotate_tac 1]
   817       val first_prem = find_index (fn (ax_no', _) => ax_no' = ax_no) substs
   818     in
   819       rotate_tac first_prem
   820       THEN' (EVERY' (maps do_cluster_subst cluster_substs))
   821       THEN' rotate_tac (~ first_prem - length cluster_substs)
   822       THEN' release_clusters_tac thy ax_counts substs clusters
   823     end
   824 
   825 fun cluster_key ((ax_no, (cluster_no, index_no)), skolem) =
   826   (ax_no, (cluster_no, (skolem, index_no)))
   827 fun cluster_ord p =
   828   prod_ord int_ord (prod_ord int_ord (prod_ord bool_ord int_ord))
   829            (pairself cluster_key p)
   830 
   831 val tysubst_ord =
   832   list_ord (prod_ord Term_Ord.fast_indexname_ord
   833                      (prod_ord Term_Ord.sort_ord Term_Ord.typ_ord))
   834 
   835 structure Int_Tysubst_Table =
   836   Table(type key = int * (indexname * (sort * typ)) list
   837         val ord = prod_ord int_ord tysubst_ord)
   838 
   839 structure Int_Pair_Graph =
   840   Graph(type key = int * int val ord = prod_ord int_ord int_ord)
   841 
   842 fun shuffle_key (((axiom_no, (_, index_no)), _), _) = (axiom_no, index_no)
   843 fun shuffle_ord p = prod_ord int_ord int_ord (pairself shuffle_key p)
   844 
   845 (* Attempts to derive the theorem "False" from a theorem of the form
   846    "P1 ==> ... ==> Pn ==> False", where the "Pi"s are to be discharged using the
   847    specified axioms. The axioms have leading "All" and "Ex" quantifiers, which
   848    must be eliminated first. *)
   849 fun discharge_skolem_premises ctxt axioms prems_imp_false =
   850   if prop_of prems_imp_false aconv @{prop False} then
   851     prems_imp_false
   852   else
   853     let
   854       val thy = Proof_Context.theory_of ctxt
   855       fun match_term p =
   856         let
   857           val (tyenv, tenv) =
   858             Pattern.first_order_match thy p (Vartab.empty, Vartab.empty)
   859           val tsubst =
   860             tenv |> Vartab.dest
   861                  |> filter (Meson_Clausify.is_zapped_var_name o fst o fst)
   862                  |> sort (cluster_ord
   863                           o pairself (Meson_Clausify.cluster_of_zapped_var_name
   864                                       o fst o fst))
   865                  |> map (Meson.term_pair_of
   866                          #> pairself (Envir.subst_term_types tyenv))
   867           val tysubst = tyenv |> Vartab.dest
   868         in (tysubst, tsubst) end
   869       fun subst_info_for_prem subgoal_no prem =
   870         case prem of
   871           _ $ (Const (@{const_name Meson.skolem}, _) $ (_ $ t $ num)) =>
   872           let val ax_no = HOLogic.dest_nat num in
   873             (ax_no, (subgoal_no,
   874                      match_term (nth axioms ax_no |> the |> snd, t)))
   875           end
   876         | _ => raise TERM ("discharge_skolem_premises: Malformed premise",
   877                            [prem])
   878       fun cluster_of_var_name skolem s =
   879         case try Meson_Clausify.cluster_of_zapped_var_name s of
   880           NONE => NONE
   881         | SOME ((ax_no, (cluster_no, _)), skolem') =>
   882           if skolem' = skolem andalso cluster_no > 0 then
   883             SOME (ax_no, cluster_no)
   884           else
   885             NONE
   886       fun clusters_in_term skolem t =
   887         Term.add_var_names t [] |> map_filter (cluster_of_var_name skolem o fst)
   888       fun deps_for_term_subst (var, t) =
   889         case clusters_in_term false var of
   890           [] => NONE
   891         | [(ax_no, cluster_no)] =>
   892           SOME ((ax_no, cluster_no),
   893                 clusters_in_term true t
   894                 |> cluster_no > 1 ? cons (ax_no, cluster_no - 1))
   895         | _ => raise TERM ("discharge_skolem_premises: Expected Var", [var])
   896       val prems = Logic.strip_imp_prems (prop_of prems_imp_false)
   897       val substs = prems |> map2 subst_info_for_prem (1 upto length prems)
   898                          |> sort (int_ord o pairself fst)
   899       val depss = maps (map_filter deps_for_term_subst o snd o snd o snd) substs
   900       val clusters = maps (op ::) depss
   901       val ordered_clusters =
   902         Int_Pair_Graph.empty
   903         |> fold Int_Pair_Graph.default_node (map (rpair ()) clusters)
   904         |> fold Int_Pair_Graph.add_deps_acyclic depss
   905         |> Int_Pair_Graph.topological_order
   906         handle Int_Pair_Graph.CYCLES _ =>
   907                error "Cannot replay Metis proof in Isabelle without \
   908                      \\"Hilbert_Choice\"."
   909       val ax_counts =
   910         Int_Tysubst_Table.empty
   911         |> fold (fn (ax_no, (_, (tysubst, _))) =>
   912                     Int_Tysubst_Table.map_default ((ax_no, tysubst), 0)
   913                                                   (Integer.add 1)) substs
   914         |> Int_Tysubst_Table.dest
   915       val needed_axiom_props =
   916         0 upto length axioms - 1 ~~ axioms
   917         |> map_filter (fn (_, NONE) => NONE
   918                         | (ax_no, SOME (_, t)) =>
   919                           if exists (fn ((ax_no', _), n) =>
   920                                         ax_no' = ax_no andalso n > 0)
   921                                     ax_counts then
   922                             SOME t
   923                           else
   924                             NONE)
   925       val outer_param_names =
   926         [] |> fold Term.add_var_names needed_axiom_props
   927            |> filter (Meson_Clausify.is_zapped_var_name o fst)
   928            |> map (`(Meson_Clausify.cluster_of_zapped_var_name o fst))
   929            |> filter (fn (((_, (cluster_no, _)), skolem), _) =>
   930                          cluster_no = 0 andalso skolem)
   931            |> sort shuffle_ord |> map (fst o snd)
   932 (* for debugging only:
   933       fun string_for_subst_info (ax_no, (subgoal_no, (tysubst, tsubst))) =
   934         "ax: " ^ string_of_int ax_no ^ "; asm: " ^ string_of_int subgoal_no ^
   935         "; tysubst: " ^ PolyML.makestring tysubst ^ "; tsubst: {" ^
   936         commas (map ((fn (s, t) => s ^ " |-> " ^ t)
   937                      o pairself (Syntax.string_of_term ctxt)) tsubst) ^ "}"
   938       val _ = tracing ("ORDERED CLUSTERS: " ^ PolyML.makestring ordered_clusters)
   939       val _ = tracing ("AXIOM COUNTS: " ^ PolyML.makestring ax_counts)
   940       val _ = tracing ("OUTER PARAMS: " ^ PolyML.makestring outer_param_names)
   941       val _ = tracing ("SUBSTS (" ^ string_of_int (length substs) ^ "):\n" ^
   942                        cat_lines (map string_for_subst_info substs))
   943 *)
   944       fun cut_and_ex_tac axiom =
   945         cut_rules_tac [axiom] 1
   946         THEN TRY (REPEAT_ALL_NEW (etac @{thm exE}) 1)
   947       fun rotation_for_subgoal i =
   948         find_index (fn (_, (subgoal_no, _)) => subgoal_no = i) substs
   949     in
   950       Goal.prove ctxt [] [] @{prop False}
   951           (K (DETERM (EVERY (map (cut_and_ex_tac o fst o the o nth axioms o fst
   952                                   o fst) ax_counts)
   953                       THEN rename_tac outer_param_names 1
   954                       THEN copy_prems_tac (map snd ax_counts) [] 1)
   955               THEN release_clusters_tac thy ax_counts substs ordered_clusters 1
   956               THEN match_tac [prems_imp_false] 1
   957               THEN ALLGOALS (fn i =>
   958                        rtac @{thm Meson.skolem_COMBK_I} i
   959                        THEN rotate_tac (rotation_for_subgoal i) i
   960                        THEN PRIMITIVE (unify_first_prem_with_concl thy i)
   961                        THEN assume_tac i
   962                        THEN flexflex_tac)))
   963       handle ERROR _ =>
   964              error ("Cannot replay Metis proof in Isabelle:\n\
   965                     \Error when discharging Skolem assumptions.")
   966     end
   967 
   968 end;