From f224e2392dc5f8ccf5791703acd77cd800f077f5 Mon Sep 17 00:00:00 2001 From: Japheth Lim Date: Fri, 27 Apr 2018 16:42:47 +1000 Subject: [PATCH] lib: add time_methods method for comparing proof tactic speeds --- lib/NICTATools.thy | 1 + lib/Time_Methods_Cmd.thy | 131 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 132 insertions(+) create mode 100644 lib/Time_Methods_Cmd.thy diff --git a/lib/NICTATools.thy b/lib/NICTATools.thy index 2c50a74f5..dcfb4bb2d 100644 --- a/lib/NICTATools.thy +++ b/lib/NICTATools.thy @@ -17,6 +17,7 @@ imports (* Solves_Tac *) Rule_By_Method Eisbach_Methods + Time_Methods_Cmd Insulin ShowTypes AutoLevity_Hooks diff --git a/lib/Time_Methods_Cmd.thy b/lib/Time_Methods_Cmd.thy new file mode 100644 index 000000000..2f50120d3 --- /dev/null +++ b/lib/Time_Methods_Cmd.thy @@ -0,0 +1,131 @@ +(* + * + * Copyright 2018, Data61, CSIRO + * + * This software may be distributed and modified according to the terms of + * the BSD 2-Clause license. Note that NO WARRANTY is provided. + * See "LICENSE_BSD2.txt" for details. + * + * @TAG(DATA61_BSD) + *) + +theory Time_Methods_Cmd imports + Eisbach_Methods +begin + +text \ + Utility that runs several methods on the same proof goal, printing the + running time of each one. + + Usage: + + apply (time_methods [(no_check)] + [name1:] \method1\ + [name2:] \method2\ + ...) + + See the examples at the end of this theory. +\ + +ML {* +*} +method_setup time_methods = + \ +let + (* Work around Isabelle running every apply method on an empty proof state *) + fun skip_dummy_state tactic = fn st => + case Thm.prop_of st of + Const ("Pure.prop", _) $ (Const ("Pure.term", _) $ Const ("Pure.dummy_pattern", _)) => + Seq.succeed st + | _ => tactic st; +in + Scan.lift (Scan.optional (Args.parens (Parse.reserved "no_check") >> K true) false) -- + Scan.repeat1 (Scan.option (Scan.lift (Parse.liberal_name --| Parse.$$$ ":")) -- Method.text_closure) >> + (fn (no_check, maybe_named_methods) => fn ctxt => fn facts => let + val named_methods = tag_list 1 maybe_named_methods + |> map (fn (i, (maybe_name, method)) => + case maybe_name of SOME name => (name, method) + | NONE => ("[method " ^ string_of_int i ^ "]", method)) + fun tac st = let + fun run name method = + Timing.timing (fn () => case method_evaluate method ctxt facts st |> Seq.pull of + NONE => (NONE, Seq.empty) + | SOME (st', sts') => (SOME st', Seq.cons st' sts')) () + val results = named_methods |> map (fn (name, method) => + let val (time, (st', results)) = run name method + val _ = warning (name ^ ": " ^ Timing.message time) + in {name = name, state = st', results = results} end) + val canonical_result = hd results + val other_results = tl results + in + if no_check then #results canonical_result else + case other_results |> filter (fn result => + Option.map Thm.full_prop_of (#state result) <> + Option.map Thm.full_prop_of (#state canonical_result)) of + [] => #results canonical_result + | (bad::_) => raise THM ("methods \"" ^ #name canonical_result ^ + "\" and \"" ^ #name bad ^ "\" have different results", + 1, the_list (#state canonical_result) @ the_list (#state bad)) + end + in SIMPLE_METHOD (skip_dummy_state tac) [] end) +end +\ + +text \Examples\ +experiment begin + lemma + "a = b \ b = c \ a = c" + apply (time_methods + \rule back_subst[where P="op= a"], assumption+\ + \rule trans, assumption+\) + done + + lemma + "a = b \ b = c \ a = c" + apply (time_methods (no_check) + \rule back_subst[where P="op= a"]\ + \rule trans\) + text \no_check prevents failing even though the method results differ\ + apply assumption+ + done + + text \ + Fast and slow list reversals + \ + lemma list_eval_rev_append: + "rev xs = rev xs @ []" + "rev [] @ ys = ys" + "rev (x # xs) @ ys = rev xs @ (x # ys)" + by auto + + lemma "rev [10..90] = map (op- 100) [10..90]" + "rev [10..290] = map (op- 300) [10..290]" + text \evaluate everything but @{term rev}\ + apply (all \match conclusion in "rev x = y" for x y \ + \rule subst[where t = x], simp\\) + apply (all \match conclusion in "rev x = y" for x y \ + \rule subst[where t = y], simp\\) + + text \evaluate @{term rev}\ + apply (time_methods + simp: \simp\ + slow: \simp only: rev.simps append.simps\ + fast: \subst list_eval_rev_append(1), simp only: list_eval_rev_append(2-3)\ + ) + apply (time_methods + simp: \simp\ + slow: \simp only: rev.simps append.simps\ + fast: \subst list_eval_rev_append(1), simp only: list_eval_rev_append(2-3)\ + ) + done + + + text \Other tests\ + + lemma "A" + -- "simp should fail and time_methods should propagate the failure" + apply (fails \time_methods \simp\\) + oops +end + +end