src/HOL/Tools/Sledgehammer/metis_reconstruct.ML
changeset 39497 fa16349939b7
parent 39495 bb4fb9ffe2d1
child 39498 e8aef7ea9cbb
equal deleted inserted replaced
39496:a52a4e4399c1 39497:fa16349939b7
     7 Proof reconstruction for Metis.
     7 Proof reconstruction for Metis.
     8 *)
     8 *)
     9 
     9 
    10 signature METIS_RECONSTRUCT =
    10 signature METIS_RECONSTRUCT =
    11 sig
    11 sig
       
    12   type mode = Metis_Translate.mode
       
    13 
       
    14   val trace: bool Unsynchronized.ref
       
    15   val lookth : (Metis_Thm.thm * 'a) list -> Metis_Thm.thm -> 'a
       
    16   val replay_one_inference :
       
    17     Proof.context -> mode -> (string * term) list
       
    18     -> Metis_Thm.thm * Metis_Proof.inference -> (Metis_Thm.thm * thm) list
       
    19     -> (Metis_Thm.thm * thm) list
    12 end;
    20 end;
    13 
    21 
    14 structure Metis_Reconstruct : METIS_RECONSTRUCT =
    22 structure Metis_Reconstruct : METIS_RECONSTRUCT =
    15 struct
    23 struct
    16 
    24 
       
    25 open Metis_Translate
       
    26 
       
    27 val trace = Unsynchronized.ref false
       
    28 fun trace_msg msg = if !trace then tracing (msg ()) else ()
       
    29 
       
    30 datatype term_or_type = Term of Term.term | Type of Term.typ;
       
    31 
       
    32 fun terms_of [] = []
       
    33   | terms_of (Term t :: tts) = t :: terms_of tts
       
    34   | terms_of (Type _ :: tts) = terms_of tts;
       
    35 
       
    36 fun types_of [] = []
       
    37   | types_of (Term (Term.Var ((a,idx), _)) :: tts) =
       
    38       if String.isPrefix "_" a then
       
    39           (*Variable generated by Metis, which might have been a type variable.*)
       
    40           TVar (("'" ^ a, idx), HOLogic.typeS) :: types_of tts
       
    41       else types_of tts
       
    42   | types_of (Term _ :: tts) = types_of tts
       
    43   | types_of (Type T :: tts) = T :: types_of tts;
       
    44 
       
    45 fun apply_list rator nargs rands =
       
    46   let val trands = terms_of rands
       
    47   in  if length trands = nargs then Term (list_comb(rator, trands))
       
    48       else raise Fail
       
    49         ("apply_list: wrong number of arguments: " ^ Syntax.string_of_term_global Pure.thy rator ^
       
    50           " expected " ^ Int.toString nargs ^
       
    51           " received " ^ commas (map (Syntax.string_of_term_global Pure.thy) trands))
       
    52   end;
       
    53 
       
    54 fun infer_types ctxt =
       
    55   Syntax.check_terms (ProofContext.set_mode ProofContext.mode_pattern ctxt);
       
    56 
       
    57 (*We use 1 rather than 0 because variable references in clauses may otherwise conflict
       
    58   with variable constraints in the goal...at least, type inference often fails otherwise.
       
    59   SEE ALSO axiom_inf below.*)
       
    60 fun mk_var (w,T) = Term.Var((w,1), T);
       
    61 
       
    62 (*include the default sort, if available*)
       
    63 fun mk_tfree ctxt w =
       
    64   let val ww = "'" ^ w
       
    65   in  TFree(ww, the_default HOLogic.typeS (Variable.def_sort ctxt (ww, ~1)))  end;
       
    66 
       
    67 (*Remove the "apply" operator from an HO term*)
       
    68 fun strip_happ args (Metis_Term.Fn(".",[t,u])) = strip_happ (u::args) t
       
    69   | strip_happ args x = (x, args);
       
    70 
       
    71 fun make_tvar s = TVar (("'" ^ s, 0), HOLogic.typeS)
       
    72 
       
    73 fun smart_invert_const "fequal" = @{const_name HOL.eq}
       
    74   | smart_invert_const s = invert_const s
       
    75 
       
    76 fun hol_type_from_metis_term _ (Metis_Term.Var v) =
       
    77      (case strip_prefix_and_unascii tvar_prefix v of
       
    78           SOME w => make_tvar w
       
    79         | NONE   => make_tvar v)
       
    80   | hol_type_from_metis_term ctxt (Metis_Term.Fn(x, tys)) =
       
    81      (case strip_prefix_and_unascii type_const_prefix x of
       
    82           SOME tc => Term.Type (smart_invert_const tc,
       
    83                                 map (hol_type_from_metis_term ctxt) tys)
       
    84         | NONE    =>
       
    85       case strip_prefix_and_unascii tfree_prefix x of
       
    86           SOME tf => mk_tfree ctxt tf
       
    87         | NONE    => raise Fail ("hol_type_from_metis_term: " ^ x));
       
    88 
       
    89 (*Maps metis terms to isabelle terms*)
       
    90 fun hol_term_from_metis_PT ctxt fol_tm =
       
    91   let val thy = ProofContext.theory_of ctxt
       
    92       val _ = trace_msg (fn () => "hol_term_from_metis_PT: " ^
       
    93                                   Metis_Term.toString fol_tm)
       
    94       fun tm_to_tt (Metis_Term.Var v) =
       
    95              (case strip_prefix_and_unascii tvar_prefix v of
       
    96                   SOME w => Type (make_tvar w)
       
    97                 | NONE =>
       
    98               case strip_prefix_and_unascii schematic_var_prefix v of
       
    99                   SOME w => Term (mk_var (w, HOLogic.typeT))
       
   100                 | NONE   => Term (mk_var (v, HOLogic.typeT)) )
       
   101                     (*Var from Metis with a name like _nnn; possibly a type variable*)
       
   102         | tm_to_tt (Metis_Term.Fn ("{}", [arg])) = tm_to_tt arg   (*hBOOL*)
       
   103         | tm_to_tt (t as Metis_Term.Fn (".",_)) =
       
   104             let val (rator,rands) = strip_happ [] t
       
   105             in  case rator of
       
   106                     Metis_Term.Fn(fname,ts) => applic_to_tt (fname, ts @ rands)
       
   107                   | _ => case tm_to_tt rator of
       
   108                              Term t => Term (list_comb(t, terms_of (map tm_to_tt rands)))
       
   109                            | _ => raise Fail "tm_to_tt: HO application"
       
   110             end
       
   111         | tm_to_tt (Metis_Term.Fn (fname, args)) = applic_to_tt (fname,args)
       
   112       and applic_to_tt ("=",ts) =
       
   113             Term (list_comb(Const (@{const_name HOL.eq}, HOLogic.typeT), terms_of (map tm_to_tt ts)))
       
   114         | applic_to_tt (a,ts) =
       
   115             case strip_prefix_and_unascii const_prefix a of
       
   116                 SOME b =>
       
   117                   let val c = smart_invert_const b
       
   118                       val ntypes = num_type_args thy c
       
   119                       val nterms = length ts - ntypes
       
   120                       val tts = map tm_to_tt ts
       
   121                       val tys = types_of (List.take(tts,ntypes))
       
   122                   in if length tys = ntypes then
       
   123                          apply_list (Const (c, dummyT)) nterms (List.drop(tts,ntypes))
       
   124                      else
       
   125                        raise Fail ("Constant " ^ c ^ " expects " ^ Int.toString ntypes ^
       
   126                                    " but gets " ^ Int.toString (length tys) ^
       
   127                                    " type arguments\n" ^
       
   128                                    cat_lines (map (Syntax.string_of_typ ctxt) tys) ^
       
   129                                    " the terms are \n" ^
       
   130                                    cat_lines (map (Syntax.string_of_term ctxt) (terms_of tts)))
       
   131                      end
       
   132               | NONE => (*Not a constant. Is it a type constructor?*)
       
   133             case strip_prefix_and_unascii type_const_prefix a of
       
   134                 SOME b =>
       
   135                   Type (Term.Type (smart_invert_const b, types_of (map tm_to_tt ts)))
       
   136               | NONE => (*Maybe a TFree. Should then check that ts=[].*)
       
   137             case strip_prefix_and_unascii tfree_prefix a of
       
   138                 SOME b => Type (mk_tfree ctxt b)
       
   139               | NONE => (*a fixed variable? They are Skolem functions.*)
       
   140             case strip_prefix_and_unascii fixed_var_prefix a of
       
   141                 SOME b =>
       
   142                   let val opr = Term.Free(b, HOLogic.typeT)
       
   143                   in  apply_list opr (length ts) (map tm_to_tt ts)  end
       
   144               | NONE => raise Fail ("unexpected metis function: " ^ a)
       
   145   in
       
   146     case tm_to_tt fol_tm of
       
   147       Term t => t
       
   148     | _ => raise Fail "fol_tm_to_tt: Term expected"
       
   149   end
       
   150 
       
   151 (*Maps fully-typed metis terms to isabelle terms*)
       
   152 fun hol_term_from_metis_FT ctxt fol_tm =
       
   153   let val _ = trace_msg (fn () => "hol_term_from_metis_FT: " ^
       
   154                                   Metis_Term.toString fol_tm)
       
   155       fun cvt (Metis_Term.Fn ("ti", [Metis_Term.Var v, _])) =
       
   156              (case strip_prefix_and_unascii schematic_var_prefix v of
       
   157                   SOME w =>  mk_var(w, dummyT)
       
   158                 | NONE   => mk_var(v, dummyT))
       
   159         | cvt (Metis_Term.Fn ("ti", [Metis_Term.Fn ("=",[]), _])) =
       
   160             Const (@{const_name HOL.eq}, HOLogic.typeT)
       
   161         | cvt (Metis_Term.Fn ("ti", [Metis_Term.Fn (x,[]), ty])) =
       
   162            (case strip_prefix_and_unascii const_prefix x of
       
   163                 SOME c => Const (smart_invert_const c, dummyT)
       
   164               | NONE => (*Not a constant. Is it a fixed variable??*)
       
   165             case strip_prefix_and_unascii fixed_var_prefix x of
       
   166                 SOME v => Free (v, hol_type_from_metis_term ctxt ty)
       
   167               | NONE => raise Fail ("hol_term_from_metis_FT bad constant: " ^ x))
       
   168         | cvt (Metis_Term.Fn ("ti", [Metis_Term.Fn (".",[tm1,tm2]), _])) =
       
   169             cvt tm1 $ cvt tm2
       
   170         | cvt (Metis_Term.Fn (".",[tm1,tm2])) = (*untyped application*)
       
   171             cvt tm1 $ cvt tm2
       
   172         | cvt (Metis_Term.Fn ("{}", [arg])) = cvt arg   (*hBOOL*)
       
   173         | cvt (Metis_Term.Fn ("=", [tm1,tm2])) =
       
   174             list_comb(Const (@{const_name HOL.eq}, HOLogic.typeT), map cvt [tm1,tm2])
       
   175         | cvt (t as Metis_Term.Fn (x, [])) =
       
   176            (case strip_prefix_and_unascii const_prefix x of
       
   177                 SOME c => Const (smart_invert_const c, dummyT)
       
   178               | NONE => (*Not a constant. Is it a fixed variable??*)
       
   179             case strip_prefix_and_unascii fixed_var_prefix x of
       
   180                 SOME v => Free (v, dummyT)
       
   181               | NONE => (trace_msg (fn () => "hol_term_from_metis_FT bad const: " ^ x);
       
   182                   hol_term_from_metis_PT ctxt t))
       
   183         | cvt t = (trace_msg (fn () => "hol_term_from_metis_FT bad term: " ^ Metis_Term.toString t);
       
   184             hol_term_from_metis_PT ctxt t)
       
   185   in fol_tm |> cvt end
       
   186 
       
   187 fun hol_term_from_metis FT = hol_term_from_metis_FT
       
   188   | hol_term_from_metis _ = hol_term_from_metis_PT
       
   189 
       
   190 fun hol_terms_from_fol ctxt mode skolems fol_tms =
       
   191   let val ts = map (hol_term_from_metis mode ctxt) fol_tms
       
   192       val _ = trace_msg (fn () => "  calling type inference:")
       
   193       val _ = app (fn t => trace_msg (fn () => Syntax.string_of_term ctxt t)) ts
       
   194       val ts' = ts |> map (reveal_skolem_terms skolems) |> infer_types ctxt
       
   195       val _ = app (fn t => trace_msg
       
   196                     (fn () => "  final term: " ^ Syntax.string_of_term ctxt t ^
       
   197                               "  of type  " ^ Syntax.string_of_typ ctxt (type_of t)))
       
   198                   ts'
       
   199   in  ts'  end;
       
   200 
       
   201 (* ------------------------------------------------------------------------- *)
       
   202 (* FOL step Inference Rules                                                  *)
       
   203 (* ------------------------------------------------------------------------- *)
       
   204 
       
   205 (*for debugging only*)
       
   206 (*
       
   207 fun print_thpair (fth,th) =
       
   208   (trace_msg (fn () => "=============================================");
       
   209    trace_msg (fn () => "Metis: " ^ Metis_Thm.toString fth);
       
   210    trace_msg (fn () => "Isabelle: " ^ Display.string_of_thm_without_context th));
       
   211 *)
       
   212 
       
   213 fun lookth thpairs (fth : Metis_Thm.thm) =
       
   214   the (AList.lookup (uncurry Metis_Thm.equal) thpairs fth)
       
   215   handle Option.Option =>
       
   216          raise Fail ("Failed to find Metis theorem " ^ Metis_Thm.toString fth)
       
   217 
       
   218 fun cterm_incr_types thy idx = cterm_of thy o (map_types (Logic.incr_tvar idx));
       
   219 
       
   220 (* INFERENCE RULE: AXIOM *)
       
   221 
       
   222 fun axiom_inf thpairs th = Thm.incr_indexes 1 (lookth thpairs th);
       
   223     (*This causes variables to have an index of 1 by default. SEE ALSO mk_var above.*)
       
   224 
       
   225 (* INFERENCE RULE: ASSUME *)
       
   226 
       
   227 val EXCLUDED_MIDDLE = @{lemma "P ==> ~ P ==> False" by (rule notE)}
       
   228 
       
   229 fun inst_excluded_middle thy i_atm =
       
   230   let val th = EXCLUDED_MIDDLE
       
   231       val [vx] = Term.add_vars (prop_of th) []
       
   232       val substs = [(cterm_of thy (Var vx), cterm_of thy i_atm)]
       
   233   in  cterm_instantiate substs th  end;
       
   234 
       
   235 fun assume_inf ctxt mode skolems atm =
       
   236   inst_excluded_middle
       
   237       (ProofContext.theory_of ctxt)
       
   238       (singleton (hol_terms_from_fol ctxt mode skolems) (Metis_Term.Fn atm))
       
   239 
       
   240 (* INFERENCE RULE: INSTANTIATE (Subst). Type instantiations are ignored. Trying
       
   241    to reconstruct them admits new possibilities of errors, e.g. concerning
       
   242    sorts. Instead we try to arrange that new TVars are distinct and that types
       
   243    can be inferred from terms.*)
       
   244 
       
   245 fun inst_inf ctxt mode skolems thpairs fsubst th =
       
   246   let val thy = ProofContext.theory_of ctxt
       
   247       val i_th   = lookth thpairs th
       
   248       val i_th_vars = Term.add_vars (prop_of i_th) []
       
   249       fun find_var x = the (List.find (fn ((a,_),_) => a=x) i_th_vars)
       
   250       fun subst_translation (x,y) =
       
   251             let val v = find_var x
       
   252                 (* We call "reveal_skolem_terms" and "infer_types" below. *)
       
   253                 val t = hol_term_from_metis mode ctxt y
       
   254             in  SOME (cterm_of thy (Var v), t)  end
       
   255             handle Option =>
       
   256                 (trace_msg (fn() => "\"find_var\" failed for the variable " ^ x ^
       
   257                                        " in " ^ Display.string_of_thm ctxt i_th);
       
   258                  NONE)
       
   259       fun remove_typeinst (a, t) =
       
   260             case strip_prefix_and_unascii schematic_var_prefix a of
       
   261                 SOME b => SOME (b, t)
       
   262               | NONE => case strip_prefix_and_unascii tvar_prefix a of
       
   263                 SOME _ => NONE          (*type instantiations are forbidden!*)
       
   264               | NONE => SOME (a,t)    (*internal Metis var?*)
       
   265       val _ = trace_msg (fn () => "  isa th: " ^ Display.string_of_thm ctxt i_th)
       
   266       val substs = map_filter remove_typeinst (Metis_Subst.toList fsubst)
       
   267       val (vars,rawtms) = ListPair.unzip (map_filter subst_translation substs)
       
   268       val tms = rawtms |> map (reveal_skolem_terms skolems) |> infer_types ctxt
       
   269       val ctm_of = cterm_incr_types thy (1 + Thm.maxidx_of i_th)
       
   270       val substs' = ListPair.zip (vars, map ctm_of tms)
       
   271       val _ = trace_msg (fn () =>
       
   272         cat_lines ("subst_translations:" ::
       
   273           (substs' |> map (fn (x, y) =>
       
   274             Syntax.string_of_term ctxt (term_of x) ^ " |-> " ^
       
   275             Syntax.string_of_term ctxt (term_of y)))));
       
   276   in cterm_instantiate substs' i_th end
       
   277   handle THM (msg, _, _) =>
       
   278          error ("Cannot replay Metis proof in Isabelle:\n" ^ msg)
       
   279 
       
   280 (* INFERENCE RULE: RESOLVE *)
       
   281 
       
   282 (* Like RSN, but we rename apart only the type variables. Vars here typically
       
   283    have an index of 1, and the use of RSN would increase this typically to 3.
       
   284    Instantiations of those Vars could then fail. See comment on "mk_var". *)
       
   285 fun resolve_inc_tyvars thy tha i thb =
       
   286   let
       
   287     val tha = Drule.incr_type_indexes (1 + Thm.maxidx_of thb) tha
       
   288     fun aux tha thb =
       
   289       case Thm.bicompose false (false, tha, nprems_of tha) i thb
       
   290            |> Seq.list_of |> distinct Thm.eq_thm of
       
   291         [th] => th
       
   292       | _ => raise THM ("resolve_inc_tyvars: unique result expected", i,
       
   293                         [tha, thb])
       
   294   in
       
   295     aux tha thb
       
   296     handle TERM z =>
       
   297            (* The unifier, which is invoked from "Thm.bicompose", will sometimes
       
   298               refuse to unify "?a::?'a" with "?a::?'b" or "?a::nat" and throw a
       
   299               "TERM" exception (with "add_ffpair" as first argument). We then
       
   300               perform unification of the types of variables by hand and try
       
   301               again. We could do this the first time around but this error
       
   302               occurs seldom and we don't want to break existing proofs in subtle
       
   303               ways or slow them down needlessly. *)
       
   304            case [] |> fold (Term.add_vars o prop_of) [tha, thb]
       
   305                    |> AList.group (op =)
       
   306                    |> maps (fn ((s, _), T :: Ts) =>
       
   307                                map (fn T' => (Free (s, T), Free (s, T'))) Ts)
       
   308                    |> rpair (Envir.empty ~1)
       
   309                    |-> fold (Pattern.unify thy)
       
   310                    |> Envir.type_env |> Vartab.dest
       
   311                    |> map (fn (x, (S, T)) =>
       
   312                               pairself (ctyp_of thy) (TVar (x, S), T)) of
       
   313              [] => raise TERM z
       
   314            | ps => aux (instantiate (ps, []) tha) (instantiate (ps, []) thb)
       
   315   end
       
   316 
       
   317 fun mk_not (Const (@{const_name Not}, _) $ b) = b
       
   318   | mk_not b = HOLogic.mk_not b
       
   319 
       
   320 (* Match untyped terms. *)
       
   321 fun untyped_aconv (Const (a, _)) (Const(b, _)) = (a = b)
       
   322   | untyped_aconv (Free (a, _)) (Free (b, _)) = (a = b)
       
   323   | untyped_aconv (Var ((a, _), _)) (Var ((b, _), _)) =
       
   324     (a = b) (* The index is ignored, for some reason. *)
       
   325   | untyped_aconv (Bound i) (Bound j) = (i = j)
       
   326   | untyped_aconv (Abs (_, _, t)) (Abs (_, _, u)) = untyped_aconv t u
       
   327   | untyped_aconv (t1 $ t2) (u1 $ u2) =
       
   328     untyped_aconv t1 u1 andalso untyped_aconv t2 u2
       
   329   | untyped_aconv _ _ = false
       
   330 
       
   331 (* Finding the relative location of an untyped term within a list of terms *)
       
   332 fun literal_index lit =
       
   333   let
       
   334     val lit = Envir.eta_contract lit
       
   335     fun get _ [] = raise Empty
       
   336       | get n (x :: xs) =
       
   337         if untyped_aconv lit (Envir.eta_contract (HOLogic.dest_Trueprop x)) then
       
   338           n
       
   339         else
       
   340           get (n+1) xs
       
   341   in get 1 end
       
   342 
       
   343 fun resolve_inf ctxt mode skolems thpairs atm th1 th2 =
       
   344   let
       
   345     val thy = ProofContext.theory_of ctxt
       
   346     val i_th1 = lookth thpairs th1 and i_th2 = lookth thpairs th2
       
   347     val _ = trace_msg (fn () => "  isa th1 (pos): " ^ Display.string_of_thm ctxt i_th1)
       
   348     val _ = trace_msg (fn () => "  isa th2 (neg): " ^ Display.string_of_thm ctxt i_th2)
       
   349   in
       
   350     (* Trivial cases where one operand is type info *)
       
   351     if Thm.eq_thm (TrueI, i_th1) then
       
   352       i_th2
       
   353     else if Thm.eq_thm (TrueI, i_th2) then
       
   354       i_th1
       
   355     else
       
   356       let
       
   357         val i_atm = singleton (hol_terms_from_fol ctxt mode skolems)
       
   358                               (Metis_Term.Fn atm)
       
   359         val _ = trace_msg (fn () => "  atom: " ^ Syntax.string_of_term ctxt i_atm)
       
   360         val prems_th1 = prems_of i_th1
       
   361         val prems_th2 = prems_of i_th2
       
   362         val index_th1 = literal_index (mk_not i_atm) prems_th1
       
   363               handle Empty => raise Fail "Failed to find literal in th1"
       
   364         val _ = trace_msg (fn () => "  index_th1: " ^ Int.toString index_th1)
       
   365         val index_th2 = literal_index i_atm prems_th2
       
   366               handle Empty => raise Fail "Failed to find literal in th2"
       
   367         val _ = trace_msg (fn () => "  index_th2: " ^ Int.toString index_th2)
       
   368     in
       
   369       resolve_inc_tyvars thy (Meson.select_literal index_th1 i_th1) index_th2
       
   370                          i_th2
       
   371     end
       
   372   end;
       
   373 
       
   374 (* INFERENCE RULE: REFL *)
       
   375 
       
   376 val REFL_THM = Thm.incr_indexes 2 @{lemma "t ~= t ==> False" by simp}
       
   377 
       
   378 val refl_x = cterm_of @{theory} (Var (hd (Term.add_vars (prop_of REFL_THM) [])));
       
   379 val refl_idx = 1 + Thm.maxidx_of REFL_THM;
       
   380 
       
   381 fun refl_inf ctxt mode skolems t =
       
   382   let val thy = ProofContext.theory_of ctxt
       
   383       val i_t = singleton (hol_terms_from_fol ctxt mode skolems) t
       
   384       val _ = trace_msg (fn () => "  term: " ^ Syntax.string_of_term ctxt i_t)
       
   385       val c_t = cterm_incr_types thy refl_idx i_t
       
   386   in  cterm_instantiate [(refl_x, c_t)] REFL_THM  end;
       
   387 
       
   388 (* INFERENCE RULE: EQUALITY *)
       
   389 
       
   390 val subst_em = @{lemma "s = t ==> P s ==> ~ P t ==> False" by simp}
       
   391 val ssubst_em = @{lemma "s = t ==> P t ==> ~ P s ==> False" by simp}
       
   392 
       
   393 val metis_eq = Metis_Term.Fn ("=", []);
       
   394 
       
   395 fun get_ty_arg_size _ (Const (@{const_name HOL.eq}, _)) = 0  (*equality has no type arguments*)
       
   396   | get_ty_arg_size thy (Const (c, _)) = (num_type_args thy c handle TYPE _ => 0)
       
   397   | get_ty_arg_size _ _ = 0;
       
   398 
       
   399 fun equality_inf ctxt mode skolems (pos, atm) fp fr =
       
   400   let val thy = ProofContext.theory_of ctxt
       
   401       val m_tm = Metis_Term.Fn atm
       
   402       val [i_atm,i_tm] = hol_terms_from_fol ctxt mode skolems [m_tm, fr]
       
   403       val _ = trace_msg (fn () => "sign of the literal: " ^ Bool.toString pos)
       
   404       fun replace_item_list lx 0 (_::ls) = lx::ls
       
   405         | replace_item_list lx i (l::ls) = l :: replace_item_list lx (i-1) ls
       
   406       fun path_finder_FO tm [] = (tm, Term.Bound 0)
       
   407         | path_finder_FO tm (p::ps) =
       
   408             let val (tm1,args) = strip_comb tm
       
   409                 val adjustment = get_ty_arg_size thy tm1
       
   410                 val p' = if adjustment > p then p else p-adjustment
       
   411                 val tm_p = List.nth(args,p')
       
   412                   handle Subscript =>
       
   413                          error ("Cannot replay Metis proof in Isabelle:\n" ^
       
   414                                 "equality_inf: " ^ Int.toString p ^ " adj " ^
       
   415                                 Int.toString adjustment ^ " term " ^
       
   416                                 Syntax.string_of_term ctxt tm)
       
   417                 val _ = trace_msg (fn () => "path_finder: " ^ Int.toString p ^
       
   418                                       "  " ^ Syntax.string_of_term ctxt tm_p)
       
   419                 val (r,t) = path_finder_FO tm_p ps
       
   420             in
       
   421                 (r, list_comb (tm1, replace_item_list t p' args))
       
   422             end
       
   423       fun path_finder_HO tm [] = (tm, Term.Bound 0)
       
   424         | path_finder_HO (t$u) (0::ps) = (fn(x,y) => (x, y$u)) (path_finder_HO t ps)
       
   425         | path_finder_HO (t$u) (_::ps) = (fn(x,y) => (x, t$y)) (path_finder_HO u ps)
       
   426         | path_finder_HO tm ps =
       
   427           raise Fail ("equality_inf, path_finder_HO: path = " ^
       
   428                       space_implode " " (map Int.toString ps) ^
       
   429                       " isa-term: " ^  Syntax.string_of_term ctxt tm)
       
   430       fun path_finder_FT tm [] _ = (tm, Term.Bound 0)
       
   431         | path_finder_FT tm (0::ps) (Metis_Term.Fn ("ti", [t1, _])) =
       
   432             path_finder_FT tm ps t1
       
   433         | path_finder_FT (t$u) (0::ps) (Metis_Term.Fn (".", [t1, _])) =
       
   434             (fn(x,y) => (x, y$u)) (path_finder_FT t ps t1)
       
   435         | path_finder_FT (t$u) (1::ps) (Metis_Term.Fn (".", [_, t2])) =
       
   436             (fn(x,y) => (x, t$y)) (path_finder_FT u ps t2)
       
   437         | path_finder_FT tm ps t =
       
   438           raise Fail ("equality_inf, path_finder_FT: path = " ^
       
   439                       space_implode " " (map Int.toString ps) ^
       
   440                       " isa-term: " ^  Syntax.string_of_term ctxt tm ^
       
   441                       " fol-term: " ^ Metis_Term.toString t)
       
   442       fun path_finder FO tm ps _ = path_finder_FO tm ps
       
   443         | path_finder HO (tm as Const(@{const_name HOL.eq},_) $ _ $ _) (p::ps) _ =
       
   444              (*equality: not curried, as other predicates are*)
       
   445              if p=0 then path_finder_HO tm (0::1::ps)  (*select first operand*)
       
   446              else path_finder_HO tm (p::ps)        (*1 selects second operand*)
       
   447         | path_finder HO tm (_ :: ps) (Metis_Term.Fn ("{}", [_])) =
       
   448              path_finder_HO tm ps      (*if not equality, ignore head to skip hBOOL*)
       
   449         | path_finder FT (tm as Const(@{const_name HOL.eq}, _) $ _ $ _) (p::ps)
       
   450                             (Metis_Term.Fn ("=", [t1,t2])) =
       
   451              (*equality: not curried, as other predicates are*)
       
   452              if p=0 then path_finder_FT tm (0::1::ps)
       
   453                           (Metis_Term.Fn (".", [Metis_Term.Fn (".", [metis_eq,t1]), t2]))
       
   454                           (*select first operand*)
       
   455              else path_finder_FT tm (p::ps)
       
   456                    (Metis_Term.Fn (".", [metis_eq,t2]))
       
   457                    (*1 selects second operand*)
       
   458         | path_finder FT tm (_ :: ps) (Metis_Term.Fn ("{}", [t1])) = path_finder_FT tm ps t1
       
   459              (*if not equality, ignore head to skip the hBOOL predicate*)
       
   460         | path_finder FT tm ps t = path_finder_FT tm ps t  (*really an error case!*)
       
   461       fun path_finder_lit ((nt as Const (@{const_name Not}, _)) $ tm_a) idx =
       
   462             let val (tm, tm_rslt) = path_finder mode tm_a idx m_tm
       
   463             in (tm, nt $ tm_rslt) end
       
   464         | path_finder_lit tm_a idx = path_finder mode tm_a idx m_tm
       
   465       val (tm_subst, body) = path_finder_lit i_atm fp
       
   466       val tm_abs = Term.Abs ("x", type_of tm_subst, body)
       
   467       val _ = trace_msg (fn () => "abstraction: " ^ Syntax.string_of_term ctxt tm_abs)
       
   468       val _ = trace_msg (fn () => "i_tm: " ^ Syntax.string_of_term ctxt i_tm)
       
   469       val _ = trace_msg (fn () => "located term: " ^ Syntax.string_of_term ctxt tm_subst)
       
   470       val imax = maxidx_of_term (i_tm $ tm_abs $ tm_subst)  (*ill typed but gives right max*)
       
   471       val subst' = Thm.incr_indexes (imax+1) (if pos then subst_em else ssubst_em)
       
   472       val _ = trace_msg (fn () => "subst' " ^ Display.string_of_thm ctxt subst')
       
   473       val eq_terms = map (pairself (cterm_of thy))
       
   474         (ListPair.zip (OldTerm.term_vars (prop_of subst'), [tm_abs, tm_subst, i_tm]))
       
   475   in  cterm_instantiate eq_terms subst'  end;
       
   476 
       
   477 val factor = Seq.hd o distinct_subgoals_tac;
       
   478 
       
   479 fun step ctxt mode skolems thpairs p =
       
   480   case p of
       
   481     (fol_th, Metis_Proof.Axiom _) => factor (axiom_inf thpairs fol_th)
       
   482   | (_, Metis_Proof.Assume f_atm) => assume_inf ctxt mode skolems f_atm
       
   483   | (_, Metis_Proof.Metis_Subst (f_subst, f_th1)) =>
       
   484     factor (inst_inf ctxt mode skolems thpairs f_subst f_th1)
       
   485   | (_, Metis_Proof.Resolve(f_atm, f_th1, f_th2)) =>
       
   486     factor (resolve_inf ctxt mode skolems thpairs f_atm f_th1 f_th2)
       
   487   | (_, Metis_Proof.Refl f_tm) => refl_inf ctxt mode skolems f_tm
       
   488   | (_, Metis_Proof.Equality (f_lit, f_p, f_r)) =>
       
   489     equality_inf ctxt mode skolems f_lit f_p f_r
       
   490 
       
   491 fun is_real_literal (_, (c, _)) = not (String.isPrefix class_prefix c)
       
   492 
       
   493 fun replay_one_inference ctxt mode skolems (fol_th, inf) thpairs =
       
   494   let
       
   495     val _ = trace_msg (fn () => "=============================================")
       
   496     val _ = trace_msg (fn () => "METIS THM: " ^ Metis_Thm.toString fol_th)
       
   497     val _ = trace_msg (fn () => "INFERENCE: " ^ Metis_Proof.inferenceToString inf)
       
   498     val th = Meson.flexflex_first_order (step ctxt mode skolems
       
   499                                               thpairs (fol_th, inf))
       
   500     val _ = trace_msg (fn () => "ISABELLE THM: " ^ Display.string_of_thm ctxt th)
       
   501     val _ = trace_msg (fn () => "=============================================")
       
   502     val n_metis_lits =
       
   503       length (filter is_real_literal (Metis_LiteralSet.toList (Metis_Thm.clause fol_th)))
       
   504     val _ = if nprems_of th = n_metis_lits then ()
       
   505             else error "Cannot replay Metis proof in Isabelle."
       
   506   in (fol_th, th) :: thpairs end
       
   507 
    17 end;
   508 end;