1 (*<*)theory AB = Main:(*>*)
3 section{*Case Study: A Context Free Grammar*}
6 Grammars are nothing but shorthands for inductive definitions of nonterminals
7 which represent sets of strings. For example, the production
8 $A \to B c$ is short for
9 \[ w \in B \Longrightarrow wc \in A \]
10 This section demonstrates this idea with an example
11 due to Hopcroft and Ullman, a grammar for generating all words with an
12 equal number of $a$'s and~$b$'s:
14 S &\to& \epsilon \mid b A \mid a B \nonumber\\
15 A &\to& a S \mid b A A \nonumber\\
16 B &\to& b S \mid a B B \nonumber
18 At the end we say a few words about the relationship between
19 the original proof \cite[p.\ts81]{HopcroftUllman} and our formal version.
21 We start by fixing the alphabet, which consists only of @{term a}'s
25 datatype alfa = a | b;
28 For convenience we include the following easy lemmas as simplification rules:
31 lemma [simp]: "(x \<noteq> a) = (x = b) \<and> (x \<noteq> b) = (x = a)";
35 Words over this alphabet are of type @{typ"alfa list"}, and
36 the three nonterminals are declared as sets of such words:
39 consts S :: "alfa list set"
44 The productions above are recast as a \emph{mutual} inductive
45 definition\index{inductive definition!simultaneous}
46 of @{term S}, @{term A} and~@{term B}:
52 "w \<in> A \<Longrightarrow> b#w \<in> S"
53 "w \<in> B \<Longrightarrow> a#w \<in> S"
55 "w \<in> S \<Longrightarrow> a#w \<in> A"
56 "\<lbrakk> v\<in>A; w\<in>A \<rbrakk> \<Longrightarrow> b#v@w \<in> A"
58 "w \<in> S \<Longrightarrow> b#w \<in> B"
59 "\<lbrakk> v \<in> B; w \<in> B \<rbrakk> \<Longrightarrow> a#v@w \<in> B";
62 First we show that all words in @{term S} contain the same number of @{term
63 a}'s and @{term b}'s. Since the definition of @{term S} is by mutual
64 induction, so is the proof: we show at the same time that all words in
65 @{term A} contain one more @{term a} than @{term b} and all words in @{term
66 B} contains one more @{term b} than @{term a}.
70 "(w \<in> S \<longrightarrow> size[x\<in>w. x=a] = size[x\<in>w. x=b]) \<and>
71 (w \<in> A \<longrightarrow> size[x\<in>w. x=a] = size[x\<in>w. x=b] + 1) \<and>
72 (w \<in> B \<longrightarrow> size[x\<in>w. x=b] = size[x\<in>w. x=a] + 1)"
75 These propositions are expressed with the help of the predefined @{term
76 filter} function on lists, which has the convenient syntax @{text"[x\<in>xs. P
77 x]"}, the list of all elements @{term x} in @{term xs} such that @{prop"P x"}
78 holds. Remember that on lists @{text size} and @{text length} are synonymous.
80 The proof itself is by rule induction and afterwards automatic:
83 by (rule S_A_B.induct, auto)
86 This may seem surprising at first, and is indeed an indication of the power
87 of inductive definitions. But it is also quite straightforward. For example,
88 consider the production $A \to b A A$: if $v,w \in A$ and the elements of $A$
89 contain one more $a$ than~$b$'s, then $bvw$ must again contain one more $a$
92 As usual, the correctness of syntactic descriptions is easy, but completeness
93 is hard: does @{term S} contain \emph{all} words with an equal number of
94 @{term a}'s and @{term b}'s? It turns out that this proof requires the
95 following lemma: every string with two more @{term a}'s than @{term
96 b}'s can be cut somewhere such that each half has one more @{term a} than
97 @{term b}. This is best seen by imagining counting the difference between the
98 number of @{term a}'s and @{term b}'s starting at the left end of the
99 word. We start with 0 and end (at the right end) with 2. Since each move to the
100 right increases or decreases the difference by 1, we must have passed through
101 1 on our way from 0 to 2. Formally, we appeal to the following discrete
102 intermediate value theorem @{thm[source]nat0_intermed_int_val}
103 @{thm[display]nat0_intermed_int_val[no_vars]}
104 where @{term f} is of type @{typ"nat \<Rightarrow> int"}, @{typ int} are the integers,
105 @{text"\<bar>.\<bar>"} is the absolute value function, and @{term"#1::int"} is the
106 integer 1 (see \S\ref{sec:numbers}).
108 First we show that our specific function, the difference between the
109 numbers of @{term a}'s and @{term b}'s, does indeed only change by 1 in every
110 move to the right. At this point we also start generalizing from @{term a}'s
111 and @{term b}'s to an arbitrary property @{term P}. Otherwise we would have
112 to prove the desired lemma twice, once as stated above and once with the
113 roles of @{term a}'s and @{term b}'s interchanged.
116 lemma step1: "\<forall>i < size w.
117 \<bar>(int(size[x\<in>take (i+1) w. P x])-int(size[x\<in>take (i+1) w. \<not>P x]))
118 - (int(size[x\<in>take i w. P x])-int(size[x\<in>take i w. \<not>P x]))\<bar> \<le> #1"
121 The lemma is a bit hard to read because of the coercion function
122 @{text"int :: nat \<Rightarrow> int"}. It is required because @{term size} returns
123 a natural number, but subtraction on type~@{typ nat} will do the wrong thing.
124 Function @{term take} is predefined and @{term"take i xs"} is the prefix of
125 length @{term i} of @{term xs}; below we also need @{term"drop i xs"}, which
126 is what remains after that prefix has been dropped from @{term xs}.
128 The proof is by induction on @{term w}, with a trivial base case, and a not
129 so trivial induction step. Since it is essentially just arithmetic, we do not
135 by(force simp add:zabs_def take_Cons split:nat.split if_splits);
138 Finally we come to the above mentioned lemma about cutting in half a word with two
139 more elements of one sort than of the other sort:
143 "size[x\<in>w. P x] = size[x\<in>w. \<not>P x]+2 \<Longrightarrow>
144 \<exists>i\<le>size w. size[x\<in>take i w. P x] = size[x\<in>take i w. \<not>P x]+1";
147 This is proved by @{text force} with the help of the intermediate value theorem,
148 instantiated appropriately and with its first premise disposed of by lemma
152 apply(insert nat0_intermed_int_val[OF step1, of "P" "w" "#1"]);
157 Lemma @{thm[source]part1} tells us only about the prefix @{term"take i w"}.
158 An easy lemma deals with the suffix @{term"drop i w"}:
163 "\<lbrakk>size[x\<in>take i w @ drop i w. P x] =
164 size[x\<in>take i w @ drop i w. \<not>P x]+2;
165 size[x\<in>take i w. P x] = size[x\<in>take i w. \<not>P x]+1\<rbrakk>
166 \<Longrightarrow> size[x\<in>drop i w. P x] = size[x\<in>drop i w. \<not>P x]+1";
167 by(simp del:append_take_drop_id);
170 In the proof, we have had to disable a normally useful lemma:
172 @{thm append_take_drop_id[no_vars]}
173 \rulename{append_take_drop_id}
176 To dispose of trivial cases automatically, the rules of the inductive
177 definition are declared simplification rules:
180 declare S_A_B.intros[simp];
183 This could have been done earlier but was not necessary so far.
185 The completeness theorem tells us that if a word has the same number of
186 @{term a}'s and @{term b}'s, then it is in @{term S}, and similarly
187 for @{term A} and @{term B}:
190 theorem completeness:
191 "(size[x\<in>w. x=a] = size[x\<in>w. x=b] \<longrightarrow> w \<in> S) \<and>
192 (size[x\<in>w. x=a] = size[x\<in>w. x=b] + 1 \<longrightarrow> w \<in> A) \<and>
193 (size[x\<in>w. x=b] = size[x\<in>w. x=a] + 1 \<longrightarrow> w \<in> B)";
196 The proof is by induction on @{term w}. Structural induction would fail here
197 because, as we can see from the grammar, we need to make bigger steps than
198 merely appending a single letter at the front. Hence we induct on the length
199 of @{term w}, using the induction rule @{thm[source]length_induct}:
202 apply(induct_tac w rule: length_induct);
203 (*<*)apply(rename_tac w)(*>*)
206 The @{text rule} parameter tells @{text induct_tac} explicitly which induction
207 rule to use. For details see \S\ref{sec:complete-ind} below.
208 In this case the result is that we may assume the lemma already
209 holds for all words shorter than @{term w}.
211 The proof continues with a case distinction on @{term w},
212 i.e.\ if @{term w} is empty or not.
217 (*<*)apply(rename_tac x v)(*>*)
220 Simplification disposes of the base case and leaves only two step
222 if @{prop"w = a#v"} and @{prop[display]"size[x\<in>v. x=a] = size[x\<in>v. x=b]+2"} then
223 @{prop"b#v \<in> A"}, and similarly for @{prop"w = b#v"}.
224 We only consider the first case in detail.
226 After breaking the conjuction up into two cases, we can apply
227 @{thm[source]part1} to the assumption that @{term w} contains two more @{term
228 a}'s than @{term b}'s.
233 apply(frule part1[of "\<lambda>x. x=a", simplified]);
238 This yields an index @{prop"i \<le> length v"} such that
239 @{prop[display]"length [x\<in>take i v . x = a] = length [x\<in>take i v . x = b] + 1"}
240 With the help of @{thm[source]part2} it follows that
241 @{prop[display]"length [x\<in>drop i v . x = a] = length [x\<in>drop i v . x = b] + 1"}
244 apply(drule part2[of "\<lambda>x. x=a", simplified]);
248 Now it is time to decompose @{term v} in the conclusion @{prop"b#v \<in> A"}
249 into @{term"take i v @ drop i v"},
250 after which the appropriate rule of the grammar reduces the goal
251 to the two subgoals @{prop"take i v \<in> A"} and @{prop"drop i v \<in> A"}:
254 apply(rule_tac n1=i and t=v in subst[OF append_take_drop_id]);
255 apply(rule S_A_B.intros);
258 Both subgoals follow from the induction hypothesis because both @{term"take i
259 v"} and @{term"drop i v"} are shorter than @{term w}:
262 apply(force simp add: min_less_iff_disj);
263 apply(force split add: nat_diff_split);
266 Note that the variables @{term n1} and @{term t} referred to in the
267 substitution step above come from the derived theorem @{text"subst[OF
268 append_take_drop_id]"}.
270 The case @{prop"w = b#v"} is proved analogously:
274 apply(frule part1[of "\<lambda>x. x=b", simplified]);
277 apply(drule part2[of "\<lambda>x. x=b", simplified]);
279 apply(rule_tac n1=i and t=v in subst[OF append_take_drop_id]);
280 apply(rule S_A_B.intros);
281 apply(force simp add:min_less_iff_disj);
282 by(force simp add:min_less_iff_disj split add: nat_diff_split);
285 We conclude this section with a comparison of our proof with
286 Hopcroft and Ullman's \cite[p.\ts81]{HopcroftUllman}. For a start, the texbook
287 grammar, for no good reason, excludes the empty word. That complicates
288 matters just a little bit because we now have 8 instead of our 7 productions.
290 More importantly, the proof itself is different: rather than
291 separating the two directions, they perform one induction on the
292 length of a word. This deprives them of the beauty of rule induction,
293 and in the easy direction (correctness) their reasoning is more
294 detailed than our @{text auto}. For the hard part (completeness), they
295 consider just one of the cases that our @{text simp_all} disposes of
296 automatically. Then they conclude the proof by saying about the
297 remaining cases: ``We do this in a manner similar to our method of
298 proof for part (1); this part is left to the reader''. But this is
299 precisely the part that requires the intermediate value theorem and
300 thus is not at all similar to the other cases (which are automatic in
301 Isabelle). The authors are at least cavalier about this point and may
302 even have overlooked the slight difficulty lurking in the omitted
303 cases. This is not atypical for pen-and-paper proofs, once analysed in