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 "" |