(* Examples for Simpl VCG in part from $AFP/Simpl/ex/VcgEx.thy. License: LGPL *) theory week11A_demo imports Vcg begin -- --------------------------------------------------------------------- subsection {* State Spaces *} text {* The state space for the example programs below. The record lists all global and local variables that will occur. Each name has the postfix @{text "_'"} so program variable names don't clutter the Isabelle name space. Hoare logic syntax and VCG rely on this naming scheme. *} record 'g vars = "'g state" + A_' :: nat I_' :: nat M_' :: nat N_' :: nat R_' :: nat S_' :: nat Abr_':: string B_' :: bool subsection {* Basic Examples *} text {* Basic Hoare triples have a procedure environment @{text \}, a precondition, a command, and a postcondition. To distinguish them from normal sets, pre/post conditions use @{text "{|"} and @{text "|}"} instead of @{text "{"} and @{text "}"}. Unicode symbols are @{text "\"} and @{text "\"}. *} lemma "\ \ {| \N = 5 |} \N :== 2 * \N {| \N = 10 |}" apply (rule HoarePartial.Basic) apply simp done text {* Program variables referring to the current state are prefixed by the @{text "\"} (acute) symbol. This distinguishes them from normal, logical Isabelle names. *} text {* We usually do not apply Hoare logic rules directly, but use the VCG instead. It performs very basic simplification, and also tries to leave goals that don't explicitly refer to the state. *} lemma "\\ \True\ \N :== 10 \\N = 10\" by vcg lemma "\\ \2 * \N = 10\ \N :== 2 * \N \\N = 10\" by vcg -- "Note the difference to the Hoare rule application above, N becomes an Isabelle bound name, not a record function of the state." lemma "\\ \\N = 5\ \N :== 2 * \N \\N = 10\" apply vcg apply simp done -- "This triple hs the weakest precondition, so vcg solves it directly" lemma "\\ \a = a \ b = b\ \M :== a;; \N :== b \\M = a \ \N = b\" by vcg -- "Usually the vcg will leave implications to solve" lemma "\\ \True\ \M :== a;; \N :== b \\M = a \ \N = b\" apply vcg apply simp done -- "Slightly more complex example" lemma "\\ \\M = a \ \N = b\ \I :== \M;; \M :== \N;; \N :== \I \\M = b \ \N = a\" apply vcg apply simp done -- "Single stepping for debugging:" lemma "\\ \\M = a \ \N = b\ \I :== \M;; \M :== \N;; \N :== \I \\M = b \ \N = a\" apply vcg_step apply vcg_step apply vcg_step apply vcg_step apply simp done subsection {* While loops *} -- "Loop invariants are specified inline:" lemma while_sum: "\\ \\M = 0 \ \S = 0 \ WHILE \M \ a INV \\S = \M * b \ DO \S :== \S + b;; \M :== \M + 1 OD \\S = a * b \" apply vcg apply auto done -- "We actually proved a statement about a program schema for any a and b:" thm while_sum -- "Factorial:" primrec fac:: "nat \ nat" where "fac 0 = 1" | "fac (Suc n) = (Suc n) * fac n" lemma fac_simp [simp]: "0 < i \ fac i = i * fac (i - 1)" by (cases i) simp_all lemma fac_sound: "\ \ {| \N = n |} \M :== 1;; WHILE \N \ 0 INV {| fac n = \M * fac \N |} DO \M :== \M * \N;; \N :== \N - 1 OD {| \M = fac n |}" apply vcg apply auto done -- --------------------------------------------------------------------- subsection "More control flow" -- "Exceptions" lemma "\\ \\N = 0\ Throw \False\,\\N = 0\" by vcg lemma "\\ \True\ TRY IF \A = 0 THEN THROW ELSE \N :== 1 FI CATCH \N :== 42;; THROW END \\N = 1\,\\N = 42\" apply vcg apply simp done -- "Break/continue" lemma "\\ \\M = 0 \ \S = 0\ TRY WHILE True INV \\S = \M * b\ DO IF \M = a THEN THROW ELSE \S :== \S + b;; \M :== \M + 1 FI OD CATCH SKIP END \\S = a * b\" apply vcg apply auto done lemma "\\ \\M = 0 \ \S = 0\ TRY WHILE True INV \\S = \M * b\ DO IF \M = a THEN \Abr :== ''Break'';;THROW ELSE \S :== \S + b;; \M :== \M + 1 FI OD CATCH IF \Abr = ''Break'' THEN SKIP ELSE Throw FI END \\S = a * b\" apply vcg apply auto done -- {* SWITCH *} lemma "\\ \\N = 5\ SWITCH \B {True} \ \N :== 6 | {False} \ \N :== 7 END \\N > 5\" apply vcg apply simp done lemma "\\ \\N = 5\ SWITCH \N {v. v < 5} \ \N :== 6 | {v. v \ 5} \ \N :== 7 END \\N > 5\" apply vcg apply simp done -- --------------------------------------------------------------------- subsection {* Procedures *} text {* Parameters are on the left of the |, result parameters are on the right. *} procedures Add (N,M|R) = "\R :== \N + \M;; \N :== 0" text {* The procedures command sets up a locale (named context with set of assumptions) for the name and implementation of Add. *} context Add_impl begin thm Add_impl Add_body_def lemma "\ \ \ True \ \N :== n;; \I :== CALL Add(\N,\N) \ \I = 2 * \N \ \N = n\" -- "formal parameters are replaced with actual, I gets the value of R, the change of N is local to Add" apply vcg apply simp done end -- {* Recursion: *} text {* Recursive version of factorial. *} procedures Fac (N|R) = "IF \N = 0 THEN \R :== 1 ELSE \R :== CALL Fac(\N - 1);; \R :== \N * \R FI" context Fac_impl begin thm Fac_impl Fac_body_def text {* For recursive procedures, we carry around another environment \ for procedure specifications. Similarly to induction, we need to quantify n if we want to use a different value n in the recursive call. *} lemma "\n. \,\\\\N=n\ PROC Fac(\N,\R) \\R = fac n\" apply (hoare_rule HoarePartial.ProcRec1) apply vcg apply simp done -- "single stepping, \ does not really need to be named explicitly." lemma "\n. \\\\N=n\ \R :== PROC Fac(\N) \\R = fac n\" apply (hoare_rule HoarePartial.ProcRec1) apply vcg_step apply vcg_step apply vcg_step apply vcg_step apply vcg_step apply simp done end (* of context Fac_Impl *) end