src/HOL/Tools/ATP/atp_reconstruct.ML
changeset 45883 cf7ef3fca5e4
parent 45882 5d8a7fe36ce5
child 45887 bfb5234a70ba
equal deleted inserted replaced
45882:5d8a7fe36ce5 45883:cf7ef3fca5e4
   667      else
   667      else
   668        map (replace_dependencies_in_line (name, deps)) lines)  (* drop line *)
   668        map (replace_dependencies_in_line (name, deps)) lines)  (* drop line *)
   669 
   669 
   670 (** Isar proof construction and manipulation **)
   670 (** Isar proof construction and manipulation **)
   671 
   671 
   672 fun merge_fact_sets (ls1, ss1) (ls2, ss2) =
       
   673   (union (op =) ls1 ls2, union (op =) ss1 ss2)
       
   674 
       
   675 type label = string * int
   672 type label = string * int
   676 type facts = label list * string list
   673 type facts = label list * string list
   677 
   674 
   678 datatype isar_qualifier = Show | Then | Moreover | Ultimately
   675 datatype isar_qualifier = Show | Then | Moreover | Ultimately
   679 
   676 
   684   Prove of isar_qualifier list * label * term * byline
   681   Prove of isar_qualifier list * label * term * byline
   685 and byline =
   682 and byline =
   686   By_Metis of facts |
   683   By_Metis of facts |
   687   Case_Split of isar_step list list * facts
   684   Case_Split of isar_step list list * facts
   688 
   685 
   689 fun smart_case_split [] facts = By_Metis facts
       
   690   | smart_case_split proofs facts = Case_Split (proofs, facts)
       
   691 
       
   692 fun add_fact_from_dependency fact_names (name as (_, ss)) =
   686 fun add_fact_from_dependency fact_names (name as (_, ss)) =
   693   if is_fact fact_names ss then
   687   if is_fact fact_names ss then
   694     apsnd (union (op =) (map fst (resolve_fact fact_names ss)))
   688     apsnd (union (op =) (map fst (resolve_fact fact_names ss)))
   695   else
   689   else
   696     apfst (insert (op =) (raw_label_for_name name))
   690     apfst (insert (op =) (raw_label_for_name name))
   697 
       
   698 fun step_for_line _ _ (Definition (_, t1, t2)) = Let (t1, t2)
       
   699   | step_for_line _ _ (Inference (name, t, _, [])) =
       
   700     Assume (raw_label_for_name name, t)
       
   701   | step_for_line fact_names j (Inference (name, t, _, deps)) =
       
   702     Prove (if j = 1 then [Show] else [], raw_label_for_name name,
       
   703            fold_rev forall_of (map Var (Term.add_vars t [])) t,
       
   704            By_Metis (fold (add_fact_from_dependency fact_names) deps ([], [])))
       
   705 
   691 
   706 fun repair_name "$true" = "c_True"
   692 fun repair_name "$true" = "c_True"
   707   | repair_name "$false" = "c_False"
   693   | repair_name "$false" = "c_False"
   708   | repair_name "$$e" = tptp_equal (* seen in Vampire proofs *)
   694   | repair_name "$$e" = tptp_equal (* seen in Vampire proofs *)
   709   | repair_name s =
   695   | repair_name s =
   712        (String.isPrefix "sQ" s andalso String.isSuffix "_eqProxy" s) then
   698        (String.isPrefix "sQ" s andalso String.isSuffix "_eqProxy" s) then
   713       tptp_equal
   699       tptp_equal
   714     else
   700     else
   715       s
   701       s
   716 
   702 
   717 fun isar_proof_from_atp_proof pool ctxt isar_shrink_factor fact_names sym_tab
   703 (* FIXME: Still needed? Try with SPASS proofs perhaps. *)
   718                               params frees atp_proof =
       
   719   let
       
   720     val lines =
       
   721       atp_proof
       
   722       |> clean_up_atp_proof_dependencies
       
   723       |> nasty_atp_proof pool
       
   724       |> map_term_names_in_atp_proof repair_name
       
   725       |> decode_lines ctxt sym_tab
       
   726       |> rpair [] |-> fold_rev (add_line fact_names)
       
   727       |> rpair [] |-> fold_rev add_nontrivial_line
       
   728       |> rpair (0, [])
       
   729       |-> fold_rev (add_desired_line isar_shrink_factor fact_names frees)
       
   730       |> snd
       
   731   in
       
   732     (if null params then [] else [Fix params]) @
       
   733     map2 (step_for_line fact_names) (length lines downto 1) lines
       
   734   end
       
   735 
       
   736 (* When redirecting proofs, we keep information about the labels seen so far in
       
   737    the "backpatches" data structure. The first component indicates which facts
       
   738    should be associated with forthcoming proof steps. The second component is a
       
   739    pair ("assum_ls", "drop_ls"), where "assum_ls" are the labels that should
       
   740    become assumptions and "drop_ls" are the labels that should be dropped in a
       
   741    case split. *)
       
   742 type backpatches = (label * facts) list * (label list * label list)
       
   743 
       
   744 fun used_labels_of_step (Prove (_, _, _, by)) =
       
   745     (case by of
       
   746        By_Metis (ls, _) => ls
       
   747      | Case_Split (proofs, (ls, _)) =>
       
   748        fold (union (op =) o used_labels_of) proofs ls)
       
   749   | used_labels_of_step _ = []
       
   750 and used_labels_of proof = fold (union (op =) o used_labels_of_step) proof []
       
   751 
       
   752 fun new_labels_of_step (Fix _) = []
       
   753   | new_labels_of_step (Let _) = []
       
   754   | new_labels_of_step (Assume (l, _)) = [l]
       
   755   | new_labels_of_step (Prove (_, l, _, _)) = [l]
       
   756 val new_labels_of = maps new_labels_of_step
       
   757 
       
   758 val join_proofs =
       
   759   let
       
   760     fun aux _ [] = NONE
       
   761       | aux proof_tail (proofs as (proof1 :: _)) =
       
   762         if exists null proofs then
       
   763           NONE
       
   764         else if forall (curry (op =) (hd proof1) o hd) (tl proofs) then
       
   765           aux (hd proof1 :: proof_tail) (map tl proofs)
       
   766         else case hd proof1 of
       
   767           Prove ([], l, t, _) => (* FIXME: should we really ignore the "by"? *)
       
   768           if forall (fn Prove ([], l', t', _) :: _ => (l, t) = (l', t')
       
   769                       | _ => false) (tl proofs) andalso
       
   770              not (exists (member (op =) (maps new_labels_of proofs))
       
   771                          (used_labels_of proof_tail)) then
       
   772             SOME (l, t, map rev proofs, proof_tail)
       
   773           else
       
   774             NONE
       
   775         | _ => NONE
       
   776   in aux [] o map rev end
       
   777 
       
   778 fun case_split_qualifiers proofs =
       
   779   case length proofs of
       
   780     0 => []
       
   781   | 1 => [Then]
       
   782   | _ => [Ultimately]
       
   783 
       
   784 fun redirect_proof hyp_ts concl_t proof =
       
   785   let
       
   786     (* The first pass outputs those steps that are independent of the negated
       
   787        conjecture. The second pass flips the proof by contradiction to obtain a
       
   788        direct proof, introducing case splits when an inference depends on
       
   789        several facts that depend on the negated conjecture. *)
       
   790      val concl_l = (conjecture_prefix, length hyp_ts)
       
   791      fun first_pass ([], contra) = ([], contra)
       
   792        | first_pass ((step as Fix _) :: proof, contra) =
       
   793          first_pass (proof, contra) |>> cons step
       
   794        | first_pass ((step as Let _) :: proof, contra) =
       
   795          first_pass (proof, contra) |>> cons step
       
   796        | first_pass ((step as Assume (l as (_, j), _)) :: proof, contra) =
       
   797          if l = concl_l then first_pass (proof, contra ||> cons step)
       
   798          else first_pass (proof, contra) |>> cons (Assume (l, nth hyp_ts j))
       
   799        | first_pass (Prove (qs, l, t, By_Metis (ls, ss)) :: proof, contra) =
       
   800          let val step = Prove (qs, l, t, By_Metis (ls, ss)) in
       
   801            if exists (member (op =) (fst contra)) ls then
       
   802              first_pass (proof, contra |>> cons l ||> cons step)
       
   803            else
       
   804              first_pass (proof, contra) |>> cons step
       
   805          end
       
   806        | first_pass _ = raise Fail "malformed proof"
       
   807     val (proof_top, (contra_ls, contra_proof)) =
       
   808       first_pass (proof, ([concl_l], []))
       
   809     val backpatch_label = the_default ([], []) oo AList.lookup (op =) o fst
       
   810     fun backpatch_labels patches ls =
       
   811       fold merge_fact_sets (map (backpatch_label patches) ls) ([], [])
       
   812     fun second_pass end_qs ([], assums, patches) =
       
   813         ([Prove (end_qs, no_label, concl_t,
       
   814                  By_Metis (backpatch_labels patches (map snd assums)))], patches)
       
   815       | second_pass end_qs (Assume (l, t) :: proof, assums, patches) =
       
   816         second_pass end_qs (proof, (t, l) :: assums, patches)
       
   817       | second_pass end_qs (Prove (qs, l, t, By_Metis (ls, ss)) :: proof, assums,
       
   818                             patches) =
       
   819         (if member (op =) (snd (snd patches)) l andalso
       
   820             not (member (op =) (fst (snd patches)) l) andalso
       
   821             not (AList.defined (op =) (fst patches) l) then
       
   822            second_pass end_qs (proof, assums, patches ||> apsnd (append ls))
       
   823          else case List.partition (member (op =) contra_ls) ls of
       
   824            ([contra_l], co_ls) =>
       
   825            if member (op =) qs Show then
       
   826              second_pass end_qs (proof, assums,
       
   827                                  patches |>> cons (contra_l, (co_ls, ss)))
       
   828            else
       
   829              second_pass end_qs
       
   830                          (proof, assums,
       
   831                           patches |>> cons (contra_l, (l :: co_ls, ss)))
       
   832              |>> cons (if member (op =) (fst (snd patches)) l then
       
   833                          Assume (l, s_not t)
       
   834                        else
       
   835                          Prove (qs, l, s_not t,
       
   836                                 By_Metis (backpatch_label patches l)))
       
   837          | (contra_ls as _ :: _, co_ls) =>
       
   838            let
       
   839              val proofs =
       
   840                map_filter
       
   841                    (fn l =>
       
   842                        if l = concl_l then
       
   843                          NONE
       
   844                        else
       
   845                          let
       
   846                            val drop_ls = filter (curry (op <>) l) contra_ls
       
   847                          in
       
   848                            second_pass []
       
   849                                (proof, assums,
       
   850                                 patches ||> apfst (insert (op =) l)
       
   851                                         ||> apsnd (union (op =) drop_ls))
       
   852                            |> fst |> SOME
       
   853                          end) contra_ls
       
   854              val (assumes, facts) =
       
   855                if member (op =) (fst (snd patches)) l then
       
   856                  ([Assume (l, s_not t)], (l :: co_ls, ss))
       
   857                else
       
   858                  ([], (co_ls, ss))
       
   859            in
       
   860              (case join_proofs proofs of
       
   861                 SOME (l, t, proofs, proof_tail) =>
       
   862                 Prove (case_split_qualifiers proofs @
       
   863                        (if null proof_tail then end_qs else []), l, t,
       
   864                        smart_case_split proofs facts) :: proof_tail
       
   865               | NONE =>
       
   866                 [Prove (case_split_qualifiers proofs @ end_qs, no_label,
       
   867                         concl_t, smart_case_split proofs facts)],
       
   868               patches)
       
   869              |>> append assumes
       
   870            end
       
   871          | _ => raise Fail "malformed proof")
       
   872        | second_pass _ _ = raise Fail "malformed proof"
       
   873     val proof_bottom =
       
   874       second_pass [Show] (contra_proof, [], ([], ([], []))) |> fst
       
   875   in proof_top @ proof_bottom end
       
   876 
       
   877 (* FIXME: Still needed? Probably not. *)
       
   878 val kill_duplicate_assumptions_in_proof =
   704 val kill_duplicate_assumptions_in_proof =
   879   let
   705   let
   880     fun relabel_facts subst =
   706     fun relabel_facts subst =
   881       apfst (map (fn l => AList.lookup (op =) subst l |> the_default l))
   707       apfst (map (fn l => AList.lookup (op =) subst l |> the_default l))
   882     fun do_step (step as Assume (l, t)) (proof, subst, assums) =
   708     fun do_step (step as Assume (l, t)) (proof, subst, assums) =
   893          proof, subst, assums)
   719          proof, subst, assums)
   894       | do_step step (proof, subst, assums) = (step :: proof, subst, assums)
   720       | do_step step (proof, subst, assums) = (step :: proof, subst, assums)
   895     and do_proof proof = fold do_step proof ([], [], []) |> #1 |> rev
   721     and do_proof proof = fold do_step proof ([], [], []) |> #1 |> rev
   896   in do_proof end
   722   in do_proof end
   897 
   723 
   898 val then_chain_proof =
   724 fun used_labels_of_step (Prove (_, _, _, by)) =
   899   let
   725     (case by of
   900     fun aux _ [] = []
   726        By_Metis (ls, _) => ls
   901       | aux _ ((step as Assume (l, _)) :: proof) = step :: aux l proof
   727      | Case_Split (proofs, (ls, _)) =>
   902       | aux l' (Prove (qs, l, t, by) :: proof) =
   728        fold (union (op =) o used_labels_of) proofs ls)
   903         (case by of
   729   | used_labels_of_step _ = []
   904            By_Metis (ls, ss) =>
   730 and used_labels_of proof = fold (union (op =) o used_labels_of_step) proof []
   905            Prove (if member (op =) ls l' then
       
   906                     (Then :: qs, l, t,
       
   907                      By_Metis (filter_out (curry (op =) l') ls, ss))
       
   908                   else
       
   909                     (qs, l, t, By_Metis (ls, ss)))
       
   910          | Case_Split (proofs, facts) =>
       
   911            Prove (qs, l, t, Case_Split (map (aux no_label) proofs, facts))) ::
       
   912         aux l proof
       
   913       | aux _ (step :: proof) = step :: aux no_label proof
       
   914   in aux no_label end
       
   915 
   731 
   916 fun kill_useless_labels_in_proof proof =
   732 fun kill_useless_labels_in_proof proof =
   917   let
   733   let
   918     val used_ls = used_labels_of proof
   734     val used_ls = used_labels_of proof
   919     fun do_label l = if member (op =) used_ls l then l else no_label
   735     fun do_label l = if member (op =) used_ls l then l else no_label
  1035     val type_enc =
   851     val type_enc =
  1036       if is_typed_helper_used_in_atp_proof atp_proof then full_typesN
   852       if is_typed_helper_used_in_atp_proof atp_proof then full_typesN
  1037       else partial_typesN
   853       else partial_typesN
  1038     val lam_trans = lam_trans_from_atp_proof atp_proof metis_default_lam_trans
   854     val lam_trans = lam_trans_from_atp_proof atp_proof metis_default_lam_trans
  1039 
   855 
  1040     val atp_proof' = (*###*)
   856     fun isar_proof_of () =
  1041       atp_proof
   857       let
  1042       |> clean_up_atp_proof_dependencies
   858         val atp_proof =
  1043       |> nasty_atp_proof pool
   859           atp_proof
  1044       |> map_term_names_in_atp_proof repair_name
   860           |> clean_up_atp_proof_dependencies
  1045       |> decode_lines ctxt sym_tab
   861           |> nasty_atp_proof pool
  1046       |> rpair [] |-> fold_rev (add_line fact_names)
   862           |> map_term_names_in_atp_proof repair_name
  1047       |> rpair [] |-> fold_rev add_nontrivial_line
   863           |> decode_lines ctxt sym_tab
  1048       |> rpair (0, [])
   864           |> rpair [] |-> fold_rev (add_line fact_names)
  1049       |-> fold_rev (add_desired_line isar_shrink_factor fact_names frees)
   865           |> rpair [] |-> fold_rev add_nontrivial_line
  1050       |> snd
   866           |> rpair (0, [])
  1051 (*
   867           |-> fold_rev (add_desired_line isar_shrink_factor fact_names frees)
  1052       |> tap (map (tracing o PolyML.makestring))
   868           |> snd
  1053 *)
   869         val conj_name = conjecture_prefix ^ string_of_int (length hyp_ts)
  1054 
   870         val conjs =
  1055     val conj_name = conjecture_prefix ^ string_of_int (length hyp_ts)
   871           atp_proof
  1056     val conjs =
   872           |> map_filter (fn Inference (name as (_, ss), _, _, []) =>
  1057       atp_proof'
   873                             if member (op =) ss conj_name then SOME name else NONE
  1058       |> map_filter (fn Inference (name as (_, ss), _, _, []) =>
   874                           | _ => NONE)
  1059                         if member (op =) ss conj_name then SOME name else NONE
   875         fun dep_of_step (Definition _) = NONE
  1060                       | _ => NONE)
   876           | dep_of_step (Inference (name, _, _, from)) = SOME (from, name)
  1061 
   877         val ref_graph = atp_proof |> map_filter dep_of_step |> make_ref_graph
  1062 
   878         val axioms = axioms_of_ref_graph ref_graph conjs
  1063     fun dep_of_step (Definition _) = NONE
   879         val tainted = tainted_atoms_of_ref_graph ref_graph conjs
  1064       | dep_of_step (Inference (name, _, _, from)) = SOME (from, name)
   880         val props =
  1065 
   881           Symtab.empty
  1066     val ref_graph = atp_proof' |> map_filter dep_of_step |> make_ref_graph
   882           |> fold (fn Definition _ => I (* FIXME *)
  1067     val axioms = axioms_of_ref_graph ref_graph conjs
   883                     | Inference ((s, _), t, _, _) =>
  1068     val tainted = tainted_atoms_of_ref_graph ref_graph conjs
   884                       Symtab.update_new (s,
  1069 
   885                           t |> member (op = o apsnd fst) tainted s ? s_not))
  1070     val props =
   886                   atp_proof
  1071       Symtab.empty
   887         (* FIXME: add "fold_rev forall_of (map Var (Term.add_vars t []))"? *)
  1072       |> fold (fn Definition _ => I (* FIXME *)
   888         fun prop_of_clause c =
  1073                 | Inference ((s, _), t, _, _) =>
   889           fold (curry s_disj) (map_filter (Symtab.lookup props o fst) c)
  1074                   Symtab.update_new (s,
   890                @{term False}
  1075                       t |> member (op = o apsnd fst) tainted s ? s_not))
   891         fun label_of_clause c = (space_implode "___" (map fst c), 0)
  1076               atp_proof'
   892         fun maybe_show outer c =
  1077 
   893           (outer andalso length c = 1 andalso subset (op =) (c, conjs))
  1078     val direct_proof =
   894           ? cons Show
  1079       ref_graph |> redirect_graph axioms tainted
   895         fun do_have outer qs (gamma, c) =
  1080                 |> chain_direct_proof
   896           Prove (maybe_show outer c qs, label_of_clause c, prop_of_clause c,
  1081                 |> tap (tracing o string_of_direct_proof) (*###*)
   897                  By_Metis (fold (add_fact_from_dependency fact_names
  1082 
   898                                  o the_single) gamma ([], [])))
  1083     fun prop_of_clause c =
   899         fun do_inf outer (Have z) = do_have outer [] z
  1084       fold (curry s_disj) (map_filter (Symtab.lookup props o fst) c)
   900           | do_inf outer (Hence z) = do_have outer [Then] z
  1085            @{term False}
   901           | do_inf outer (Cases cases) =
  1086 
   902             let val c = succedent_of_cases cases in
  1087     fun label_of_clause c = (space_implode "___" (map fst c), 0)
   903               Prove (maybe_show outer c [Ultimately], label_of_clause c,
  1088 
   904                      prop_of_clause c,
  1089     fun maybe_show outer c =
   905                      Case_Split (map (do_case false) cases, ([], [])))
  1090       (outer andalso length c = 1 andalso subset (op =) (c, conjs)) ? cons Show
   906             end
  1091 
   907         and do_case outer (c, infs) =
  1092     fun do_have outer qs (gamma, c) =
   908           Assume (label_of_clause c, prop_of_clause c) ::
  1093       Prove (maybe_show outer c qs, label_of_clause c, prop_of_clause c,
   909           map (do_inf outer) infs
  1094              By_Metis (fold (add_fact_from_dependency fact_names o the_single)
   910         val isar_proof =
  1095                             gamma ([], [])))
   911           (if null params then [] else [Fix params]) @
  1096     fun do_inf outer (Have z) = do_have outer [] z
   912           (ref_graph
  1097       | do_inf outer (Hence z) = do_have outer [Then] z
   913            |> redirect_graph axioms tainted
  1098       | do_inf outer (Cases cases) =
   914            |> chain_direct_proof
  1099         let val c = succedent_of_cases cases in
   915            |> map (do_inf true)
  1100           Prove (maybe_show outer c [Ultimately], label_of_clause c,
       
  1101                  prop_of_clause c,
       
  1102                  Case_Split (map (do_case false) cases, ([], [])))
       
  1103         end
       
  1104     and do_case outer (c, infs) =
       
  1105       Assume (label_of_clause c, prop_of_clause c) :: map (do_inf outer) infs
       
  1106 
       
  1107     val isar_proof =
       
  1108       (if null params then [] else [Fix params]) @
       
  1109       (map (do_inf true) direct_proof
       
  1110        |> kill_useless_labels_in_proof
       
  1111        |> relabel_proof)
       
  1112       |> string_for_proof ctxt type_enc lam_trans subgoal subgoal_count
       
  1113       |> tap tracing (*###*)
       
  1114 
       
  1115     fun isar_proof_for () =
       
  1116       case atp_proof
       
  1117            |> isar_proof_from_atp_proof pool ctxt isar_shrink_factor fact_names
       
  1118                                         sym_tab params frees
       
  1119            |> redirect_proof hyp_ts concl_t
       
  1120            |> kill_duplicate_assumptions_in_proof
   916            |> kill_duplicate_assumptions_in_proof
  1121            |> then_chain_proof
       
  1122            |> kill_useless_labels_in_proof
   917            |> kill_useless_labels_in_proof
  1123            |> relabel_proof
   918            |> relabel_proof)
  1124            |> string_for_proof ctxt type_enc lam_trans subgoal subgoal_count of
   919           |> string_for_proof ctxt type_enc lam_trans subgoal subgoal_count
  1125         "" =>
   920       in
  1126         if isar_proof_requested then
   921         case isar_proof of
  1127           "\nNo structured proof available (proof too short)."
   922           "" =>
  1128         else
   923           if isar_proof_requested then
  1129           ""
   924             "\nNo structured proof available (proof too short)."
  1130       | proof =>
   925           else
  1131         "\n\n" ^ (if isar_proof_requested then "Structured proof"
   926             ""
  1132                   else "Perhaps this will work") ^
   927         | _ =>
  1133         ":\n" ^ Markup.markup Isabelle_Markup.sendback proof
   928           "\n\n" ^ (if isar_proof_requested then "Structured proof"
       
   929                     else "Perhaps this will work") ^
       
   930           ":\n" ^ Markup.markup Isabelle_Markup.sendback isar_proof
       
   931       end
  1134     val isar_proof =
   932     val isar_proof =
  1135       if debug then
   933       if debug then
  1136         isar_proof_for ()
   934         isar_proof_of ()
  1137       else case try isar_proof_for () of
   935       else case try isar_proof_of () of
  1138         SOME s => s
   936         SOME s => s
  1139       | NONE => if isar_proof_requested then
   937       | NONE => if isar_proof_requested then
  1140                   "\nWarning: The Isar proof construction failed."
   938                   "\nWarning: The Isar proof construction failed."
  1141                 else
   939                 else
  1142                   ""
   940                   ""