src/HOL/Tools/Sledgehammer/sledgehammer_isar_proof.ML
changeset 55281 765555d6a0b2
parent 55280 f0187a12b8f2
child 55282 d4a033f07800
equal deleted inserted replaced
55280:f0187a12b8f2 55281:765555d6a0b2
   121 fun steps_of_isar_proof (Proof (_, _, steps)) = steps
   121 fun steps_of_isar_proof (Proof (_, _, steps)) = steps
   122 
   122 
   123 fun label_of_isar_step (Prove (_, _, l, _, _, _, _)) = SOME l
   123 fun label_of_isar_step (Prove (_, _, l, _, _, _, _)) = SOME l
   124   | label_of_isar_step _ = NONE
   124   | label_of_isar_step _ = NONE
   125 
   125 
   126 fun subproofs_of_isar_step (Prove (_, _, _, _, subproofs, _, _)) = SOME subproofs
   126 fun subproofs_of_isar_step (Prove (_, _, _, _, subs, _, _)) = subs
   127   | subproofs_of_isar_step _ = NONE
   127   | subproofs_of_isar_step _ = []
   128 
   128 
   129 fun facts_of_isar_step (Prove (_, _, _, _, _, facts, _)) = facts
   129 fun facts_of_isar_step (Prove (_, _, _, _, _, facts, _)) = facts
   130   | facts_of_isar_step _ = ([], [])
   130   | facts_of_isar_step _ = ([], [])
   131 
   131 
   132 fun proof_methods_of_isar_step (Prove (_, _, _, _, _, _, meths)) = meths
   132 fun proof_methods_of_isar_step (Prove (_, _, _, _, _, _, meths)) = meths
   133   | proof_methods_of_isar_step _ = []
   133   | proof_methods_of_isar_step _ = []
   134 
   134 
   135 fun fold_isar_step f step =
   135 fun fold_isar_step f step =
   136   fold (steps_of_isar_proof #> fold_isar_steps f) (these (subproofs_of_isar_step step)) #> f step
   136   fold (steps_of_isar_proof #> fold_isar_steps f) (subproofs_of_isar_step step) #> f step
   137 and fold_isar_steps f = fold (fold_isar_step f)
   137 and fold_isar_steps f = fold (fold_isar_step f)
   138 
   138 
   139 fun map_isar_steps f =
   139 fun map_isar_steps f =
   140   let
   140   let
   141     fun map_proof (Proof (fix, assms, steps)) = Proof (fix, assms, map map_step steps)
   141     fun map_proof (Proof (fix, assms, steps)) = Proof (fix, assms, map map_step steps)
   142     and map_step (step as Let _) = f step
   142     and map_step (step as Let _) = f step
   143       | map_step (Prove (qs, xs, l, t, subproofs, facts, meths)) =
   143       | map_step (Prove (qs, xs, l, t, subs, facts, meths)) =
   144         f (Prove (qs, xs, l, t, map map_proof subproofs, facts, meths))
   144         f (Prove (qs, xs, l, t, map map_proof subs, facts, meths))
   145   in map_proof end
   145   in map_proof end
   146 
   146 
   147 val add_isar_steps = fold_isar_steps (fn Prove _ => Integer.add 1 | _ => I)
   147 val add_isar_steps = fold_isar_steps (fn Prove _ => Integer.add 1 | _ => I)
   148 
   148 
   149 (* canonical proof labels: 1, 2, 3, ... in post traversal order *)
   149 (* canonical proof labels: 1, 2, 3, ... in post traversal order *)
   154   val ord = canonical_label_ord)
   154   val ord = canonical_label_ord)
   155 
   155 
   156 fun chain_qs_lfs NONE lfs = ([], lfs)
   156 fun chain_qs_lfs NONE lfs = ([], lfs)
   157   | chain_qs_lfs (SOME l0) lfs =
   157   | chain_qs_lfs (SOME l0) lfs =
   158     if member (op =) lfs l0 then ([Then], lfs |> remove (op =) l0) else ([], lfs)
   158     if member (op =) lfs l0 then ([Then], lfs |> remove (op =) l0) else ([], lfs)
   159 fun chain_isar_step lbl (Prove (qs, xs, l, t, subproofs, (lfs, gfs), meths)) =
   159 fun chain_isar_step lbl (Prove (qs, xs, l, t, subs, (lfs, gfs), meths)) =
   160     let val (qs', lfs) = chain_qs_lfs lbl lfs in
   160     let val (qs', lfs) = chain_qs_lfs lbl lfs in
   161       Prove (qs' @ qs, xs, l, t, map chain_isar_proof subproofs, (lfs, gfs), meths)
   161       Prove (qs' @ qs, xs, l, t, map chain_isar_proof subs, (lfs, gfs), meths)
   162     end
   162     end
   163   | chain_isar_step _ step = step
   163   | chain_isar_step _ step = step
   164 and chain_isar_steps _ [] = []
   164 and chain_isar_steps _ [] = []
   165   | chain_isar_steps (prev as SOME _) (i :: is) =
   165   | chain_isar_steps (prev as SOME _) (i :: is) =
   166     chain_isar_step prev i :: chain_isar_steps (label_of_isar_step i) is
   166     chain_isar_step prev i :: chain_isar_steps (label_of_isar_step i) is
   173     val used_ls =
   173     val used_ls =
   174       fold_isar_steps (facts_of_isar_step #> fst #> union (op =)) (steps_of_isar_proof proof) []
   174       fold_isar_steps (facts_of_isar_step #> fst #> union (op =)) (steps_of_isar_proof proof) []
   175 
   175 
   176     fun kill_label l = if member (op =) used_ls l then l else no_label
   176     fun kill_label l = if member (op =) used_ls l then l else no_label
   177 
   177 
   178     fun kill_step (Prove (qs, xs, l, t, subproofs, facts, meths)) =
   178     fun kill_step (Prove (qs, xs, l, t, subs, facts, meths)) =
   179         Prove (qs, xs, kill_label l, t, map kill_proof subproofs, facts, meths)
   179         Prove (qs, xs, kill_label l, t, map kill_proof subs, facts, meths)
   180       | kill_step step = step
   180       | kill_step step = step
   181     and kill_proof (Proof (fix, assms, steps)) =
   181     and kill_proof (Proof (fix, assms, steps)) =
   182       Proof (fix, map (apfst kill_label) assms, map kill_step steps)
   182       Proof (fix, map (apfst kill_label) assms, map kill_step steps)
   183   in
   183   in
   184     kill_proof proof
   184     kill_proof proof
   187 fun relabel_isar_proof_canonically proof =
   187 fun relabel_isar_proof_canonically proof =
   188   let
   188   let
   189     fun next_label l (next, subst) =
   189     fun next_label l (next, subst) =
   190       let val l' = ("", next) in (l', (next + 1, (l, l') :: subst)) end
   190       let val l' = ("", next) in (l', (next + 1, (l, l') :: subst)) end
   191 
   191 
   192     fun relabel_facts (lfs, gfs) (_, subst) =
   192     fun relabel_step (Prove (qs, fix, l, t, subs, (lfs, gfs), meths)) (accum as (_, subst)) =
   193       (map (AList.lookup (op =) subst #> the) lfs, gfs)
       
   194       handle Option.Option =>
       
   195         raise Fail "Sledgehammer_Isar_Proof: relabel_isar_proof_canonically"
       
   196 
       
   197     fun relabel_assm (l, t) state =
       
   198       next_label l state |> (fn (l, state) => ((l, t), state))
       
   199 
       
   200     fun relabel_proof (Proof (fix, assms, steps)) state =
       
   201       let
       
   202         val (assms, state) = fold_map relabel_assm assms state
       
   203         val (steps, state) = fold_map relabel_step steps state
       
   204       in
       
   205         (Proof (fix, assms, steps), state)
       
   206       end
       
   207 
       
   208     and relabel_step (Prove (qs, fix, l, t, subproofs, facts, meths)) state =
       
   209         let
   193         let
   210           val facts = relabel_facts facts state
   194           val lfs' = maps (the_list o AList.lookup (op =) subst) lfs
   211           val (subproofs, state) = fold_map relabel_proof subproofs state
   195           val ((subs', l'), accum') = accum
   212           val (l, state) = next_label l state
   196             |> fold_map relabel_proof subs
       
   197             ||>> next_label l
   213         in
   198         in
   214           (Prove (qs, fix, l, t, subproofs, facts, meths), state)
   199           (Prove (qs, fix, l', t, subs', (lfs', gfs), meths), accum')
   215         end
   200         end
   216       | relabel_step step state = (step, state)
   201       | relabel_step step accum = (step, accum)
       
   202     and relabel_proof (Proof (fix, assms, steps)) =
       
   203       fold_map (fn (l, t) => next_label l #> apfst (rpair t)) assms
       
   204       ##>> fold_map relabel_step steps
       
   205       #>> (fn (assms, steps) => Proof (fix, assms, steps))
   217   in
   206   in
   218     fst (relabel_proof proof (0, []))
   207     fst (relabel_proof proof (0, []))
   219   end
   208   end
   220 
   209 
   221 val assume_prefix = "a"
   210 val assume_prefix = "a"
   222 val have_prefix = "f"
   211 val have_prefix = "f"
   223 
   212 
   224 val relabel_isar_proof_finally =
   213 val relabel_isar_proof_finally =
   225   let
   214   let
   226     fun fresh_label depth prefix (accum as (l, subst, next)) =
   215     fun next_label depth prefix l (accum as (next, subst)) =
   227       if l = no_label then
   216       if l = no_label then
   228         accum
   217         (l, accum)
   229       else
   218       else
   230         let val l' = (replicate_string (depth + 1) prefix, next) in
   219         let val l' = (replicate_string (depth + 1) prefix, next) in
   231           (l', (l, l') :: subst, next + 1)
   220           (l', (next + 1, (l, l') :: subst))
   232         end
   221         end
   233 
   222 
   234     fun relabel_facts subst = apfst (maps (the_list o AList.lookup (op =) subst))
   223     fun relabel_step depth (Prove (qs, xs, l, t, subs, (lfs, gfs), meths)) (accum as (_, subst)) =
   235 
       
   236     fun relabel_assm depth (l, t) (subst, next) =
       
   237       let val (l, subst, next) = (l, subst, next) |> fresh_label depth assume_prefix in
       
   238         ((l, t), (subst, next))
       
   239       end
       
   240 
       
   241     fun relabel_assms subst depth assms = fold_map (relabel_assm depth) assms (subst, 1) ||> fst
       
   242 
       
   243     fun relabel_steps _ _ _ [] = []
       
   244       | relabel_steps subst depth next (Prove (qs, xs, l, t, sub, facts, meths) :: steps) =
       
   245         let
   224         let
   246           val (l, subst, next) = (l, subst, next) |> fresh_label depth have_prefix
   225           val lfs' = maps (the_list o AList.lookup (op =) subst) lfs
   247           val sub = relabel_proofs subst depth sub
   226           val (l', accum' as (next', subst')) = next_label depth have_prefix l accum
   248           val facts = relabel_facts subst facts
   227           val subs' = map (relabel_proof subst' (depth + 1)) subs
   249         in
   228         in
   250           Prove (qs, xs, l, t, sub, facts, meths) :: relabel_steps subst depth next steps
   229           (Prove (qs, xs, l', t, subs', (lfs', gfs), meths), accum')
   251         end
   230         end
   252       | relabel_steps subst depth next (step :: steps) =
   231       | relabel_step _ step accum = (step, accum)
   253         step :: relabel_steps subst depth next steps
       
   254     and relabel_proof subst depth (Proof (fix, assms, steps)) =
   232     and relabel_proof subst depth (Proof (fix, assms, steps)) =
   255       let val (assms, subst) = relabel_assms subst depth assms in
   233       (1, subst)
   256         Proof (fix, assms, relabel_steps subst depth 1 steps)
   234       |> fold_map (fn (l, t) => next_label depth assume_prefix l #> apfst (rpair t)) assms
   257       end
   235       ||>> fold_map (relabel_step depth) steps
   258     and relabel_proofs subst depth = map (relabel_proof subst (depth + 1))
   236       |> (fn ((assms, steps), _) => Proof (fix, assms, steps))
   259   in
   237   in
   260     relabel_proof [] 0
   238     relabel_proof [] 0
   261   end
   239   end
   262 
   240 
   263 val indent_size = 2
   241 val indent_size = 2
   318     (* Local facts are always passed via "using", which affects "meson" and "metis". This is
   296     (* Local facts are always passed via "using", which affects "meson" and "metis". This is
   319        arguably stylistically superior, because it emphasises the structure of the proof. It is also
   297        arguably stylistically superior, because it emphasises the structure of the proof. It is also
   320        more robust w.r.t. preplay: Preplay is performed before chaining of local facts with "hence"
   298        more robust w.r.t. preplay: Preplay is performed before chaining of local facts with "hence"
   321        and "thus" is introduced. See also "tac_of_method" in "Sledgehammer_Isar_Preplay". *)
   299        and "thus" is introduced. See also "tac_of_method" in "Sledgehammer_Isar_Preplay". *)
   322     fun of_method ls ss meth =
   300     fun of_method ls ss meth =
   323         let val direct = is_direct_method meth in
   301       let val direct = is_direct_method meth in
   324           using_facts ls (if direct then [] else ss) ^
   302         using_facts ls (if direct then [] else ss) ^
   325           by_facts (string_of_proof_method meth) [] (if direct then ss else [])
   303         by_facts (string_of_proof_method meth) [] (if direct then ss else [])
   326         end
   304       end
   327 
   305 
   328     fun of_free (s, T) =
   306     fun of_free (s, T) =
   329       maybe_quote s ^ " :: " ^
   307       maybe_quote s ^ " :: " ^
   330       maybe_quote (simplify_spaces (with_vanilla_print_mode (Syntax.string_of_typ ctxt) T))
   308       maybe_quote (simplify_spaces (with_vanilla_print_mode (Syntax.string_of_typ ctxt) T))
   331 
   309 
   332     fun add_frees xs (s, ctxt) =
   310     fun add_frees xs (s, ctxt) =
   333       (s ^ space_implode " and " (map of_free xs), ctxt |> register_fixes xs)
   311       (s ^ space_implode " and " (map of_free xs), ctxt |> register_fixes xs)
   334 
   312 
   335     fun add_fix _ [] = I
   313     fun add_fix _ [] = I
   336       | add_fix ind xs =
   314       | add_fix ind xs = add_str (of_indent ind ^ "fix ") #> add_frees xs #> add_str "\n"
   337         add_str (of_indent ind ^ "fix ")
       
   338         #> add_frees xs
       
   339         #> add_str "\n"
       
   340 
   315 
   341     fun add_assm ind (l, t) =
   316     fun add_assm ind (l, t) =
   342       add_str (of_indent ind ^ "assume " ^ of_label l)
   317       add_str (of_indent ind ^ "assume " ^ of_label l) #> add_term t #> add_str "\n"
   343       #> add_term t
       
   344       #> add_str "\n"
       
   345 
       
   346     fun add_assms ind assms = fold (add_assm ind) assms
       
   347 
   318 
   348     fun of_subproof ind ctxt proof =
   319     fun of_subproof ind ctxt proof =
   349       let
   320       let
   350         val ind = ind + 1
   321         val ind = ind + 1
   351         val s = of_proof ind ctxt proof
   322         val s = of_proof ind ctxt proof
   355         replicate_string (ind * indent_size - size prefix) " " ^ prefix ^
   326         replicate_string (ind * indent_size - size prefix) " " ^ prefix ^
   356         String.extract (s, ind * indent_size, SOME (size s - ind * indent_size - 1)) ^
   327         String.extract (s, ind * indent_size, SOME (size s - ind * indent_size - 1)) ^
   357         suffix ^ "\n"
   328         suffix ^ "\n"
   358       end
   329       end
   359     and of_subproofs _ _ _ [] = ""
   330     and of_subproofs _ _ _ [] = ""
   360       | of_subproofs ind ctxt qs subproofs =
   331       | of_subproofs ind ctxt qs subs =
   361         (if member (op =) qs Then then of_moreover ind else "") ^
   332         (if member (op =) qs Then then of_moreover ind else "") ^
   362         space_implode (of_moreover ind) (map (of_subproof ind ctxt) subproofs)
   333         space_implode (of_moreover ind) (map (of_subproof ind ctxt) subs)
   363     and add_step_pre ind qs subproofs (s, ctxt) =
   334     and add_step_pre ind qs subs (s, ctxt) =
   364       (s ^ of_subproofs ind ctxt qs subproofs ^ of_indent ind, ctxt)
   335       (s ^ of_subproofs ind ctxt qs subs ^ of_indent ind, ctxt)
   365     and add_step ind (Let (t1, t2)) =
   336     and add_step ind (Let (t1, t2)) =
   366         add_str (of_indent ind ^ "let ")
   337         add_str (of_indent ind ^ "let ")
   367         #> add_term t1 #> add_str " = " #> add_term t2
   338         #> add_term t1 #> add_str " = " #> add_term t2 #> add_str "\n"
   368         #> add_str "\n"
   339       | add_step ind (Prove (qs, xs, l, t, subs, (ls, ss), meths as meth :: _)) =
   369       | add_step ind (Prove (qs, xs, l, t, subproofs, (ls, ss), meths as meth :: _)) =
   340         add_step_pre ind qs subs
   370         add_step_pre ind qs subproofs
       
   371         #> (case xs of
   341         #> (case xs of
   372              [] => add_str (of_have qs (length subproofs) ^ " ")
   342              [] => add_str (of_have qs (length subs) ^ " ")
   373            | _ =>
   343            | _ => add_str (of_obtain qs (length subs) ^ " ") #> add_frees xs #> add_str " where ")
   374              add_str (of_obtain qs (length subproofs) ^ " ") #> add_frees xs #> add_str " where ")
       
   375         #> add_str (of_label l)
   344         #> add_str (of_label l)
   376         #> add_term t
   345         #> add_term t
   377         #> add_str (" " ^
   346         #> add_str (" " ^
   378              of_method (sort_distinct label_ord ls) (sort_distinct string_ord ss) meth ^
   347              of_method (sort_distinct label_ord ls) (sort_distinct string_ord ss) meth ^
   379              (case comment_of l meths of
   348              (case comment_of l meths of
   380                "" => ""
   349                "" => ""
   381              | comment => " (* " ^ comment ^ " *)") ^ "\n")
   350              | comment => " (* " ^ comment ^ " *)") ^ "\n")
   382     and add_steps ind = fold (add_step ind)
   351     and add_steps ind = fold (add_step ind)
   383     and of_proof ind ctxt (Proof (xs, assms, steps)) =
   352     and of_proof ind ctxt (Proof (xs, assms, steps)) =
   384       ("", ctxt) |> add_fix ind xs |> add_assms ind assms |> add_steps ind steps |> fst
   353       ("", ctxt)
       
   354       |> add_fix ind xs
       
   355       |> fold (add_assm ind) assms
       
   356       |> add_steps ind steps
       
   357       |> fst
   385   in
   358   in
   386     (* One-step Metis proofs are pointless; better use the one-liner directly. *)
   359     (* One-step Metis proofs are pointless; better use the one-liner directly. *)
   387     (case proof of
   360     (case proof of
   388       Proof ([], [], []) => "" (* degenerate case: the conjecture is "True" with Z3 *)
   361       Proof ([], [], []) => "" (* degenerate case: the conjecture is "True" with Z3 *)
   389     | Proof ([], [], [Prove (_, [], _, _, [], _, Metis_Method _ :: _)]) => ""
   362     | Proof ([], [], [Prove (_, [], _, _, [], _, Metis_Method _ :: _)]) => ""