src/HOL/Tools/Sledgehammer/sledgehammer_isar.ML
author Walther Neuper <walther.neuper@jku.at>
Tue, 03 Sep 2019 16:10:31 +0200
changeset 59606 c3925099d59f
parent 59451 71b442e82416
child 60065 46266dc209cd
permissions -rw-r--r--
\----- start update Isabelle2018 --> Isabelle2019
blanchet@56544
     1
(*  Title:      HOL/Tools/Sledgehammer/sledgehammer_isar.ML
blanchet@50898
     2
    Author:     Jasmin Blanchette, TU Muenchen
blanchet@50898
     3
    Author:     Steffen Juilf Smolka, TU Muenchen
blanchet@50898
     4
blanchet@50929
     5
Isar proof reconstruction from ATP proofs.
blanchet@50898
     6
*)
blanchet@50898
     7
blanchet@56544
     8
signature SLEDGEHAMMER_ISAR =
blanchet@50898
     9
sig
blanchet@56113
    10
  type atp_step_name = ATP_Proof.atp_step_name
blanchet@55868
    11
  type ('a, 'b) atp_step = ('a, 'b) ATP_Proof.atp_step
blanchet@54723
    12
  type 'a atp_proof = 'a ATP_Proof.atp_proof
blanchet@50929
    13
  type stature = ATP_Problem_Generate.stature
blanchet@56629
    14
  type one_line_params = Sledgehammer_Proof_Methods.one_line_params
blanchet@50929
    15
blanchet@56564
    16
  val trace : bool Config.T
blanchet@56564
    17
blanchet@50929
    18
  type isar_params =
wneuper@59180
    19
    bool * (string option * string option) * Time.time * real option * bool * bool
blanchet@56630
    20
    * (term, string) atp_step list * thm
blanchet@50929
    21
blanchet@56638
    22
  val proof_text : Proof.context -> bool -> bool option -> bool option -> (unit -> isar_params) ->
blanchet@56638
    23
    int -> one_line_params -> string
blanchet@50898
    24
end;
blanchet@50898
    25
blanchet@56544
    26
structure Sledgehammer_Isar : SLEDGEHAMMER_ISAR =
blanchet@50898
    27
struct
blanchet@50898
    28
blanchet@50898
    29
open ATP_Util
blanchet@50929
    30
open ATP_Problem
blanchet@50898
    31
open ATP_Proof
blanchet@50898
    32
open ATP_Proof_Reconstruct
wneuper@59180
    33
open ATP_Waldmeister
blanchet@50933
    34
open Sledgehammer_Util
blanchet@56629
    35
open Sledgehammer_Proof_Methods
blanchet@56544
    36
open Sledgehammer_Isar_Proof
blanchet@56544
    37
open Sledgehammer_Isar_Preplay
blanchet@56544
    38
open Sledgehammer_Isar_Compress
blanchet@56544
    39
open Sledgehammer_Isar_Minimize
blanchet@50929
    40
blanchet@50929
    41
structure String_Redirect = ATP_Proof_Redirect(
blanchet@54723
    42
  type key = atp_step_name
blanchet@50929
    43
  val ord = fn ((s, _ : string list), (s', _)) => fast_string_ord (s, s')
blanchet@50929
    44
  val string_of = fst)
blanchet@50929
    45
blanchet@50898
    46
open String_Redirect
blanchet@50898
    47
walther@59606
    48
val trace = Attrib.setup_config_bool \<^binding>\<open>sledgehammer_isar_trace\<close> (K false)
blanchet@56564
    49
wneuper@59180
    50
val e_definition_rule = "definition"
blanchet@58996
    51
val e_skolemize_rule = "skolemize"
wneuper@59180
    52
val leo2_extcnf_forall_neg_rule = "extcnf_forall_neg"
wneuper@59180
    53
val pirate_datatype_rule = "DT"
wneuper@59180
    54
val satallax_skolemize_rule = "tab_ex"
blanchet@56088
    55
val vampire_skolemisation_rule = "skolemisation"
wneuper@59180
    56
val veriT_la_generic_rule = "la_generic"
wneuper@59180
    57
val veriT_simp_arith_rule = "simp_arith"
wneuper@59180
    58
val veriT_tmp_skolemize_rule = "tmp_skolemize"
wneuper@59180
    59
val z3_skolemize_rule = Z3_Proof.string_of_rule Z3_Proof.Skolemize
wneuper@59180
    60
val z3_th_lemma_rule_prefix = Z3_Proof.string_of_rule (Z3_Proof.Th_Lemma "")
wneuper@59180
    61
val zipperposition_cnf_rule = "cnf"
blanchet@56088
    62
blanchet@56114
    63
val skolemize_rules =
wneuper@59180
    64
  [e_definition_rule, e_skolemize_rule, leo2_extcnf_forall_neg_rule, satallax_skolemize_rule,
walther@59606
    65
   spass_skolemize_rule, vampire_skolemisation_rule,
wneuper@59180
    66
   veriT_tmp_skolemize_rule, waldmeister_skolemize_rule, z3_skolemize_rule, zipperposition_cnf_rule]
wneuper@59180
    67
wneuper@59180
    68
fun is_ext_rule rule = (rule = leo2_extcnf_equal_neg_rule)
wneuper@59180
    69
val is_maybe_ext_rule = is_ext_rule orf String.isPrefix satallax_tab_rule_prefix
blanchet@56088
    70
blanchet@56111
    71
val is_skolemize_rule = member (op =) skolemize_rules
wneuper@59180
    72
fun is_arith_rule rule =
wneuper@59180
    73
  String.isPrefix z3_th_lemma_rule_prefix rule orelse rule = veriT_simp_arith_rule orelse
wneuper@59180
    74
  rule = veriT_la_generic_rule
wneuper@59180
    75
val is_datatype_rule = String.isPrefix pirate_datatype_rule
blanchet@56097
    76
blanchet@55874
    77
fun raw_label_of_num num = (num, 0)
blanchet@50929
    78
blanchet@55874
    79
fun label_of_clause [(num, _)] = raw_label_of_num num
blanchet@55874
    80
  | label_of_clause c = (space_implode "___" (map (fst o raw_label_of_num o fst) c), 0)
blanchet@51020
    81
wneuper@59180
    82
fun add_global_fact ss = apsnd (union (op =) ss)
wneuper@59180
    83
wneuper@59180
    84
fun add_fact_of_dependency [(_, ss as _ :: _)] = add_global_fact ss
wneuper@59180
    85
  | add_fact_of_dependency names = apfst (insert (op =) (label_of_clause names))
blanchet@50929
    86
blanchet@56141
    87
fun add_line_pass1 (line as (name, role, t, rule, [])) lines =
blanchet@56112
    88
    (* No dependencies: lemma (for Z3), fact, conjecture, or (for Vampire) internal facts or
blanchet@56112
    89
       definitions. *)
wneuper@59180
    90
    if role = Conjecture orelse role = Negated_Conjecture then
wneuper@59180
    91
      line :: lines
walther@59606
    92
    else if t aconv \<^prop>\<open>True\<close> then
wneuper@59180
    93
      map (replace_dependencies_in_line (name, [])) lines
wneuper@59180
    94
    else if role = Lemma orelse role = Hypothesis orelse is_arith_rule rule then
wneuper@59180
    95
      line :: lines
wneuper@59180
    96
    else if role = Axiom then
wneuper@59180
    97
      lines (* axioms (facts) need no proof lines *)
wneuper@59180
    98
    else
wneuper@59180
    99
      map (replace_dependencies_in_line (name, [])) lines
blanchet@56097
   100
  | add_line_pass1 line lines = line :: lines
blanchet@50929
   101
wneuper@59180
   102
fun add_lines_pass2 res [] = rev res
wneuper@59180
   103
  | add_lines_pass2 res ((line as (name, role, t, rule, deps)) :: lines) =
blanchet@56526
   104
    let
wneuper@59180
   105
      fun normalize role =
wneuper@59180
   106
        role = Conjecture ? (HOLogic.dest_Trueprop #> s_not #> HOLogic.mk_Trueprop)
wneuper@59180
   107
wneuper@59180
   108
      val norm_t = normalize role t
wneuper@59180
   109
      val is_duplicate =
wneuper@59180
   110
        exists (fn (prev_name, prev_role, prev_t, _, _) =>
wneuper@59180
   111
            (prev_role = Hypothesis andalso prev_t aconv t) orelse
wneuper@59180
   112
            (member (op =) deps prev_name andalso
wneuper@59180
   113
             Term.aconv_untyped (normalize prev_role prev_t, norm_t)))
wneuper@59180
   114
          res
wneuper@59180
   115
walther@59606
   116
      fun looks_boring () = t aconv \<^prop>\<open>False\<close> orelse length deps < 2
blanchet@56526
   117
blanchet@56526
   118
      fun is_skolemizing_line (_, _, _, rule', deps') =
blanchet@56526
   119
        is_skolemize_rule rule' andalso member (op =) deps' name
wneuper@59180
   120
blanchet@56526
   121
      fun is_before_skolemize_rule () = exists is_skolemizing_line lines
blanchet@56526
   122
    in
wneuper@59180
   123
      if is_duplicate orelse
wneuper@59180
   124
          (role = Plain andalso not (is_skolemize_rule rule) andalso
wneuper@59180
   125
           not (is_ext_rule rule) andalso not (is_arith_rule rule) andalso
wneuper@59180
   126
           not (is_datatype_rule rule) andalso not (null lines) andalso looks_boring () andalso
wneuper@59180
   127
           not (is_before_skolemize_rule ())) then
wneuper@59180
   128
        add_lines_pass2 res (map (replace_dependencies_in_line (name, deps)) lines)
blanchet@56526
   129
      else
wneuper@59180
   130
        add_lines_pass2 (line :: res) lines
blanchet@56526
   131
    end
blanchet@50929
   132
blanchet@50929
   133
type isar_params =
wneuper@59180
   134
  bool * (string option * string option) * Time.time * real option * bool * bool
blanchet@56630
   135
  * (term, string) atp_step list * thm
blanchet@50929
   136
blanchet@58194
   137
val basic_systematic_methods = [Metis_Method (NONE, NONE), Meson_Method, Blast_Method, SATx_Method]
wneuper@59180
   138
val basic_simp_based_methods = [Auto_Method, Simp_Method, Fastforce_Method, Force_Method]
blanchet@56665
   139
val basic_arith_methods = [Linarith_Method, Presburger_Method, Algebra_Method]
blanchet@56653
   140
wneuper@59180
   141
val arith_methods = basic_arith_methods @ basic_simp_based_methods @ basic_systematic_methods
blanchet@56653
   142
val datatype_methods = [Simp_Method, Simp_Size_Method]
wneuper@59180
   143
val systematic_methods =
wneuper@59180
   144
  basic_systematic_methods @ basic_arith_methods @ basic_simp_based_methods @
wneuper@59180
   145
  [Metis_Method (SOME full_typesN, NONE), Metis_Method (SOME no_typesN, NONE)]
wneuper@59180
   146
val rewrite_methods = basic_simp_based_methods @ basic_systematic_methods @ basic_arith_methods
wneuper@59180
   147
val skolem_methods = Moura_Method :: systematic_methods
blanchet@56108
   148
wneuper@59324
   149
fun isar_proof_text ctxt debug num_chained isar_proofs smt_proofs isar_params
wneuper@59180
   150
    (one_line_params as ((used_facts, (_, one_line_play)), banner, subgoal, subgoal_count)) =
blanchet@50898
   151
  let
wneuper@59180
   152
    val _ = if debug then writeln "Constructing Isar proof..." else ()
blanchet@57439
   153
blanchet@58629
   154
    fun generate_proof_text () =
blanchet@50898
   155
      let
wneuper@59180
   156
        val (verbose, alt_metis_args, preplay_timeout, compress, try0, minimize, atp_proof0, goal) =
blanchet@58587
   157
          isar_params ()
wneuper@59324
   158
      in
wneuper@59324
   159
        if null atp_proof0 then
wneuper@59324
   160
          one_line_proof_text ctxt 0 one_line_params
wneuper@59324
   161
        else
wneuper@59324
   162
          let
wneuper@59324
   163
            val systematic_methods' = insert (op =) (Metis_Method alt_metis_args) systematic_methods
blanchet@56599
   164
wneuper@59324
   165
            fun massage_methods (meths as meth :: _) =
wneuper@59324
   166
              if not try0 then [meth]
wneuper@59324
   167
              else if smt_proofs = SOME true then SMT_Method :: meths
wneuper@59324
   168
              else meths
blanchet@56510
   169
wneuper@59324
   170
            val (params, _, concl_t) = strip_subgoal goal subgoal ctxt
wneuper@59324
   171
            val fixes = map (fn (s, T) => (Binding.name s, SOME T, NoSyn)) params
wneuper@59324
   172
            val ctxt = ctxt |> Variable.set_body false |> Proof_Context.add_fixes fixes |> snd
blanchet@56615
   173
wneuper@59324
   174
            val do_preplay = preplay_timeout <> Time.zeroTime
wneuper@59324
   175
            val compress =
wneuper@59324
   176
              (case compress of
wneuper@59324
   177
                NONE => if isar_proofs = NONE andalso do_preplay then 1000.0 else 10.0
wneuper@59324
   178
              | SOME n => n)
blanchet@56510
   179
wneuper@59324
   180
            fun is_fixed ctxt = Variable.is_declared ctxt orf Name.is_skolem
wneuper@59324
   181
            fun skolems_of ctxt t = Term.add_frees t [] |> filter_out (is_fixed ctxt o fst) |> rev
blanchet@56510
   182
wneuper@59324
   183
            fun get_role keep_role ((num, _), role, t, rule, _) =
wneuper@59324
   184
              if keep_role role then SOME ((raw_label_of_num num, t), rule) else NONE
blanchet@56510
   185
wneuper@59324
   186
            val atp_proof =
wneuper@59324
   187
              fold_rev add_line_pass1 atp_proof0 []
wneuper@59324
   188
              |> add_lines_pass2 []
blanchet@56510
   189
wneuper@59324
   190
            val conjs =
wneuper@59324
   191
              map_filter (fn (name, role, _, _, _) =>
wneuper@59324
   192
                  if member (op =) [Conjecture, Negated_Conjecture] role then SOME name else NONE)
wneuper@59324
   193
                atp_proof
wneuper@59324
   194
            val assms = map_filter (Option.map fst o get_role (curry (op =) Hypothesis)) atp_proof
blanchet@56042
   195
wneuper@59324
   196
            fun add_lemma ((l, t), rule) ctxt =
wneuper@59324
   197
              let
wneuper@59324
   198
                val (skos, meths) =
wneuper@59324
   199
                  (if is_skolemize_rule rule then (skolems_of ctxt t, skolem_methods)
wneuper@59324
   200
                   else if is_arith_rule rule then ([], arith_methods)
wneuper@59324
   201
                   else ([], rewrite_methods))
wneuper@59324
   202
                  ||> massage_methods
wneuper@59324
   203
              in
wneuper@59324
   204
                (Prove ([], skos, l, t, [], ([], []), meths, ""),
wneuper@59324
   205
                 ctxt |> not (null skos) ? (Variable.add_fixes (map fst skos) #> snd))
wneuper@59324
   206
              end
blanchet@58630
   207
wneuper@59324
   208
            val (lems, _) =
wneuper@59324
   209
              fold_map add_lemma (map_filter (get_role (curry (op =) Lemma)) atp_proof) ctxt
wneuper@59324
   210
wneuper@59324
   211
            val bot = #1 (List.last atp_proof)
wneuper@59324
   212
wneuper@59324
   213
            val refute_graph =
wneuper@59324
   214
              atp_proof
wneuper@59324
   215
              |> map (fn (name, _, _, _, from) => (from, name))
wneuper@59324
   216
              |> make_refute_graph bot
wneuper@59324
   217
              |> fold (Atom_Graph.default_node o rpair ()) conjs
wneuper@59324
   218
wneuper@59324
   219
            val axioms = axioms_of_refute_graph refute_graph conjs
wneuper@59324
   220
wneuper@59324
   221
            val tainted = tainted_atoms_of_refute_graph refute_graph conjs
wneuper@59324
   222
            val is_clause_tainted = exists (member (op =) tainted)
wneuper@59324
   223
            val steps =
wneuper@59324
   224
              Symtab.empty
wneuper@59324
   225
              |> fold (fn (name as (s, _), role, t, rule, _) =>
wneuper@59324
   226
                  Symtab.update_new (s, (rule, t
wneuper@59324
   227
                    |> (if is_clause_tainted [name] then
wneuper@59324
   228
                          HOLogic.dest_Trueprop
wneuper@59324
   229
                          #> role <> Conjecture ? s_not
wneuper@59324
   230
                          #> fold exists_of (map Var (Term.add_vars t []))
wneuper@59324
   231
                          #> HOLogic.mk_Trueprop
wneuper@59324
   232
                        else
wneuper@59324
   233
                          I))))
wneuper@59324
   234
                atp_proof
wneuper@59324
   235
wneuper@59324
   236
            fun is_referenced_in_step _ (Let _) = false
wneuper@59324
   237
              | is_referenced_in_step l (Prove (_, _, _, _, subs, (ls, _), _, _)) =
wneuper@59324
   238
                member (op =) ls l orelse exists (is_referenced_in_proof l) subs
wneuper@59324
   239
            and is_referenced_in_proof l (Proof (_, _, steps)) =
wneuper@59324
   240
              exists (is_referenced_in_step l) steps
wneuper@59324
   241
wneuper@59324
   242
            fun insert_lemma_in_step lem
wneuper@59324
   243
                (step as Prove (qs, fix, l, t, subs, (ls, gs), meths, comment)) =
wneuper@59324
   244
              let val l' = the (label_of_isar_step lem) in
wneuper@59324
   245
                if member (op =) ls l' then
wneuper@59324
   246
                  [lem, step]
wneuper@59324
   247
                else
wneuper@59324
   248
                  let val refs = map (is_referenced_in_proof l') subs in
wneuper@59324
   249
                    if length (filter I refs) = 1 then
wneuper@59324
   250
                      let
wneuper@59324
   251
                        val subs' = map2 (fn false => I | true => insert_lemma_in_proof lem) refs
wneuper@59324
   252
                          subs
wneuper@59324
   253
                      in
wneuper@59324
   254
                        [Prove (qs, fix, l, t, subs', (ls, gs), meths, comment)]
wneuper@59324
   255
                      end
wneuper@59324
   256
                    else
wneuper@59324
   257
                      [lem, step]
wneuper@59324
   258
                  end
wneuper@59324
   259
              end
wneuper@59324
   260
            and insert_lemma_in_steps lem [] = [lem]
wneuper@59324
   261
              | insert_lemma_in_steps lem (step :: steps) =
wneuper@59324
   262
                if is_referenced_in_step (the (label_of_isar_step lem)) step then
wneuper@59324
   263
                  insert_lemma_in_step lem step @ steps
wneuper@59324
   264
                else
wneuper@59324
   265
                  step :: insert_lemma_in_steps lem steps
wneuper@59324
   266
            and insert_lemma_in_proof lem (Proof (fix, assms, steps)) =
wneuper@59324
   267
              Proof (fix, assms, insert_lemma_in_steps lem steps)
wneuper@59324
   268
wneuper@59324
   269
            val rule_of_clause_id = fst o the o Symtab.lookup steps o fst
wneuper@59324
   270
wneuper@59324
   271
            val finish_off = close_form #> rename_bound_vars
wneuper@59324
   272
wneuper@59324
   273
            fun prop_of_clause [(num, _)] = Symtab.lookup steps num |> the |> snd |> finish_off
wneuper@59324
   274
              | prop_of_clause names =
wneuper@59324
   275
                let
wneuper@59324
   276
                  val lits =
wneuper@59324
   277
                    map (HOLogic.dest_Trueprop o snd) (map_filter (Symtab.lookup steps o fst) names)
wneuper@59324
   278
                in
wneuper@59324
   279
                  (case List.partition (can HOLogic.dest_not) lits of
wneuper@59324
   280
                    (negs as _ :: _, pos as _ :: _) =>
wneuper@59324
   281
                    s_imp (Library.foldr1 s_conj (map HOLogic.dest_not negs),
wneuper@59324
   282
                      Library.foldr1 s_disj pos)
walther@59606
   283
                  | _ => fold (curry s_disj) lits \<^term>\<open>False\<close>)
wneuper@59324
   284
                end
wneuper@59324
   285
                |> HOLogic.mk_Trueprop |> finish_off
wneuper@59324
   286
wneuper@59324
   287
            fun maybe_show outer c = if outer andalso eq_set (op =) (c, conjs) then [Show] else []
wneuper@59324
   288
wneuper@59324
   289
            fun isar_steps outer predecessor accum [] =
wneuper@59324
   290
                accum
wneuper@59324
   291
                |> (if tainted = [] then
wneuper@59324
   292
                      (* e.g., trivial, empty proof by Z3 *)
wneuper@59324
   293
                      cons (Prove (if outer then [Show] else [], [], no_label, concl_t, [],
wneuper@59324
   294
                        sort_facts (the_list predecessor, []), massage_methods systematic_methods',
wneuper@59324
   295
                        ""))
wneuper@59324
   296
                    else
wneuper@59324
   297
                      I)
wneuper@59324
   298
                |> rev
wneuper@59324
   299
              | isar_steps outer _ accum (Have (id, (gamma, c)) :: infs) =
wneuper@59324
   300
                let
wneuper@59324
   301
                  val l = label_of_clause c
wneuper@59324
   302
                  val t = prop_of_clause c
wneuper@59324
   303
                  val rule = rule_of_clause_id id
wneuper@59324
   304
                  val skolem = is_skolemize_rule rule
wneuper@59324
   305
wneuper@59324
   306
                  val deps = ([], [])
wneuper@59324
   307
                    |> fold add_fact_of_dependency gamma
wneuper@59324
   308
                    |> is_maybe_ext_rule rule ? add_global_fact [short_thm_name ctxt ext]
wneuper@59324
   309
                    |> sort_facts
wneuper@59324
   310
                  val meths =
wneuper@59324
   311
                    (if skolem then skolem_methods
wneuper@59324
   312
                     else if is_arith_rule rule then arith_methods
wneuper@59324
   313
                     else if is_datatype_rule rule then datatype_methods
wneuper@59324
   314
                     else systematic_methods')
wneuper@59324
   315
                    |> massage_methods
wneuper@59324
   316
wneuper@59324
   317
                  fun prove sub facts = Prove (maybe_show outer c, [], l, t, sub, facts, meths, "")
wneuper@59324
   318
                  fun steps_of_rest step = isar_steps outer (SOME l) (step :: accum) infs
wneuper@59324
   319
                in
wneuper@59324
   320
                  if is_clause_tainted c then
wneuper@59324
   321
                    (case gamma of
wneuper@59324
   322
                      [g] =>
wneuper@59324
   323
                      if skolem andalso is_clause_tainted g then
wneuper@59324
   324
                        let
wneuper@59324
   325
                          val skos = skolems_of ctxt (prop_of_clause g)
wneuper@59324
   326
                          val subproof = Proof (skos, [], rev accum)
wneuper@59324
   327
                        in
wneuper@59324
   328
                          isar_steps outer (SOME l) [prove [subproof] ([], [])] infs
wneuper@59324
   329
                        end
wneuper@59324
   330
                      else
wneuper@59324
   331
                        steps_of_rest (prove [] deps)
wneuper@59324
   332
                    | _ => steps_of_rest (prove [] deps))
wneuper@59324
   333
                  else
wneuper@59324
   334
                    steps_of_rest
wneuper@59324
   335
                      (if skolem then
wneuper@59324
   336
                         (case skolems_of ctxt t of
wneuper@59324
   337
                           [] => prove [] deps
wneuper@59324
   338
                         | skos => Prove ([], skos, l, t, [], deps, meths, ""))
wneuper@59324
   339
                       else
wneuper@59324
   340
                         prove [] deps)
wneuper@59324
   341
                end
wneuper@59324
   342
              | isar_steps outer predecessor accum (Cases cases :: infs) =
wneuper@59324
   343
                let
wneuper@59324
   344
                  fun isar_case (c, subinfs) =
wneuper@59324
   345
                    isar_proof false [] [(label_of_clause c, prop_of_clause c)] [] subinfs
wneuper@59324
   346
                  val c = succedent_of_cases cases
wneuper@59324
   347
                  val l = label_of_clause c
wneuper@59324
   348
                  val t = prop_of_clause c
wneuper@59324
   349
                  val step =
wneuper@59324
   350
                    Prove (maybe_show outer c, [], l, t,
wneuper@59324
   351
                      map isar_case (filter_out (null o snd) cases),
wneuper@59324
   352
                      sort_facts (the_list predecessor, []), massage_methods systematic_methods',
wneuper@59324
   353
                      "")
wneuper@59324
   354
                in
wneuper@59324
   355
                  isar_steps outer (SOME l) (step :: accum) infs
wneuper@59324
   356
                end
wneuper@59324
   357
            and isar_proof outer fix assms lems infs =
wneuper@59324
   358
              Proof (fix, assms,
wneuper@59324
   359
                fold_rev insert_lemma_in_steps lems (isar_steps outer NONE [] infs))
wneuper@59324
   360
wneuper@59324
   361
            val trace = Config.get ctxt trace
wneuper@59324
   362
wneuper@59324
   363
            val canonical_isar_proof =
wneuper@59324
   364
              refute_graph
wneuper@59324
   365
              |> trace ? tap (tracing o prefix "Refute graph:\n" o string_of_refute_graph)
wneuper@59324
   366
              |> redirect_graph axioms tainted bot
wneuper@59324
   367
              |> trace ? tap (tracing o prefix "Direct proof:\n" o string_of_direct_proof)
wneuper@59324
   368
              |> isar_proof true params assms lems
wneuper@59324
   369
              |> postprocess_isar_proof_remove_show_stuttering
wneuper@59324
   370
              |> postprocess_isar_proof_remove_unreferenced_steps I
wneuper@59324
   371
              |> relabel_isar_proof_canonically
wneuper@59324
   372
wneuper@59324
   373
            val ctxt = ctxt |> enrich_context_with_local_facts canonical_isar_proof
wneuper@59324
   374
wneuper@59324
   375
            val preplay_data = Unsynchronized.ref Canonical_Label_Tab.empty
wneuper@59324
   376
wneuper@59324
   377
            val _ = fold_isar_steps (fn meth =>
wneuper@59324
   378
                K (set_preplay_outcomes_of_isar_step ctxt preplay_timeout preplay_data meth []))
wneuper@59324
   379
              (steps_of_isar_proof canonical_isar_proof) ()
wneuper@59324
   380
wneuper@59324
   381
            fun str_of_preplay_outcome outcome =
wneuper@59324
   382
              if Lazy.is_finished outcome then string_of_play_outcome (Lazy.force outcome) else "?"
wneuper@59324
   383
            fun str_of_meth l meth =
wneuper@59324
   384
              string_of_proof_method ctxt [] meth ^ " " ^
wneuper@59324
   385
              str_of_preplay_outcome
wneuper@59324
   386
                (preplay_outcome_of_isar_step_for_method (!preplay_data) l meth)
wneuper@59324
   387
            fun comment_of l = map (str_of_meth l) #> commas
wneuper@59324
   388
wneuper@59324
   389
            fun trace_isar_proof label proof =
wneuper@59324
   390
              if trace then
wneuper@59324
   391
                tracing (timestamp () ^ "\n" ^ label ^ ":\n\n" ^
wneuper@59324
   392
                  string_of_isar_proof ctxt subgoal subgoal_count
wneuper@59324
   393
                    (comment_isar_proof comment_of proof) ^ "\n")
wneuper@59324
   394
              else
wneuper@59324
   395
                ()
wneuper@59324
   396
wneuper@59324
   397
            fun comment_of l (meth :: _) =
wneuper@59324
   398
              (case (verbose,
wneuper@59324
   399
                  Lazy.force (preplay_outcome_of_isar_step_for_method (!preplay_data) l meth)) of
wneuper@59324
   400
                (false, Played _) => ""
wneuper@59324
   401
              | (_, outcome) => string_of_play_outcome outcome)
wneuper@59324
   402
wneuper@59324
   403
            val (play_outcome, isar_proof) =
wneuper@59324
   404
              canonical_isar_proof
wneuper@59324
   405
              |> tap (trace_isar_proof "Original")
wneuper@59324
   406
              |> compress_isar_proof ctxt compress preplay_timeout preplay_data
wneuper@59324
   407
              |> tap (trace_isar_proof "Compressed")
wneuper@59324
   408
              |> postprocess_isar_proof_remove_unreferenced_steps
wneuper@59324
   409
                   (keep_fastest_method_of_isar_step (!preplay_data)
wneuper@59324
   410
                    #> minimize ? minimize_isar_step_dependencies ctxt preplay_data)
wneuper@59324
   411
              |> tap (trace_isar_proof "Minimized")
wneuper@59324
   412
              |> `(preplay_outcome_of_isar_proof (!preplay_data))
wneuper@59324
   413
              ||> (comment_isar_proof comment_of
wneuper@59324
   414
                   #> chain_isar_proof
wneuper@59324
   415
                   #> kill_useless_labels_in_isar_proof
wneuper@59324
   416
                   #> relabel_isar_proof_nicely
wneuper@59324
   417
                   #> rationalize_obtains_in_isar_proofs ctxt)
blanchet@58630
   418
          in
wneuper@59324
   419
            (case (num_chained, add_isar_steps (steps_of_isar_proof isar_proof) 0) of
wneuper@59324
   420
              (0, 1) =>
wneuper@59324
   421
              one_line_proof_text ctxt 0
wneuper@59451
   422
                (if is_less (play_outcome_ord (play_outcome, one_line_play)) then
wneuper@59324
   423
                   (case isar_proof of
wneuper@59324
   424
                     Proof (_, _, [Prove (_, _, _, _, _, (_, gfs), meth :: _, _)]) =>
wneuper@59324
   425
                     let
wneuper@59451
   426
                       val used_facts' =
wneuper@59451
   427
                         map_filter (fn s =>
wneuper@59451
   428
                            if exists (fn (s', (sc, _)) => s' = s andalso sc = Chained)
wneuper@59451
   429
                                used_facts then
wneuper@59451
   430
                              NONE
wneuper@59451
   431
                            else
wneuper@59451
   432
                              SOME (s, (Global, General))) gfs
wneuper@59324
   433
                     in
wneuper@59324
   434
                       ((used_facts', (meth, play_outcome)), banner, subgoal, subgoal_count)
wneuper@59324
   435
                     end)
wneuper@59324
   436
                 else
wneuper@59324
   437
                   one_line_params) ^
wneuper@59324
   438
              (if isar_proofs = SOME true then "\n(No Isar proof available.)" else "")
wneuper@59324
   439
            | (_, num_steps) =>
wneuper@59324
   440
              let
wneuper@59324
   441
                val msg =
wneuper@59324
   442
                  (if verbose then [string_of_int num_steps ^ " step" ^ plural_s num_steps]
wneuper@59324
   443
                   else []) @
wneuper@59324
   444
                  (if do_preplay then [string_of_play_outcome play_outcome] else [])
wneuper@59324
   445
              in
wneuper@59324
   446
                one_line_proof_text ctxt 0 one_line_params ^
wneuper@59324
   447
                "\n\nIsar proof" ^ (commas msg |> not (null msg) ? enclose " (" ")") ^ ":\n" ^
wneuper@59324
   448
                Active.sendback_markup_command
wneuper@59324
   449
                  (string_of_isar_proof ctxt subgoal subgoal_count isar_proof)
wneuper@59324
   450
              end)
blanchet@58630
   451
          end
blanchet@50898
   452
      end
blanchet@58398
   453
  in
blanchet@58629
   454
    if debug then
blanchet@58629
   455
      generate_proof_text ()
blanchet@58629
   456
    else
blanchet@58629
   457
      (case try generate_proof_text () of
blanchet@58629
   458
        SOME s => s
blanchet@58629
   459
      | NONE =>
blanchet@58629
   460
        one_line_proof_text ctxt 0 one_line_params ^
wneuper@59324
   461
        (if isar_proofs = SOME true then "\nWarning: Isar proof construction failed" else ""))
blanchet@58398
   462
  end
blanchet@50898
   463
blanchet@56639
   464
fun isar_proof_would_be_a_good_idea smt_proofs (meth, play) =
blanchet@56166
   465
  (case play of
wneuper@59180
   466
    Played _ => meth = SMT_Method andalso smt_proofs <> SOME true
wneuper@59324
   467
  | Play_Timed_Out time => time > Time.zeroTime
blanchet@57435
   468
  | Play_Failed => true)
blanchet@52324
   469
blanchet@56639
   470
fun proof_text ctxt debug isar_proofs smt_proofs isar_params num_chained
wneuper@59180
   471
    (one_line_params as ((_, preplay), _, _, _)) =
blanchet@52327
   472
  (if isar_proofs = SOME true orelse
blanchet@56639
   473
      (isar_proofs = NONE andalso isar_proof_would_be_a_good_idea smt_proofs preplay) then
wneuper@59324
   474
     isar_proof_text ctxt debug num_chained isar_proofs smt_proofs isar_params
blanchet@50898
   475
   else
blanchet@58327
   476
     one_line_proof_text ctxt num_chained) one_line_params
blanchet@50898
   477
blanchet@50898
   478
end;