(* $Id: sol.thy,v 1.5 2012/01/04 13:40:21 webertj Exp $ Author: Tobias Nipkow *) header {* Context-Free Grammars *} (*<*) theory sol imports Main begin (*>*) text {* This exercise is concerned with context-free grammars (CFGs). Please read Section~7.4 in the tutorial which explains how to model CFGs as inductive definitions. Our particular example is about defining valid sequences of parentheses. *} subsection {* Two grammars *} text {* The most natural definition of valid sequences of parentheses is this: \[ S \quad\to\quad \varepsilon \quad\mid\quad '('~S~')' \quad\mid\quad S~S \] where $\varepsilon$ is the empty word. A second, somewhat unusual grammar is the following one: \[ T \quad\to\quad \varepsilon \quad\mid\quad T~'('~T~')' \] Model both grammars as inductive sets $S$ and $T$ and prove $S = T$. *} text {* The alphabet: *} datatype alpha = A | B text {* Standard grammar: *} inductive_set S :: "alpha list set" where S1: "[] : S" | S2: "w : S \ A#w@[B] : S" | S3: "v : S \ w : S \ v @ w : S" declare S1 [iff] S2[intro!,simp] text {* Nonstandard grammar: *} inductive_set T :: "alpha list set" where T1: "[] : T" | T23: "v : T \ w : T \ v @ A # w @ [B]: T" declare T1 [iff] text {* @{text T} is a subset of @{text S}: *} lemma T2S: "w : T \ w : S" apply (erule T.induct) apply simp apply (blast intro: S3) done text {* @{text S} is a subset of @{text T}: *} lemma T2: "w : T \ A#w@[B] : T" using T23[where v = "[]"] by simp lemma T3: "v : T \ u : T \ u@v : T" apply (erule T.induct) apply fastforce apply (simp add: append_assoc[symmetric] del:append_assoc) apply (blast intro: T23) done lemma S2T: "w : S \ w : T" apply (erule S.induct) apply simp apply (blast intro: T2) apply (blast intro: T3) done text {* @{text "S = T"}: *} lemma "S = T" by (blast intro: S2T T2S) subsection {* A recursive function *} text {* Instead of a grammar, we can also define valid sequences of parentheses via a test function: traverse the word from left to right while counting how many closing parentheses are still needed. If the counter is 0 at the end, the sequence is valid. Define this recursive function and prove that a word is in $S$ iff it is accepted by your function. The $\Longrightarrow$ direction is easy, the other direction more complicated. *} fun balanced :: "alpha list \ nat \ bool" where "balanced [] 0 = True" | "balanced (A#w) n = balanced w (Suc n)" | "balanced (B#w) (Suc n) = balanced w n" | "balanced w n = False" text {* Correctness of the recognizer w.r.t.\ @{text S}: *} lemma [simp]: "balanced w n \ balanced (w@[B]) (Suc n)" apply (induct w n rule: balanced.induct) apply simp_all done lemma [simp]: "\balanced v n; balanced w 0\ \ balanced (v @ w) n" apply (induct v n rule: balanced.induct) apply simp_all done lemma "w : S \ balanced w 0" apply (erule S.induct) apply simp_all done text {* Completeness of the recognizer w.r.t.\ @{text S}: *} lemma [iff]: "[A,B] : S" using S2[where w = "[]"] by simp lemma AB: assumes u: "u \ S" shows "\v w. u = v@w \ v @ A # B # w \ S" using u proof(induct) case S1 thus ?case by simp next case (S2 u) have uS: "u \ S" and IH: "\v w. u = v @ w \ v @ A # B # w \ S" and asm: "A # u @ [B] = v @ w" by fact+ show "v @ A # B # w \ S" proof (cases v) case Nil hence "w = A # u @ [B]" using asm by simp hence "w \ S" using uS by simp hence "[A,B] @ w \ S" by(blast intro:S3) thus ?thesis using Nil by simp next case (Cons x v') show ?thesis proof (cases w rule:rev_cases) case Nil from uS have "(A # u @ [B]) @ [A,B] \ S" by(blast intro:S3) thus ?thesis using Nil Cons asm by auto next case (snoc w' y) hence u: "u = v' @ w'" and [simp]: "x = A & y = B" using Cons asm by auto from u have "v' @ A # B # w' \ S" by(rule IH) hence "A # (v' @ A # B # w') @ [B] \ S" by(rule S.S2) thus ?thesis using Cons snoc by auto qed qed next case (S3 v' w') have v'S: "v' \ S" and w'S: "w' \ S" and IHv: "\v w. v' = v @ w \ v @ A # B # w \ S" and IHw: "\v w. w' = v @ w \ v @ A # B # w \ S" and asm: "v' @ w' = v @ w" by fact+ then obtain r where "v' = v @ r \ r @ w' = w \ v' @ r = v \ w' = r @ w" (is "?A \ ?B") by (auto simp:append_eq_append_conv2) thus "v @ A # B # w \ S" proof assume A: ?A hence "v @ A # B # r \ S" using IHv by blast hence "(v @ A # B # r) @ w' \ S" using w'S by(rule S.S3) thus ?thesis using A by auto next assume B: ?B hence "r @ A # B # w \ S" using IHw by blast with v'S have "v' @ (r @ A # B # w) \ S" by(rule S.S3) thus ?thesis using B by auto qed qed text {* The same lemma for friends of the apply style: *} lemma "u \ S \ ALL v w. u = v@w \ v @ A # B # w \ S" apply(erule S.induct) apply simp apply(rename_tac u) apply (clarsimp simp:Cons_eq_append_conv) apply(rule conjI) apply (clarsimp) apply(subgoal_tac "[A,B] @ (A # u @ [B]) : S") apply(simp) apply(blast intro:S3) apply(clarsimp simp:append_eq_append_conv2 Cons_eq_append_conv) apply(rename_tac w w1 w2) apply(erule disjE) apply clarsimp apply(subgoal_tac "A # (w1 @ A # B # w2) @ [B] : S") apply simp apply(blast intro:S3) apply clarsimp apply(erule disjE) apply clarsimp apply(subgoal_tac "A # (u @ [A,B]) @ [B] : S") apply(simp) apply(blast intro:S3) apply clarsimp apply(subgoal_tac "(A # u @ [B]) @ [A,B] : S") apply(simp) apply(blast intro:S3) apply(clarsimp simp:append_eq_append_conv2) apply(rename_tac u v w x y) apply(erule disjE) apply clarsimp apply(subgoal_tac "(w @ A # B # y) @ v : S") apply(simp) apply(blast intro:S3) apply clarsimp apply(blast intro:S3) done lemma "balanced w n \ replicate n A @ w : S" apply (induct w n rule: balanced.induct) apply simp_all apply (simp add: replicate_app_Cons_same) apply (simp add: AB replicate_app_Cons_same[symmetric]) done (*<*) end (*>*)