src/HOL/Tools/ATP/atp_reconstruct.ML
changeset 43085 0a2f5b86bdd7
parent 43062 2834548a7a48
child 43093 40e50afbc203
equal deleted inserted replaced
43084:946c8e171ffd 43085:0a2f5b86bdd7
       
     1 (*  Title:      HOL/Tools/ATP/atp_reconstruct.ML
       
     2     Author:     Lawrence C. Paulson, Cambridge University Computer Laboratory
       
     3     Author:     Claire Quigley, Cambridge University Computer Laboratory
       
     4     Author:     Jasmin Blanchette, TU Muenchen
       
     5 
       
     6 Proof reconstruction from ATP proofs.
       
     7 *)
       
     8 
       
     9 signature ATP_RECONSTRUCT =
       
    10 sig
       
    11   type 'a proof = 'a ATP_Proof.proof
       
    12   type locality = ATP_Translate.locality
       
    13   type type_system = ATP_Translate.type_system
       
    14 
       
    15   datatype reconstructor =
       
    16     Metis |
       
    17     MetisFT |
       
    18     SMT of string
       
    19 
       
    20   datatype play =
       
    21     Played of reconstructor * Time.time |
       
    22     Trust_Playable of reconstructor * Time.time option|
       
    23     Failed_to_Play
       
    24 
       
    25   type minimize_command = string list -> string
       
    26   type one_line_params =
       
    27     play * string * (string * locality) list * minimize_command * int * int
       
    28   type isar_params =
       
    29     bool * bool * int * type_system * string Symtab.table * int list list
       
    30     * int * (string * locality) list vector * int Symtab.table * string proof
       
    31     * thm
       
    32   val repair_conjecture_shape_and_fact_names :
       
    33     type_system -> string -> int list list -> int
       
    34     -> (string * locality) list vector -> int list
       
    35     -> int list list * int * (string * locality) list vector * int list
       
    36   val used_facts_in_atp_proof :
       
    37     Proof.context -> type_system -> int -> (string * locality) list vector
       
    38     -> string proof -> (string * locality) list
       
    39   val used_facts_in_unsound_atp_proof :
       
    40     Proof.context -> type_system -> int list list -> int
       
    41     -> (string * locality) list vector -> 'a proof -> string list option
       
    42   val uses_typed_helpers : int list -> 'a proof -> bool
       
    43   val reconstructor_name : reconstructor -> string
       
    44   val one_line_proof_text : one_line_params -> string
       
    45   val isar_proof_text :
       
    46     Proof.context -> bool -> isar_params -> one_line_params -> string
       
    47   val proof_text :
       
    48     Proof.context -> bool -> isar_params -> one_line_params -> string
       
    49 end;
       
    50 
       
    51 structure ATP_Reconstruct : ATP_RECONSTRUCT =
       
    52 struct
       
    53 
       
    54 open ATP_Util
       
    55 open ATP_Problem
       
    56 open ATP_Proof
       
    57 open ATP_Translate
       
    58 
       
    59 datatype reconstructor =
       
    60   Metis |
       
    61   MetisFT |
       
    62   SMT of string
       
    63 
       
    64 datatype play =
       
    65   Played of reconstructor * Time.time |
       
    66   Trust_Playable of reconstructor * Time.time option |
       
    67   Failed_to_Play
       
    68 
       
    69 type minimize_command = string list -> string
       
    70 type one_line_params =
       
    71   play * string * (string * locality) list * minimize_command * int * int
       
    72 type isar_params =
       
    73   bool * bool * int * type_system * string Symtab.table * int list list * int
       
    74   * (string * locality) list vector * int Symtab.table * string proof * thm
       
    75 
       
    76 fun is_head_digit s = Char.isDigit (String.sub (s, 0))
       
    77 val scan_integer = Scan.many1 is_head_digit >> (the o Int.fromString o implode)
       
    78 
       
    79 val is_typed_helper_name =
       
    80   String.isPrefix helper_prefix andf String.isSuffix typed_helper_suffix
       
    81 
       
    82 fun find_first_in_list_vector vec key =
       
    83   Vector.foldl (fn (ps, NONE) => AList.lookup (op =) ps key
       
    84                  | (_, value) => value) NONE vec
       
    85 
       
    86 
       
    87 (** SPASS's FLOTTER hack **)
       
    88 
       
    89 (* This is a hack required for keeping track of facts after they have been
       
    90    clausified by SPASS's FLOTTER preprocessor. The "ATP/scripts/spass" script is
       
    91    also part of this hack. *)
       
    92 
       
    93 val set_ClauseFormulaRelationN = "set_ClauseFormulaRelation"
       
    94 
       
    95 fun extract_clause_sequence output =
       
    96   let
       
    97     val tokens_of = String.tokens (not o Char.isAlphaNum)
       
    98     fun extract_num ("clause" :: (ss as _ :: _)) = Int.fromString (List.last ss)
       
    99       | extract_num _ = NONE
       
   100   in output |> split_lines |> map_filter (extract_num o tokens_of) end
       
   101 
       
   102 val parse_clause_formula_pair =
       
   103   $$ "(" |-- scan_integer --| $$ ","
       
   104   -- (Symbol.scan_id ::: Scan.repeat ($$ "," |-- Symbol.scan_id)) --| $$ ")"
       
   105   --| Scan.option ($$ ",")
       
   106 val parse_clause_formula_relation =
       
   107   Scan.this_string set_ClauseFormulaRelationN |-- $$ "("
       
   108   |-- Scan.repeat parse_clause_formula_pair
       
   109 val extract_clause_formula_relation =
       
   110   Substring.full #> Substring.position set_ClauseFormulaRelationN
       
   111   #> snd #> Substring.position "." #> fst #> Substring.string
       
   112   #> raw_explode #> filter_out Symbol.is_blank #> parse_clause_formula_relation
       
   113   #> fst
       
   114 
       
   115 fun maybe_unprefix_fact_number type_sys =
       
   116   polymorphism_of_type_sys type_sys <> Polymorphic
       
   117   ? (space_implode "_" o tl o space_explode "_")
       
   118 
       
   119 fun repair_conjecture_shape_and_fact_names type_sys output conjecture_shape
       
   120         fact_offset fact_names typed_helpers =
       
   121   if String.isSubstring set_ClauseFormulaRelationN output then
       
   122     let
       
   123       val j0 = hd (hd conjecture_shape)
       
   124       val seq = extract_clause_sequence output
       
   125       val name_map = extract_clause_formula_relation output
       
   126       fun renumber_conjecture j =
       
   127         conjecture_prefix ^ string_of_int (j - j0)
       
   128         |> AList.find (fn (s, ss) => member (op =) ss s) name_map
       
   129         |> map (fn s => find_index (curry (op =) s) seq + 1)
       
   130       fun names_for_number j =
       
   131         j |> AList.lookup (op =) name_map |> these
       
   132           |> map_filter (try (unascii_of o maybe_unprefix_fact_number type_sys
       
   133                               o unprefix fact_prefix))
       
   134           |> map (fn name =>
       
   135                      (name, name |> find_first_in_list_vector fact_names |> the)
       
   136                      handle Option.Option =>
       
   137                             error ("No such fact: " ^ quote name ^ "."))
       
   138     in
       
   139       (conjecture_shape |> map (maps renumber_conjecture), 0,
       
   140        seq |> map names_for_number |> Vector.fromList,
       
   141        name_map |> filter (forall is_typed_helper_name o snd) |> map fst)
       
   142     end
       
   143   else
       
   144     (conjecture_shape, fact_offset, fact_names, typed_helpers)
       
   145 
       
   146 val vampire_step_prefix = "f" (* grrr... *)
       
   147 
       
   148 val extract_step_number =
       
   149   Int.fromString o perhaps (try (unprefix vampire_step_prefix))
       
   150 
       
   151 fun resolve_fact type_sys _ fact_names (_, SOME s) =
       
   152     (case try (unprefix fact_prefix) s of
       
   153        SOME s' =>
       
   154        let val s' = s' |> maybe_unprefix_fact_number type_sys |> unascii_of in
       
   155          case find_first_in_list_vector fact_names s' of
       
   156            SOME x => [(s', x)]
       
   157          | NONE => []
       
   158        end
       
   159      | NONE => [])
       
   160   | resolve_fact _ facts_offset fact_names (num, NONE) =
       
   161     (case extract_step_number num of
       
   162        SOME j =>
       
   163        let val j = j - facts_offset in
       
   164          if j > 0 andalso j <= Vector.length fact_names then
       
   165            Vector.sub (fact_names, j - 1)
       
   166          else
       
   167            []
       
   168        end
       
   169      | NONE => [])
       
   170 
       
   171 fun is_fact type_sys conjecture_shape =
       
   172   not o null o resolve_fact type_sys 0 conjecture_shape
       
   173 
       
   174 fun resolve_conjecture _ (_, SOME s) =
       
   175     (case try (unprefix conjecture_prefix) s of
       
   176        SOME s' =>
       
   177        (case Int.fromString s' of
       
   178           SOME j => [j]
       
   179         | NONE => [])
       
   180      | NONE => [])
       
   181   | resolve_conjecture conjecture_shape (num, NONE) =
       
   182     case extract_step_number num of
       
   183       SOME i => (case find_index (exists (curry (op =) i)) conjecture_shape of
       
   184                    ~1 => []
       
   185                  | j => [j])
       
   186     | NONE => []
       
   187 
       
   188 fun is_conjecture conjecture_shape =
       
   189   not o null o resolve_conjecture conjecture_shape
       
   190 
       
   191 fun is_typed_helper _ (_, SOME s) = is_typed_helper_name s
       
   192   | is_typed_helper typed_helpers (num, NONE) =
       
   193     (case extract_step_number num of
       
   194        SOME i => member (op =) typed_helpers i
       
   195      | NONE => false)
       
   196 
       
   197 val leo2_ext = "extcnf_equal_neg"
       
   198 val isa_ext = Thm.get_name_hint @{thm ext}
       
   199 val isa_short_ext = Long_Name.base_name isa_ext
       
   200 
       
   201 fun ext_name ctxt =
       
   202   if Thm.eq_thm_prop (@{thm ext},
       
   203          singleton (Attrib.eval_thms ctxt) (Facts.named isa_short_ext, [])) then
       
   204     isa_short_ext
       
   205   else
       
   206     isa_ext
       
   207 
       
   208 fun add_fact _ type_sys facts_offset fact_names (Inference (name, _, [])) =
       
   209     union (op =) (resolve_fact type_sys facts_offset fact_names name)
       
   210   | add_fact ctxt _ _ _ (Inference (_, _, deps)) =
       
   211     if AList.defined (op =) deps leo2_ext then
       
   212       insert (op =) (ext_name ctxt, General (* or Chained... *))
       
   213     else
       
   214       I
       
   215   | add_fact _ _ _ _ _ = I
       
   216 
       
   217 fun used_facts_in_atp_proof ctxt type_sys facts_offset fact_names atp_proof =
       
   218   if null atp_proof then Vector.foldl (op @) [] fact_names
       
   219   else fold (add_fact ctxt type_sys facts_offset fact_names) atp_proof []
       
   220 
       
   221 fun is_conjecture_referred_to_in_proof conjecture_shape =
       
   222   exists (fn Inference (name, _, []) => is_conjecture conjecture_shape name
       
   223            | _ => false)
       
   224 
       
   225 fun used_facts_in_unsound_atp_proof ctxt type_sys conjecture_shape facts_offset
       
   226                                     fact_names atp_proof =
       
   227   let
       
   228     val used_facts =
       
   229       used_facts_in_atp_proof ctxt type_sys facts_offset fact_names atp_proof
       
   230   in
       
   231     if forall (is_locality_global o snd) used_facts andalso
       
   232        not (is_conjecture_referred_to_in_proof conjecture_shape atp_proof) then
       
   233       SOME (map fst used_facts)
       
   234     else
       
   235       NONE
       
   236   end
       
   237 
       
   238 fun uses_typed_helpers typed_helpers =
       
   239   exists (fn Inference (name, _, []) => is_typed_helper typed_helpers name
       
   240            | _ => false)
       
   241 
       
   242 
       
   243 (** Soft-core proof reconstruction: Metis one-liner **)
       
   244 
       
   245 fun reconstructor_name Metis = "metis"
       
   246   | reconstructor_name MetisFT = "metisFT"
       
   247   | reconstructor_name (SMT _) = "smt"
       
   248 
       
   249 fun reconstructor_settings (SMT settings) = settings
       
   250   | reconstructor_settings _ = ""
       
   251 
       
   252 fun string_for_label (s, num) = s ^ string_of_int num
       
   253 
       
   254 fun show_time NONE = ""
       
   255   | show_time (SOME ext_time) = " (" ^ string_from_ext_time ext_time ^ ")"
       
   256 
       
   257 fun set_settings "" = ""
       
   258   | set_settings settings = "using [[" ^ settings ^ "]] "
       
   259 fun apply_on_subgoal settings _ 1 = set_settings settings ^ "by "
       
   260   | apply_on_subgoal settings 1 _ = set_settings settings ^ "apply "
       
   261   | apply_on_subgoal settings i n =
       
   262     "prefer " ^ string_of_int i ^ " " ^ apply_on_subgoal settings 1 n
       
   263 fun command_call name [] = name
       
   264   | command_call name args = "(" ^ name ^ " " ^ space_implode " " args ^ ")"
       
   265 fun try_command_line banner time command =
       
   266   banner ^ ": " ^ Markup.markup Markup.sendback command ^ show_time time ^ "."
       
   267 fun using_labels [] = ""
       
   268   | using_labels ls =
       
   269     "using " ^ space_implode " " (map string_for_label ls) ^ " "
       
   270 fun reconstructor_command reconstructor i n (ls, ss) =
       
   271   using_labels ls ^
       
   272   apply_on_subgoal (reconstructor_settings reconstructor) i n ^
       
   273   command_call (reconstructor_name reconstructor) ss
       
   274 fun minimize_line _ [] = ""
       
   275   | minimize_line minimize_command ss =
       
   276     case minimize_command ss of
       
   277       "" => ""
       
   278     | command => "\nTo minimize: " ^ Markup.markup Markup.sendback command ^ "."
       
   279 
       
   280 val split_used_facts =
       
   281   List.partition (curry (op =) Chained o snd)
       
   282   #> pairself (sort_distinct (string_ord o pairself fst))
       
   283 
       
   284 fun one_line_proof_text (preplay, banner, used_facts, minimize_command,
       
   285                          subgoal, subgoal_count) =
       
   286   let
       
   287     val (chained, extra) = split_used_facts used_facts
       
   288     val (reconstructor, ext_time) =
       
   289       case preplay of
       
   290         Played (reconstructor, time) =>
       
   291         (SOME reconstructor, (SOME (false, time)))
       
   292       | Trust_Playable (reconstructor, time) =>
       
   293         (SOME reconstructor,
       
   294          case time of
       
   295            NONE => NONE
       
   296          | SOME time =>
       
   297            if time = Time.zeroTime then NONE else SOME (true, time))
       
   298       | Failed_to_Play => (NONE, NONE)
       
   299     val try_line =
       
   300       case reconstructor of
       
   301         SOME r => ([], map fst extra)
       
   302                   |> reconstructor_command r subgoal subgoal_count
       
   303                   |> try_command_line banner ext_time
       
   304       | NONE => "One-line proof reconstruction failed."
       
   305   in try_line ^ minimize_line minimize_command (map fst (extra @ chained)) end
       
   306 
       
   307 (** Hard-core proof reconstruction: structured Isar proofs **)
       
   308 
       
   309 (* Simple simplifications to ensure that sort annotations don't leave a trail of
       
   310    spurious "True"s. *)
       
   311 fun s_not (Const (@{const_name All}, T) $ Abs (s, T', t')) =
       
   312     Const (@{const_name Ex}, T) $ Abs (s, T', s_not t')
       
   313   | s_not (Const (@{const_name Ex}, T) $ Abs (s, T', t')) =
       
   314     Const (@{const_name All}, T) $ Abs (s, T', s_not t')
       
   315   | s_not (@{const HOL.implies} $ t1 $ t2) = @{const HOL.conj} $ t1 $ s_not t2
       
   316   | s_not (@{const HOL.conj} $ t1 $ t2) =
       
   317     @{const HOL.disj} $ s_not t1 $ s_not t2
       
   318   | s_not (@{const HOL.disj} $ t1 $ t2) =
       
   319     @{const HOL.conj} $ s_not t1 $ s_not t2
       
   320   | s_not (@{const False}) = @{const True}
       
   321   | s_not (@{const True}) = @{const False}
       
   322   | s_not (@{const Not} $ t) = t
       
   323   | s_not t = @{const Not} $ t
       
   324 fun s_conj (@{const True}, t2) = t2
       
   325   | s_conj (t1, @{const True}) = t1
       
   326   | s_conj p = HOLogic.mk_conj p
       
   327 fun s_disj (@{const False}, t2) = t2
       
   328   | s_disj (t1, @{const False}) = t1
       
   329   | s_disj p = HOLogic.mk_disj p
       
   330 fun s_imp (@{const True}, t2) = t2
       
   331   | s_imp (t1, @{const False}) = s_not t1
       
   332   | s_imp p = HOLogic.mk_imp p
       
   333 fun s_iff (@{const True}, t2) = t2
       
   334   | s_iff (t1, @{const True}) = t1
       
   335   | s_iff (t1, t2) = HOLogic.eq_const HOLogic.boolT $ t1 $ t2
       
   336 
       
   337 fun forall_of v t = HOLogic.all_const (fastype_of v) $ lambda v t
       
   338 fun exists_of v t = HOLogic.exists_const (fastype_of v) $ lambda v t
       
   339 
       
   340 val indent_size = 2
       
   341 val no_label = ("", ~1)
       
   342 
       
   343 val raw_prefix = "X"
       
   344 val assum_prefix = "A"
       
   345 val have_prefix = "F"
       
   346 
       
   347 fun raw_label_for_name conjecture_shape name =
       
   348   case resolve_conjecture conjecture_shape name of
       
   349     [j] => (conjecture_prefix, j)
       
   350   | _ => case Int.fromString (fst name) of
       
   351            SOME j => (raw_prefix, j)
       
   352          | NONE => (raw_prefix ^ fst name, 0)
       
   353 
       
   354 (**** INTERPRETATION OF TSTP SYNTAX TREES ****)
       
   355 
       
   356 exception FO_TERM of string fo_term list
       
   357 exception FORMULA of (string, string, string fo_term) formula list
       
   358 exception SAME of unit
       
   359 
       
   360 (* Type variables are given the basic sort "HOL.type". Some will later be
       
   361    constrained by information from type literals, or by type inference. *)
       
   362 fun typ_from_fo_term tfrees (u as ATerm (a, us)) =
       
   363   let val Ts = map (typ_from_fo_term tfrees) us in
       
   364     case strip_prefix_and_unascii type_const_prefix a of
       
   365       SOME b => Type (invert_const b, Ts)
       
   366     | NONE =>
       
   367       if not (null us) then
       
   368         raise FO_TERM [u]  (* only "tconst"s have type arguments *)
       
   369       else case strip_prefix_and_unascii tfree_prefix a of
       
   370         SOME b =>
       
   371         let val s = "'" ^ b in
       
   372           TFree (s, AList.lookup (op =) tfrees s |> the_default HOLogic.typeS)
       
   373         end
       
   374       | NONE =>
       
   375         case strip_prefix_and_unascii tvar_prefix a of
       
   376           SOME b => TVar (("'" ^ b, 0), HOLogic.typeS)
       
   377         | NONE =>
       
   378           (* Variable from the ATP, say "X1" *)
       
   379           Type_Infer.param 0 (a, HOLogic.typeS)
       
   380   end
       
   381 
       
   382 (* Type class literal applied to a type. Returns triple of polarity, class,
       
   383    type. *)
       
   384 fun type_constraint_from_term tfrees (u as ATerm (a, us)) =
       
   385   case (strip_prefix_and_unascii class_prefix a,
       
   386         map (typ_from_fo_term tfrees) us) of
       
   387     (SOME b, [T]) => (b, T)
       
   388   | _ => raise FO_TERM [u]
       
   389 
       
   390 (** Accumulate type constraints in a formula: negative type literals **)
       
   391 fun add_var (key, z)  = Vartab.map_default (key, []) (cons z)
       
   392 fun add_type_constraint false (cl, TFree (a ,_)) = add_var ((a, ~1), cl)
       
   393   | add_type_constraint false (cl, TVar (ix, _)) = add_var (ix, cl)
       
   394   | add_type_constraint _ _ = I
       
   395 
       
   396 fun repair_tptp_variable_name f s =
       
   397   let
       
   398     fun subscript_name s n = s ^ nat_subscript n
       
   399     val s = String.map f s
       
   400   in
       
   401     case space_explode "_" s of
       
   402       [_] => (case take_suffix Char.isDigit (String.explode s) of
       
   403                 (cs1 as _ :: _, cs2 as _ :: _) =>
       
   404                 subscript_name (String.implode cs1)
       
   405                                (the (Int.fromString (String.implode cs2)))
       
   406               | (_, _) => s)
       
   407     | [s1, s2] => (case Int.fromString s2 of
       
   408                      SOME n => subscript_name s1 n
       
   409                    | NONE => s)
       
   410     | _ => s
       
   411   end
       
   412   
       
   413 fun num_type_args thy s =
       
   414   (s, Sign.the_const_type thy s) |> Sign.const_typargs thy |> length
       
   415 
       
   416 (* First-order translation. No types are known for variables. "HOLogic.typeT"
       
   417    should allow them to be inferred. *)
       
   418 fun raw_term_from_pred thy sym_tab tfrees =
       
   419   let
       
   420     fun aux opt_T extra_us u =
       
   421       case u of
       
   422         ATerm (a, us) =>
       
   423         if String.isPrefix simple_type_prefix a then
       
   424           @{const True} (* ignore TPTP type information *)
       
   425         else if a = tptp_equal then
       
   426           let val ts = map (aux NONE []) us in
       
   427             if length ts = 2 andalso hd ts aconv List.last ts then
       
   428               (* Vampire is keen on producing these. *)
       
   429               @{const True}
       
   430             else
       
   431               list_comb (Const (@{const_name HOL.eq}, HOLogic.typeT), ts)
       
   432           end
       
   433         else case strip_prefix_and_unascii const_prefix a of
       
   434           SOME s =>
       
   435           let
       
   436             val ((s', s), mangled_us) = s |> unmangled_const |>> `invert_const
       
   437           in
       
   438             if s' = type_tag_name then
       
   439               case mangled_us @ us of
       
   440                 [typ_u, term_u] =>
       
   441                 aux (SOME (typ_from_fo_term tfrees typ_u)) extra_us term_u
       
   442               | _ => raise FO_TERM us
       
   443             else if s' = predicator_name then
       
   444               aux (SOME @{typ bool}) [] (hd us)
       
   445             else if s' = app_op_name then
       
   446               aux opt_T (nth us 1 :: extra_us) (hd us)
       
   447             else if s' = type_pred_name then
       
   448               @{const True} (* ignore type predicates *)
       
   449             else
       
   450               let
       
   451                 val num_ty_args =
       
   452                   length us - the_default 0 (Symtab.lookup sym_tab s)
       
   453                 val (type_us, term_us) =
       
   454                   chop num_ty_args us |>> append mangled_us
       
   455                 (* Extra args from "hAPP" come after any arguments given
       
   456                    directly to the constant. *)
       
   457                 val term_ts = map (aux NONE []) term_us
       
   458                 val extra_ts = map (aux NONE []) extra_us
       
   459                 val T =
       
   460                   if not (null type_us) andalso
       
   461                      num_type_args thy s' = length type_us then
       
   462                     Sign.const_instance thy
       
   463                         (s', map (typ_from_fo_term tfrees) type_us)
       
   464                   else case opt_T of
       
   465                     SOME T => map fastype_of (term_ts @ extra_ts) ---> T
       
   466                   | NONE => HOLogic.typeT
       
   467                 val s' = s' |> unproxify_const
       
   468               in list_comb (Const (s', T), term_ts @ extra_ts) end
       
   469           end
       
   470         | NONE => (* a free or schematic variable *)
       
   471           let
       
   472             val ts = map (aux NONE []) (us @ extra_us)
       
   473             val T = map fastype_of ts ---> HOLogic.typeT
       
   474             val t =
       
   475               case strip_prefix_and_unascii fixed_var_prefix a of
       
   476                 SOME b => Free (b, T)
       
   477               | NONE =>
       
   478                 case strip_prefix_and_unascii schematic_var_prefix a of
       
   479                   SOME b => Var ((b, 0), T)
       
   480                 | NONE =>
       
   481                   if is_tptp_variable a then
       
   482                     Var ((repair_tptp_variable_name Char.toLower a, 0), T)
       
   483                   else
       
   484                     (* Skolem constants? *)
       
   485                     Var ((repair_tptp_variable_name Char.toUpper a, 0), T)
       
   486           in list_comb (t, ts) end
       
   487   in aux (SOME HOLogic.boolT) [] end
       
   488 
       
   489 fun term_from_pred thy sym_tab tfrees pos (u as ATerm (s, _)) =
       
   490   if String.isPrefix class_prefix s then
       
   491     add_type_constraint pos (type_constraint_from_term tfrees u)
       
   492     #> pair @{const True}
       
   493   else
       
   494     pair (raw_term_from_pred thy sym_tab tfrees u)
       
   495 
       
   496 val combinator_table =
       
   497   [(@{const_name Meson.COMBI}, @{thm Meson.COMBI_def_raw}),
       
   498    (@{const_name Meson.COMBK}, @{thm Meson.COMBK_def_raw}),
       
   499    (@{const_name Meson.COMBB}, @{thm Meson.COMBB_def_raw}),
       
   500    (@{const_name Meson.COMBC}, @{thm Meson.COMBC_def_raw}),
       
   501    (@{const_name Meson.COMBS}, @{thm Meson.COMBS_def_raw})]
       
   502 
       
   503 fun uncombine_term thy =
       
   504   let
       
   505     fun aux (t1 $ t2) = betapply (pairself aux (t1, t2))
       
   506       | aux (Abs (s, T, t')) = Abs (s, T, aux t')
       
   507       | aux (t as Const (x as (s, _))) =
       
   508         (case AList.lookup (op =) combinator_table s of
       
   509            SOME thm => thm |> prop_of |> specialize_type thy x
       
   510                            |> Logic.dest_equals |> snd
       
   511          | NONE => t)
       
   512       | aux t = t
       
   513   in aux end
       
   514 
       
   515 (* Update schematic type variables with detected sort constraints. It's not
       
   516    totally clear whether this code is necessary. *)
       
   517 fun repair_tvar_sorts (t, tvar_tab) =
       
   518   let
       
   519     fun do_type (Type (a, Ts)) = Type (a, map do_type Ts)
       
   520       | do_type (TVar (xi, s)) =
       
   521         TVar (xi, the_default s (Vartab.lookup tvar_tab xi))
       
   522       | do_type (TFree z) = TFree z
       
   523     fun do_term (Const (a, T)) = Const (a, do_type T)
       
   524       | do_term (Free (a, T)) = Free (a, do_type T)
       
   525       | do_term (Var (xi, T)) = Var (xi, do_type T)
       
   526       | do_term (t as Bound _) = t
       
   527       | do_term (Abs (a, T, t)) = Abs (a, do_type T, do_term t)
       
   528       | do_term (t1 $ t2) = do_term t1 $ do_term t2
       
   529   in t |> not (Vartab.is_empty tvar_tab) ? do_term end
       
   530 
       
   531 fun quantify_over_var quant_of var_s t =
       
   532   let
       
   533     val vars = [] |> Term.add_vars t |> filter (fn ((s, _), _) => s = var_s)
       
   534                   |> map Var
       
   535   in fold_rev quant_of vars t end
       
   536 
       
   537 (* Interpret an ATP formula as a HOL term, extracting sort constraints as they
       
   538    appear in the formula. *)
       
   539 fun prop_from_formula thy sym_tab tfrees phi =
       
   540   let
       
   541     fun do_formula pos phi =
       
   542       case phi of
       
   543         AQuant (_, [], phi) => do_formula pos phi
       
   544       | AQuant (q, (s, _) :: xs, phi') =>
       
   545         do_formula pos (AQuant (q, xs, phi'))
       
   546         (* FIXME: TFF *)
       
   547         #>> quantify_over_var (case q of
       
   548                                  AForall => forall_of
       
   549                                | AExists => exists_of)
       
   550                               (repair_tptp_variable_name Char.toLower s)
       
   551       | AConn (ANot, [phi']) => do_formula (not pos) phi' #>> s_not
       
   552       | AConn (c, [phi1, phi2]) =>
       
   553         do_formula (pos |> c = AImplies ? not) phi1
       
   554         ##>> do_formula pos phi2
       
   555         #>> (case c of
       
   556                AAnd => s_conj
       
   557              | AOr => s_disj
       
   558              | AImplies => s_imp
       
   559              | AIf => s_imp o swap
       
   560              | AIff => s_iff
       
   561              | ANotIff => s_not o s_iff
       
   562              | _ => raise Fail "unexpected connective")
       
   563       | AAtom tm => term_from_pred thy sym_tab tfrees pos tm
       
   564       | _ => raise FORMULA [phi]
       
   565   in repair_tvar_sorts (do_formula true phi Vartab.empty) end
       
   566 
       
   567 fun check_formula ctxt =
       
   568   Type.constraint HOLogic.boolT
       
   569   #> Syntax.check_term
       
   570          (Proof_Context.set_mode Proof_Context.mode_schematic ctxt)
       
   571 
       
   572 (**** Translation of TSTP files to Isar Proofs ****)
       
   573 
       
   574 fun unvarify_term (Var ((s, 0), T)) = Free (s, T)
       
   575   | unvarify_term t = raise TERM ("unvarify_term: non-Var", [t])
       
   576 
       
   577 fun decode_line sym_tab tfrees (Definition (name, phi1, phi2)) ctxt =
       
   578     let
       
   579       val thy = Proof_Context.theory_of ctxt
       
   580       val t1 = prop_from_formula thy sym_tab tfrees phi1
       
   581       val vars = snd (strip_comb t1)
       
   582       val frees = map unvarify_term vars
       
   583       val unvarify_args = subst_atomic (vars ~~ frees)
       
   584       val t2 = prop_from_formula thy sym_tab tfrees phi2
       
   585       val (t1, t2) =
       
   586         HOLogic.eq_const HOLogic.typeT $ t1 $ t2
       
   587         |> unvarify_args |> uncombine_term thy |> check_formula ctxt
       
   588         |> HOLogic.dest_eq
       
   589     in
       
   590       (Definition (name, t1, t2),
       
   591        fold Variable.declare_term (maps OldTerm.term_frees [t1, t2]) ctxt)
       
   592     end
       
   593   | decode_line sym_tab tfrees (Inference (name, u, deps)) ctxt =
       
   594     let
       
   595       val thy = Proof_Context.theory_of ctxt
       
   596       val t = u |> prop_from_formula thy sym_tab tfrees
       
   597                 |> uncombine_term thy |> check_formula ctxt
       
   598     in
       
   599       (Inference (name, t, deps),
       
   600        fold Variable.declare_term (OldTerm.term_frees t) ctxt)
       
   601     end
       
   602 fun decode_lines ctxt sym_tab tfrees lines =
       
   603   fst (fold_map (decode_line sym_tab tfrees) lines ctxt)
       
   604 
       
   605 fun is_same_inference _ (Definition _) = false
       
   606   | is_same_inference t (Inference (_, t', _)) = t aconv t'
       
   607 
       
   608 (* No "real" literals means only type information (tfree_tcs, clsrel, or
       
   609    clsarity). *)
       
   610 val is_only_type_information = curry (op aconv) HOLogic.true_const
       
   611 
       
   612 fun replace_one_dependency (old, new) dep =
       
   613   if is_same_atp_step dep old then new else [dep]
       
   614 fun replace_dependencies_in_line _ (line as Definition _) = line
       
   615   | replace_dependencies_in_line p (Inference (name, t, deps)) =
       
   616     Inference (name, t, fold (union (op =) o replace_one_dependency p) deps [])
       
   617 
       
   618 (* Discard facts; consolidate adjacent lines that prove the same formula, since
       
   619    they differ only in type information.*)
       
   620 fun add_line _ _ _ (line as Definition _) lines = line :: lines
       
   621   | add_line type_sys conjecture_shape fact_names (Inference (name, t, []))
       
   622              lines =
       
   623     (* No dependencies: fact, conjecture, or (for Vampire) internal facts or
       
   624        definitions. *)
       
   625     if is_fact type_sys fact_names name then
       
   626       (* Facts are not proof lines. *)
       
   627       if is_only_type_information t then
       
   628         map (replace_dependencies_in_line (name, [])) lines
       
   629       (* Is there a repetition? If so, replace later line by earlier one. *)
       
   630       else case take_prefix (not o is_same_inference t) lines of
       
   631         (_, []) => lines (* no repetition of proof line *)
       
   632       | (pre, Inference (name', _, _) :: post) =>
       
   633         pre @ map (replace_dependencies_in_line (name', [name])) post
       
   634       | _ => raise Fail "unexpected inference"
       
   635     else if is_conjecture conjecture_shape name then
       
   636       Inference (name, s_not t, []) :: lines
       
   637     else
       
   638       map (replace_dependencies_in_line (name, [])) lines
       
   639   | add_line _ _ _ (Inference (name, t, deps)) lines =
       
   640     (* Type information will be deleted later; skip repetition test. *)
       
   641     if is_only_type_information t then
       
   642       Inference (name, t, deps) :: lines
       
   643     (* Is there a repetition? If so, replace later line by earlier one. *)
       
   644     else case take_prefix (not o is_same_inference t) lines of
       
   645       (* FIXME: Doesn't this code risk conflating proofs involving different
       
   646          types? *)
       
   647        (_, []) => Inference (name, t, deps) :: lines
       
   648      | (pre, Inference (name', t', _) :: post) =>
       
   649        Inference (name, t', deps) ::
       
   650        pre @ map (replace_dependencies_in_line (name', [name])) post
       
   651      | _ => raise Fail "unexpected inference"
       
   652 
       
   653 (* Recursively delete empty lines (type information) from the proof. *)
       
   654 fun add_nontrivial_line (Inference (name, t, [])) lines =
       
   655     if is_only_type_information t then delete_dependency name lines
       
   656     else Inference (name, t, []) :: lines
       
   657   | add_nontrivial_line line lines = line :: lines
       
   658 and delete_dependency name lines =
       
   659   fold_rev add_nontrivial_line
       
   660            (map (replace_dependencies_in_line (name, [])) lines) []
       
   661 
       
   662 (* ATPs sometimes reuse free variable names in the strangest ways. Removing
       
   663    offending lines often does the trick. *)
       
   664 fun is_bad_free frees (Free x) = not (member (op =) frees x)
       
   665   | is_bad_free _ _ = false
       
   666 
       
   667 fun add_desired_line _ _ _ _ _ (line as Definition (name, _, _)) (j, lines) =
       
   668     (j, line :: map (replace_dependencies_in_line (name, [])) lines)
       
   669   | add_desired_line type_sys isar_shrink_factor conjecture_shape fact_names
       
   670                      frees (Inference (name, t, deps)) (j, lines) =
       
   671     (j + 1,
       
   672      if is_fact type_sys fact_names name orelse
       
   673         is_conjecture conjecture_shape name orelse
       
   674         (* the last line must be kept *)
       
   675         j = 0 orelse
       
   676         (not (is_only_type_information t) andalso
       
   677          null (Term.add_tvars t []) andalso
       
   678          not (exists_subterm (is_bad_free frees) t) andalso
       
   679          length deps >= 2 andalso j mod isar_shrink_factor = 0 andalso
       
   680          (* kill next to last line, which usually results in a trivial step *)
       
   681          j <> 1) then
       
   682        Inference (name, t, deps) :: lines  (* keep line *)
       
   683      else
       
   684        map (replace_dependencies_in_line (name, deps)) lines)  (* drop line *)
       
   685 
       
   686 (** Isar proof construction and manipulation **)
       
   687 
       
   688 fun merge_fact_sets (ls1, ss1) (ls2, ss2) =
       
   689   (union (op =) ls1 ls2, union (op =) ss1 ss2)
       
   690 
       
   691 type label = string * int
       
   692 type facts = label list * string list
       
   693 
       
   694 datatype isar_qualifier = Show | Then | Moreover | Ultimately
       
   695 
       
   696 datatype isar_step =
       
   697   Fix of (string * typ) list |
       
   698   Let of term * term |
       
   699   Assume of label * term |
       
   700   Have of isar_qualifier list * label * term * byline
       
   701 and byline =
       
   702   ByMetis of facts |
       
   703   CaseSplit of isar_step list list * facts
       
   704 
       
   705 fun smart_case_split [] facts = ByMetis facts
       
   706   | smart_case_split proofs facts = CaseSplit (proofs, facts)
       
   707 
       
   708 fun add_fact_from_dependency type_sys conjecture_shape facts_offset fact_names
       
   709                              name =
       
   710   if is_fact type_sys fact_names name then
       
   711     apsnd (union (op =)
       
   712           (map fst (resolve_fact type_sys facts_offset fact_names name)))
       
   713   else
       
   714     apfst (insert (op =) (raw_label_for_name conjecture_shape name))
       
   715 
       
   716 fun step_for_line _ _ _ _ _ (Definition (_, t1, t2)) = Let (t1, t2)
       
   717   | step_for_line _ conjecture_shape _ _ _ (Inference (name, t, [])) =
       
   718     Assume (raw_label_for_name conjecture_shape name, t)
       
   719   | step_for_line type_sys conjecture_shape facts_offset
       
   720                   fact_names j (Inference (name, t, deps)) =
       
   721     Have (if j = 1 then [Show] else [],
       
   722           raw_label_for_name conjecture_shape name,
       
   723           fold_rev forall_of (map Var (Term.add_vars t [])) t,
       
   724           ByMetis (fold (add_fact_from_dependency type_sys conjecture_shape
       
   725                                                   facts_offset fact_names)
       
   726                         deps ([], [])))
       
   727 
       
   728 fun repair_name "$true" = "c_True"
       
   729   | repair_name "$false" = "c_False"
       
   730   | repair_name "$$e" = tptp_equal (* seen in Vampire proofs *)
       
   731   | repair_name s =
       
   732     if is_tptp_equal s orelse
       
   733        (* seen in Vampire proofs *)
       
   734        (String.isPrefix "sQ" s andalso String.isSuffix "_eqProxy" s) then
       
   735       tptp_equal
       
   736     else
       
   737       s
       
   738 
       
   739 fun isar_proof_from_atp_proof pool ctxt type_sys tfrees isar_shrink_factor
       
   740         conjecture_shape facts_offset fact_names sym_tab params frees
       
   741         atp_proof =
       
   742   let
       
   743     val lines =
       
   744       atp_proof
       
   745       |> clean_up_atp_proof_dependencies
       
   746       |> nasty_atp_proof pool
       
   747       |> map_term_names_in_atp_proof repair_name
       
   748       |> decode_lines ctxt sym_tab tfrees
       
   749       |> rpair [] |-> fold_rev (add_line type_sys conjecture_shape fact_names)
       
   750       |> rpair [] |-> fold_rev add_nontrivial_line
       
   751       |> rpair (0, [])
       
   752       |-> fold_rev (add_desired_line type_sys isar_shrink_factor
       
   753                                      conjecture_shape fact_names frees)
       
   754       |> snd
       
   755   in
       
   756     (if null params then [] else [Fix params]) @
       
   757     map2 (step_for_line type_sys conjecture_shape facts_offset fact_names)
       
   758          (length lines downto 1) lines
       
   759   end
       
   760 
       
   761 (* When redirecting proofs, we keep information about the labels seen so far in
       
   762    the "backpatches" data structure. The first component indicates which facts
       
   763    should be associated with forthcoming proof steps. The second component is a
       
   764    pair ("assum_ls", "drop_ls"), where "assum_ls" are the labels that should
       
   765    become assumptions and "drop_ls" are the labels that should be dropped in a
       
   766    case split. *)
       
   767 type backpatches = (label * facts) list * (label list * label list)
       
   768 
       
   769 fun used_labels_of_step (Have (_, _, _, by)) =
       
   770     (case by of
       
   771        ByMetis (ls, _) => ls
       
   772      | CaseSplit (proofs, (ls, _)) =>
       
   773        fold (union (op =) o used_labels_of) proofs ls)
       
   774   | used_labels_of_step _ = []
       
   775 and used_labels_of proof = fold (union (op =) o used_labels_of_step) proof []
       
   776 
       
   777 fun new_labels_of_step (Fix _) = []
       
   778   | new_labels_of_step (Let _) = []
       
   779   | new_labels_of_step (Assume (l, _)) = [l]
       
   780   | new_labels_of_step (Have (_, l, _, _)) = [l]
       
   781 val new_labels_of = maps new_labels_of_step
       
   782 
       
   783 val join_proofs =
       
   784   let
       
   785     fun aux _ [] = NONE
       
   786       | aux proof_tail (proofs as (proof1 :: _)) =
       
   787         if exists null proofs then
       
   788           NONE
       
   789         else if forall (curry (op =) (hd proof1) o hd) (tl proofs) then
       
   790           aux (hd proof1 :: proof_tail) (map tl proofs)
       
   791         else case hd proof1 of
       
   792           Have ([], l, t, _) => (* FIXME: should we really ignore the "by"? *)
       
   793           if forall (fn Have ([], l', t', _) :: _ => (l, t) = (l', t')
       
   794                       | _ => false) (tl proofs) andalso
       
   795              not (exists (member (op =) (maps new_labels_of proofs))
       
   796                          (used_labels_of proof_tail)) then
       
   797             SOME (l, t, map rev proofs, proof_tail)
       
   798           else
       
   799             NONE
       
   800         | _ => NONE
       
   801   in aux [] o map rev end
       
   802 
       
   803 fun case_split_qualifiers proofs =
       
   804   case length proofs of
       
   805     0 => []
       
   806   | 1 => [Then]
       
   807   | _ => [Ultimately]
       
   808 
       
   809 fun redirect_proof hyp_ts concl_t proof =
       
   810   let
       
   811     (* The first pass outputs those steps that are independent of the negated
       
   812        conjecture. The second pass flips the proof by contradiction to obtain a
       
   813        direct proof, introducing case splits when an inference depends on
       
   814        several facts that depend on the negated conjecture. *)
       
   815      val concl_l = (conjecture_prefix, length hyp_ts)
       
   816      fun first_pass ([], contra) = ([], contra)
       
   817        | first_pass ((step as Fix _) :: proof, contra) =
       
   818          first_pass (proof, contra) |>> cons step
       
   819        | first_pass ((step as Let _) :: proof, contra) =
       
   820          first_pass (proof, contra) |>> cons step
       
   821        | first_pass ((step as Assume (l as (_, j), _)) :: proof, contra) =
       
   822          if l = concl_l then first_pass (proof, contra ||> cons step)
       
   823          else first_pass (proof, contra) |>> cons (Assume (l, nth hyp_ts j))
       
   824        | first_pass (Have (qs, l, t, ByMetis (ls, ss)) :: proof, contra) =
       
   825          let val step = Have (qs, l, t, ByMetis (ls, ss)) in
       
   826            if exists (member (op =) (fst contra)) ls then
       
   827              first_pass (proof, contra |>> cons l ||> cons step)
       
   828            else
       
   829              first_pass (proof, contra) |>> cons step
       
   830          end
       
   831        | first_pass _ = raise Fail "malformed proof"
       
   832     val (proof_top, (contra_ls, contra_proof)) =
       
   833       first_pass (proof, ([concl_l], []))
       
   834     val backpatch_label = the_default ([], []) oo AList.lookup (op =) o fst
       
   835     fun backpatch_labels patches ls =
       
   836       fold merge_fact_sets (map (backpatch_label patches) ls) ([], [])
       
   837     fun second_pass end_qs ([], assums, patches) =
       
   838         ([Have (end_qs, no_label, concl_t,
       
   839                 ByMetis (backpatch_labels patches (map snd assums)))], patches)
       
   840       | second_pass end_qs (Assume (l, t) :: proof, assums, patches) =
       
   841         second_pass end_qs (proof, (t, l) :: assums, patches)
       
   842       | second_pass end_qs (Have (qs, l, t, ByMetis (ls, ss)) :: proof, assums,
       
   843                             patches) =
       
   844         (if member (op =) (snd (snd patches)) l andalso
       
   845             not (member (op =) (fst (snd patches)) l) andalso
       
   846             not (AList.defined (op =) (fst patches) l) then
       
   847            second_pass end_qs (proof, assums, patches ||> apsnd (append ls))
       
   848          else case List.partition (member (op =) contra_ls) ls of
       
   849            ([contra_l], co_ls) =>
       
   850            if member (op =) qs Show then
       
   851              second_pass end_qs (proof, assums,
       
   852                                  patches |>> cons (contra_l, (co_ls, ss)))
       
   853            else
       
   854              second_pass end_qs
       
   855                          (proof, assums,
       
   856                           patches |>> cons (contra_l, (l :: co_ls, ss)))
       
   857              |>> cons (if member (op =) (fst (snd patches)) l then
       
   858                          Assume (l, s_not t)
       
   859                        else
       
   860                          Have (qs, l, s_not t,
       
   861                                ByMetis (backpatch_label patches l)))
       
   862          | (contra_ls as _ :: _, co_ls) =>
       
   863            let
       
   864              val proofs =
       
   865                map_filter
       
   866                    (fn l =>
       
   867                        if l = concl_l then
       
   868                          NONE
       
   869                        else
       
   870                          let
       
   871                            val drop_ls = filter (curry (op <>) l) contra_ls
       
   872                          in
       
   873                            second_pass []
       
   874                                (proof, assums,
       
   875                                 patches ||> apfst (insert (op =) l)
       
   876                                         ||> apsnd (union (op =) drop_ls))
       
   877                            |> fst |> SOME
       
   878                          end) contra_ls
       
   879              val (assumes, facts) =
       
   880                if member (op =) (fst (snd patches)) l then
       
   881                  ([Assume (l, s_not t)], (l :: co_ls, ss))
       
   882                else
       
   883                  ([], (co_ls, ss))
       
   884            in
       
   885              (case join_proofs proofs of
       
   886                 SOME (l, t, proofs, proof_tail) =>
       
   887                 Have (case_split_qualifiers proofs @
       
   888                       (if null proof_tail then end_qs else []), l, t,
       
   889                       smart_case_split proofs facts) :: proof_tail
       
   890               | NONE =>
       
   891                 [Have (case_split_qualifiers proofs @ end_qs, no_label,
       
   892                        concl_t, smart_case_split proofs facts)],
       
   893               patches)
       
   894              |>> append assumes
       
   895            end
       
   896          | _ => raise Fail "malformed proof")
       
   897        | second_pass _ _ = raise Fail "malformed proof"
       
   898     val proof_bottom =
       
   899       second_pass [Show] (contra_proof, [], ([], ([], []))) |> fst
       
   900   in proof_top @ proof_bottom end
       
   901 
       
   902 (* FIXME: Still needed? Probably not. *)
       
   903 val kill_duplicate_assumptions_in_proof =
       
   904   let
       
   905     fun relabel_facts subst =
       
   906       apfst (map (fn l => AList.lookup (op =) subst l |> the_default l))
       
   907     fun do_step (step as Assume (l, t)) (proof, subst, assums) =
       
   908         (case AList.lookup (op aconv) assums t of
       
   909            SOME l' => (proof, (l, l') :: subst, assums)
       
   910          | NONE => (step :: proof, subst, (t, l) :: assums))
       
   911       | do_step (Have (qs, l, t, by)) (proof, subst, assums) =
       
   912         (Have (qs, l, t,
       
   913                case by of
       
   914                  ByMetis facts => ByMetis (relabel_facts subst facts)
       
   915                | CaseSplit (proofs, facts) =>
       
   916                  CaseSplit (map do_proof proofs, relabel_facts subst facts)) ::
       
   917          proof, subst, assums)
       
   918       | do_step step (proof, subst, assums) = (step :: proof, subst, assums)
       
   919     and do_proof proof = fold do_step proof ([], [], []) |> #1 |> rev
       
   920   in do_proof end
       
   921 
       
   922 val then_chain_proof =
       
   923   let
       
   924     fun aux _ [] = []
       
   925       | aux _ ((step as Assume (l, _)) :: proof) = step :: aux l proof
       
   926       | aux l' (Have (qs, l, t, by) :: proof) =
       
   927         (case by of
       
   928            ByMetis (ls, ss) =>
       
   929            Have (if member (op =) ls l' then
       
   930                    (Then :: qs, l, t,
       
   931                     ByMetis (filter_out (curry (op =) l') ls, ss))
       
   932                  else
       
   933                    (qs, l, t, ByMetis (ls, ss)))
       
   934          | CaseSplit (proofs, facts) =>
       
   935            Have (qs, l, t, CaseSplit (map (aux no_label) proofs, facts))) ::
       
   936         aux l proof
       
   937       | aux _ (step :: proof) = step :: aux no_label proof
       
   938   in aux no_label end
       
   939 
       
   940 fun kill_useless_labels_in_proof proof =
       
   941   let
       
   942     val used_ls = used_labels_of proof
       
   943     fun do_label l = if member (op =) used_ls l then l else no_label
       
   944     fun do_step (Assume (l, t)) = Assume (do_label l, t)
       
   945       | do_step (Have (qs, l, t, by)) =
       
   946         Have (qs, do_label l, t,
       
   947               case by of
       
   948                 CaseSplit (proofs, facts) =>
       
   949                 CaseSplit (map (map do_step) proofs, facts)
       
   950               | _ => by)
       
   951       | do_step step = step
       
   952   in map do_step proof end
       
   953 
       
   954 fun prefix_for_depth n = replicate_string (n + 1)
       
   955 
       
   956 val relabel_proof =
       
   957   let
       
   958     fun aux _ _ _ [] = []
       
   959       | aux subst depth (next_assum, next_fact) (Assume (l, t) :: proof) =
       
   960         if l = no_label then
       
   961           Assume (l, t) :: aux subst depth (next_assum, next_fact) proof
       
   962         else
       
   963           let val l' = (prefix_for_depth depth assum_prefix, next_assum) in
       
   964             Assume (l', t) ::
       
   965             aux ((l, l') :: subst) depth (next_assum + 1, next_fact) proof
       
   966           end
       
   967       | aux subst depth (next_assum, next_fact) (Have (qs, l, t, by) :: proof) =
       
   968         let
       
   969           val (l', subst, next_fact) =
       
   970             if l = no_label then
       
   971               (l, subst, next_fact)
       
   972             else
       
   973               let
       
   974                 val l' = (prefix_for_depth depth have_prefix, next_fact)
       
   975               in (l', (l, l') :: subst, next_fact + 1) end
       
   976           val relabel_facts =
       
   977             apfst (maps (the_list o AList.lookup (op =) subst))
       
   978           val by =
       
   979             case by of
       
   980               ByMetis facts => ByMetis (relabel_facts facts)
       
   981             | CaseSplit (proofs, facts) =>
       
   982               CaseSplit (map (aux subst (depth + 1) (1, 1)) proofs,
       
   983                          relabel_facts facts)
       
   984         in
       
   985           Have (qs, l', t, by) ::
       
   986           aux subst depth (next_assum, next_fact) proof
       
   987         end
       
   988       | aux subst depth nextp (step :: proof) =
       
   989         step :: aux subst depth nextp proof
       
   990   in aux [] 0 (1, 1) end
       
   991 
       
   992 fun string_for_proof ctxt0 full_types i n =
       
   993   let
       
   994     val ctxt =
       
   995       ctxt0 |> Config.put show_free_types false
       
   996             |> Config.put show_types true
       
   997             |> Config.put show_sorts true
       
   998     fun fix_print_mode f x =
       
   999       Print_Mode.setmp (filter (curry (op =) Symbol.xsymbolsN)
       
  1000                                (print_mode_value ())) f x
       
  1001     fun do_indent ind = replicate_string (ind * indent_size) " "
       
  1002     fun do_free (s, T) =
       
  1003       maybe_quote s ^ " :: " ^
       
  1004       maybe_quote (fix_print_mode (Syntax.string_of_typ ctxt) T)
       
  1005     fun do_label l = if l = no_label then "" else string_for_label l ^ ": "
       
  1006     fun do_have qs =
       
  1007       (if member (op =) qs Moreover then "moreover " else "") ^
       
  1008       (if member (op =) qs Ultimately then "ultimately " else "") ^
       
  1009       (if member (op =) qs Then then
       
  1010          if member (op =) qs Show then "thus" else "hence"
       
  1011        else
       
  1012          if member (op =) qs Show then "show" else "have")
       
  1013     val do_term = maybe_quote o fix_print_mode (Syntax.string_of_term ctxt)
       
  1014     val reconstructor = if full_types then MetisFT else Metis
       
  1015     fun do_facts (ls, ss) =
       
  1016       reconstructor_command reconstructor 1 1
       
  1017           (ls |> sort_distinct (prod_ord string_ord int_ord),
       
  1018            ss |> sort_distinct string_ord)
       
  1019     and do_step ind (Fix xs) =
       
  1020         do_indent ind ^ "fix " ^ space_implode " and " (map do_free xs) ^ "\n"
       
  1021       | do_step ind (Let (t1, t2)) =
       
  1022         do_indent ind ^ "let " ^ do_term t1 ^ " = " ^ do_term t2 ^ "\n"
       
  1023       | do_step ind (Assume (l, t)) =
       
  1024         do_indent ind ^ "assume " ^ do_label l ^ do_term t ^ "\n"
       
  1025       | do_step ind (Have (qs, l, t, ByMetis facts)) =
       
  1026         do_indent ind ^ do_have qs ^ " " ^
       
  1027         do_label l ^ do_term t ^ " " ^ do_facts facts ^ "\n"
       
  1028       | do_step ind (Have (qs, l, t, CaseSplit (proofs, facts))) =
       
  1029         space_implode (do_indent ind ^ "moreover\n")
       
  1030                       (map (do_block ind) proofs) ^
       
  1031         do_indent ind ^ do_have qs ^ " " ^ do_label l ^ do_term t ^ " " ^
       
  1032         do_facts facts ^ "\n"
       
  1033     and do_steps prefix suffix ind steps =
       
  1034       let val s = implode (map (do_step ind) steps) in
       
  1035         replicate_string (ind * indent_size - size prefix) " " ^ prefix ^
       
  1036         String.extract (s, ind * indent_size,
       
  1037                         SOME (size s - ind * indent_size - 1)) ^
       
  1038         suffix ^ "\n"
       
  1039       end
       
  1040     and do_block ind proof = do_steps "{ " " }" (ind + 1) proof
       
  1041     (* One-step proofs are pointless; better use the Metis one-liner
       
  1042        directly. *)
       
  1043     and do_proof [Have (_, _, _, ByMetis _)] = ""
       
  1044       | do_proof proof =
       
  1045         (if i <> 1 then "prefer " ^ string_of_int i ^ "\n" else "") ^
       
  1046         do_indent 0 ^ "proof -\n" ^ do_steps "" "" 1 proof ^ do_indent 0 ^
       
  1047         (if n <> 1 then "next" else "qed")
       
  1048   in do_proof end
       
  1049 
       
  1050 fun isar_proof_text ctxt isar_proof_requested
       
  1051         (debug, full_types, isar_shrink_factor, type_sys, pool,
       
  1052          conjecture_shape, facts_offset, fact_names, sym_tab, atp_proof, goal)
       
  1053         (one_line_params as (_, _, _, _, subgoal, subgoal_count)) =
       
  1054   let
       
  1055     val isar_shrink_factor =
       
  1056       (if isar_proof_requested then 1 else 2) * isar_shrink_factor
       
  1057     val (params, hyp_ts, concl_t) = strip_subgoal ctxt goal subgoal
       
  1058     val frees = fold Term.add_frees (concl_t :: hyp_ts) []
       
  1059     val tfrees = fold Term.add_tfrees (concl_t :: hyp_ts) []
       
  1060     val one_line_proof = one_line_proof_text one_line_params
       
  1061     fun isar_proof_for () =
       
  1062       case atp_proof
       
  1063            |> isar_proof_from_atp_proof pool ctxt type_sys tfrees
       
  1064                   isar_shrink_factor conjecture_shape facts_offset
       
  1065                   fact_names sym_tab params frees
       
  1066            |> redirect_proof hyp_ts concl_t
       
  1067            |> kill_duplicate_assumptions_in_proof
       
  1068            |> then_chain_proof
       
  1069            |> kill_useless_labels_in_proof
       
  1070            |> relabel_proof
       
  1071            |> string_for_proof ctxt full_types subgoal subgoal_count of
       
  1072         "" =>
       
  1073         if isar_proof_requested then
       
  1074           "\nNo structured proof available (proof too short)."
       
  1075         else
       
  1076           ""
       
  1077       | proof =>
       
  1078         "\n\n" ^ (if isar_proof_requested then "Structured proof"
       
  1079                   else "Perhaps this will work") ^
       
  1080         ":\n" ^ Markup.markup Markup.sendback proof
       
  1081     val isar_proof =
       
  1082       if debug then
       
  1083         isar_proof_for ()
       
  1084       else
       
  1085         case try isar_proof_for () of
       
  1086           SOME s => s
       
  1087         | NONE => if isar_proof_requested then
       
  1088                     "\nWarning: The Isar proof construction failed."
       
  1089                   else
       
  1090                     ""
       
  1091   in one_line_proof ^ isar_proof end
       
  1092 
       
  1093 fun proof_text ctxt isar_proof isar_params
       
  1094                (one_line_params as (preplay, _, _, _, _, _)) =
       
  1095   (if isar_proof orelse preplay = Failed_to_Play then
       
  1096      isar_proof_text ctxt isar_proof isar_params
       
  1097    else
       
  1098      one_line_proof_text) one_line_params
       
  1099 
       
  1100 end;