theory ToyLang_demo imports Main begin datatype toy_language = Skip | Seq toy_language toy_language | Do toy_language inductive semantics :: "toy_language \ toy_language \ bool" where semantics_seq1: "\semantics p p'\ \ semantics (Seq p q) (Seq p' q)" | semantics_seq2: "\p = Skip\ \ semantics (Seq p q) q" | semantics_do: "semantics (Do p) (Seq p (Do p))" inductive big_semantics :: "toy_language \ toy_language \ bool" where big_semantics1: "big_semantics p p" | big_semantics2: "\semantics p q; big_semantics q r\ \ big_semantics p r" definition stuck where "stuck p = (\q. semantics p q \ False)" definition terminates where "terminates p = (\q. big_semantics p q \ stuck q)" lemma "terminates Skip" unfolding terminates_def stuck_def by(auto simp add: semantics.simps[where ?a1.0="Skip",simplified] intro: big_semantics1) \ \Step-by-step proof: apply(rule exI[where x="Skip"]) apply(rule conjI) apply(rule big_semantics1) apply(rule allI) apply(subst semantics.simps) apply simp done \ thm semantics.simps \ \Loop-prone: contains an instance of itself in the RHS. \ thm semantics.simps[where ?a1.0="Skip"] \ \Specialised to the case where source term is Skip\ thm semantics.simps[where ?a1.0="Skip",simplified] \ \simp normal form of previous lemma\ thm semantics.simps[where ?a1.0="Do p"] \ \Only applies to exactly the blue variable p\ thm semantics.simps[where ?a1.0="Do p" for p] \ \Notice the schematic: applies to any term of the shape "Do _"\ lemmas do_simp = semantics.simps[where ?a1.0="Do p" for p, simplified] \ \lemmas foo = bar saves thm(s) bar under the name foo\ lemmas seq_simp = semantics.simps[where ?a1.0="Seq p q" for p q, simplified] lemma "terminates Skip" unfolding terminates_def stuck_def by(auto intro: big_semantics.intros simp add: semantics.simps[where ?a1.0="Skip",simplified]) \ \First try: structural induction on p.\ lemma do_diverges_lemma: assumes "big_semantics (Do p) q" shows "Ex (semantics q)" using assms apply(induct p) oops \ \Goes in circles. Besides, we shouldn't have to care what's in the body; a Do diverges because it's a Do, not because of what's in it.\ \ \Second try: rule induction.\ lemma do_diverges_lemma: assumes "big_semantics (Do p) q" shows "Ex (semantics q)" using assms apply(induct rule: big_semantics.induct) nitpick \ \Finds a counterexample that happens to be not spurious. The induction ate the information that the original process was a do, so our first subgoal is now unprovable.\ oops \ \Third try: rule induction, conserving the syntactic information that the first argument to big_semantics is "Do p".\ lemma do_diverges_lemma: assumes "big_semantics (Do p) q" shows "Ex (semantics q)" using assms apply(induct "Do p" q rule: big_semantics.induct) \ \Tell induct to preserve the structural information about the source term.\ apply(force simp add: do_simp) \ \First subgoal is now provable!\ \ \But the second subgoal is unprovable: the induction hypothesis only applies to terms=Do _, but the residual after reducing a Do is a sequential composition\ apply(erule meta_mp) apply(subst (asm) do_simp) apply clarify apply simp oops \ \Third attempt: Weaken the induction hypothesis. Find a weaker syntactic predicate than "equals Do p" that is strong enough so that there will always be an outgoing transition, but weak enough so that it's preserved by the transition relation (that way we will be able to apply the induction hypothesis). \ primrec has_trailing_do where "has_trailing_do(Do p) = True" | "has_trailing_do(Seq p q) = has_trailing_do q" | "has_trailing_do(Skip) = False" lemma not_skip_reduces: "p1 \ Skip \ \p'. semantics p1 p'" apply(induct p1) \ \Structural induction because there's nothing in the assumptions to do rule induction on\ apply simp apply(rename_tac p q) apply(case_tac "p \ Skip"; force intro: semantics.intros) \ \m1; m2 applies m2 to every subgoal produces by m1\ apply(force intro: semantics.intros) \ \force is like auto except it tries harder, on a single subgoal, and either completely discharges the goal or fails\ done \ \Step-by-step proof: apply(induct p1) apply simp apply clarsimp apply(rename_tac p q) apply(case_tac "p \ Skip") apply clarsimp apply(force intro: semantics.intros) apply clarsimp apply(force intro: semantics.intros) apply(force intro: semantics.intros) done\ lemma seq_reduces: "Ex (semantics (Seq p1 p2))" by(simp add: not_skip_reduces) lemma has_trailing_do_reduces: "has_trailing_do p \ Ex (semantics p)" by(induct p; force simp add: do_simp intro: seq_reduces) \ \ Step-by-step proof apply(induct p) apply simp apply clarsimp defer apply(rule exI) apply(force simp add: do_simp) apply(rule seq_reduces) done\ lemma has_trailing_do_sem_pres: "semantics p q \ has_trailing_do p \ has_trailing_do q" proof(induct rule: semantics.induct) case (semantics_seq1 p p' q) then show ?case by simp next case (semantics_seq2 p q) then show ?case by simp next case (semantics_do p) then show ?case by simp qed lemma do_diverges_lemma_lemma: assumes "big_semantics p q" and "has_trailing_do p" shows "Ex (semantics q)" using assms by(induct rule: big_semantics.induct) (auto intro: has_trailing_do_sem_pres has_trailing_do_reduces) lemma do_diverges_lemma: assumes "big_semantics (Do p) q" shows "Ex (semantics q)" using assms by(auto elim: do_diverges_lemma_lemma) \ \Step-by-step proof: apply(erule_tac do_diverges_lemma_lemma) apply simp done\ lemma "\terminates(Do p)" unfolding terminates_def stuck_def by(auto intro: do_diverges_lemma) end