13613
|
1 |
(*<*)theory Induction = Main:(*>*)
|
|
2 |
|
|
3 |
section{*Case distinction and induction \label{sec:Induct}*}
|
|
4 |
|
|
5 |
|
|
6 |
subsection{*Case distinction*}
|
|
7 |
|
|
8 |
text{* We have already met the @{text cases} method for performing
|
|
9 |
binary case splits. Here is another example: *}
|
|
10 |
lemma "P \<or> \<not> P"
|
|
11 |
proof cases
|
|
12 |
assume "P" thus ?thesis ..
|
|
13 |
next
|
|
14 |
assume "\<not> P" thus ?thesis ..
|
|
15 |
qed
|
|
16 |
text{*\noindent Note that the two cases must come in this order.
|
|
17 |
|
|
18 |
This form is appropriate if @{term P} is textually small. However, if
|
|
19 |
@{term P} is large, we don't want to repeat it. This can be avoided by
|
|
20 |
the following idiom *}
|
|
21 |
|
|
22 |
lemma "P \<or> \<not> P"
|
|
23 |
proof (cases "P")
|
|
24 |
case True thus ?thesis ..
|
|
25 |
next
|
|
26 |
case False thus ?thesis ..
|
|
27 |
qed
|
|
28 |
text{*\noindent which is simply a shorthand for the previous
|
|
29 |
proof. More precisely, the phrases \isakeyword{case}~@{prop
|
|
30 |
True}/@{prop False} abbreviate the corresponding assumptions @{prop P}
|
|
31 |
and @{prop"\<not>P"}. In contrast to the previous proof we can prove the cases
|
|
32 |
in arbitrary order.
|
|
33 |
|
|
34 |
The same game can be played with other datatypes, for example lists:
|
|
35 |
*}
|
|
36 |
(*<*)declare length_tl[simp del](*>*)
|
|
37 |
lemma "length(tl xs) = length xs - 1"
|
|
38 |
proof (cases xs)
|
|
39 |
case Nil thus ?thesis by simp
|
|
40 |
next
|
|
41 |
case Cons thus ?thesis by simp
|
|
42 |
qed
|
|
43 |
text{*\noindent Here \isakeyword{case}~@{text Nil} abbreviates
|
|
44 |
\isakeyword{assume}~@{prop"xs = []"} and \isakeyword{case}~@{text Cons}
|
|
45 |
abbreviates \isakeyword{fix}~@{text"? ??"}
|
|
46 |
\isakeyword{assume}~@{text"xs = ? # ??"} where @{text"?"} and @{text"??"}
|
|
47 |
stand for variable names that have been chosen by the system.
|
|
48 |
Therefore we cannot
|
|
49 |
refer to them (this would lead to obscure proofs) and have not even shown
|
|
50 |
them. Luckily, this proof is simple enough we do not need to refer to them.
|
|
51 |
However, sometimes one may have to. Hence Isar offers a simple scheme for
|
|
52 |
naming those variables: replace the anonymous @{text Cons} by, for example,
|
|
53 |
@{text"(Cons y ys)"}, which abbreviates \isakeyword{fix}~@{text"y ys"}
|
|
54 |
\isakeyword{assume}~@{text"xs = Cons y ys"}, i.e.\ @{prop"xs = y # ys"}. Here
|
|
55 |
is a (somewhat contrived) example: *}
|
|
56 |
|
|
57 |
lemma "length(tl xs) = length xs - 1"
|
|
58 |
proof (cases xs)
|
|
59 |
case Nil thus ?thesis by simp
|
|
60 |
next
|
|
61 |
case (Cons y ys)
|
|
62 |
hence "length(tl xs) = length ys \<and> length xs = length ys + 1"
|
|
63 |
by simp
|
|
64 |
thus ?thesis by simp
|
|
65 |
qed
|
|
66 |
|
|
67 |
|
|
68 |
subsection{*Structural induction*}
|
|
69 |
|
|
70 |
text{* We start with a simple inductive proof where both cases are proved automatically: *}
|
|
71 |
lemma "2 * (\<Sum>i<n+1. i) = n*(n+1)"
|
|
72 |
by (induct n, simp_all)
|
|
73 |
|
|
74 |
text{*\noindent If we want to expose more of the structure of the
|
|
75 |
proof, we can use pattern matching to avoid having to repeat the goal
|
|
76 |
statement: *}
|
|
77 |
lemma "2 * (\<Sum>i<n+1. i) = n*(n+1)" (is "?P n")
|
|
78 |
proof (induct n)
|
|
79 |
show "?P 0" by simp
|
|
80 |
next
|
|
81 |
fix n assume "?P n"
|
|
82 |
thus "?P(Suc n)" by simp
|
|
83 |
qed
|
|
84 |
|
|
85 |
text{* \noindent We could refine this further to show more of the equational
|
|
86 |
proof. Instead we explore the same avenue as for case distinctions:
|
|
87 |
introducing context via the \isakeyword{case} command: *}
|
|
88 |
lemma "2 * (\<Sum>i<n+1. i) = n*(n+1)"
|
|
89 |
proof (induct n)
|
|
90 |
case 0 show ?case by simp
|
|
91 |
next
|
|
92 |
case Suc thus ?case by simp
|
|
93 |
qed
|
|
94 |
|
|
95 |
text{* \noindent The implicitly defined @{text ?case} refers to the
|
|
96 |
corresponding case to be proved, i.e.\ @{text"?P 0"} in the first case and
|
|
97 |
@{text"?P(Suc n)"} in the second case. Context \isakeyword{case}~@{text 0} is
|
|
98 |
empty whereas \isakeyword{case}~@{text Suc} assumes @{text"?P n"}. Again we
|
|
99 |
have the same problem as with case distinctions: we cannot refer to an anonymous @{term n}
|
|
100 |
in the induction step because it has not been introduced via \isakeyword{fix}
|
|
101 |
(in contrast to the previous proof). The solution is the same as above:
|
|
102 |
replace @{term Suc} by @{text"(Suc i)"}: *}
|
|
103 |
lemma fixes n::nat shows "n < n*n + 1"
|
|
104 |
proof (induct n)
|
|
105 |
case 0 show ?case by simp
|
|
106 |
next
|
|
107 |
case (Suc i) thus "Suc i < Suc i * Suc i + 1" by simp
|
|
108 |
qed
|
|
109 |
|
|
110 |
text{* \noindent Of course we could again have written
|
|
111 |
\isakeyword{thus}~@{text ?case} instead of giving the term explicitly
|
|
112 |
but we wanted to use @{term i} somewhere. *}
|
|
113 |
|
|
114 |
subsection{*Induction formulae involving @{text"\<And>"} or @{text"\<Longrightarrow>"}*}
|
|
115 |
|
|
116 |
text{* Let us now consider the situation where the goal to be proved contains
|
|
117 |
@{text"\<And>"} or @{text"\<Longrightarrow>"}, say @{prop"\<And>x. P x \<Longrightarrow> Q x"} --- motivation and a
|
|
118 |
real example follow shortly. This means that in each case of the induction,
|
|
119 |
@{text ?case} would be of the same form @{prop"\<And>x. P' x \<Longrightarrow> Q' x"}. Thus the
|
|
120 |
first proof steps will be the canonical ones, fixing @{text x} and assuming
|
|
121 |
@{prop"P' x"}. To avoid this tedium, induction performs these steps
|
|
122 |
automatically: for example in case @{text"(Suc n)"}, @{text ?case} is only
|
|
123 |
@{prop"Q' x"} whereas the assumptions (named @{term Suc}) contain both the
|
|
124 |
usual induction hypothesis \emph{and} @{prop"P' x"}. To fix the name of the
|
|
125 |
bound variable @{term x} you may write @{text"(Suc n x)"}, thus abbreviating
|
|
126 |
\isakeyword{fix}~@{term x}.
|
|
127 |
It should be clear how this example generalizes to more complex formulae.
|
|
128 |
|
|
129 |
As a concrete example we will now prove complete induction via
|
|
130 |
structural induction: *}
|
|
131 |
|
|
132 |
lemma assumes A: "(\<And>n. (\<And>m. m < n \<Longrightarrow> P m) \<Longrightarrow> P n)"
|
|
133 |
shows "P(n::nat)"
|
|
134 |
proof (rule A)
|
|
135 |
show "\<And>m. m < n \<Longrightarrow> P m"
|
|
136 |
proof (induct n)
|
|
137 |
case 0 thus ?case by simp
|
|
138 |
next
|
|
139 |
case (Suc n m) -- {*@{text"?m < n \<Longrightarrow> P ?m"} and @{prop"m < Suc n"}*}
|
|
140 |
show ?case -- {*@{term ?case}*}
|
|
141 |
proof cases
|
|
142 |
assume eq: "m = n"
|
|
143 |
from Suc A have "P n" by blast
|
|
144 |
with eq show "P m" by simp
|
|
145 |
next
|
|
146 |
assume "m \<noteq> n"
|
|
147 |
with Suc have "m < n" by arith
|
|
148 |
thus "P m" by(rule Suc)
|
|
149 |
qed
|
|
150 |
qed
|
|
151 |
qed
|
|
152 |
text{* \noindent Given the explanations above and the comments in
|
|
153 |
the proof text, the proof should be quite readable.
|
|
154 |
|
|
155 |
The statement of the lemma is interesting because it deviates from the style in
|
|
156 |
the Tutorial~\cite{LNCS2283}, which suggests to introduce @{text"\<forall>"} or
|
|
157 |
@{text"\<longrightarrow>"} into a theorem to strengthen it for induction. In structured Isar
|
|
158 |
proofs we can use @{text"\<And>"} and @{text"\<Longrightarrow>"} instead. This simplifies the
|
|
159 |
proof and means we do not have to convert between the two kinds of
|
|
160 |
connectives.
|
|
161 |
*}
|
|
162 |
|
|
163 |
subsection{*Rule induction*}
|
|
164 |
|
|
165 |
text{* We define our own version of reflexive transitive closure of a
|
|
166 |
relation *}
|
|
167 |
consts rtc :: "('a \<times> 'a)set \<Rightarrow> ('a \<times> 'a)set" ("_*" [1000] 999)
|
|
168 |
inductive "r*"
|
|
169 |
intros
|
|
170 |
refl: "(x,x) \<in> r*"
|
|
171 |
step: "\<lbrakk> (x,y) \<in> r; (y,z) \<in> r* \<rbrakk> \<Longrightarrow> (x,z) \<in> r*"
|
|
172 |
|
|
173 |
text{* \noindent and prove that @{term"r*"} is indeed transitive: *}
|
|
174 |
lemma assumes A: "(x,y) \<in> r*" shows "(y,z) \<in> r* \<Longrightarrow> (x,z) \<in> r*"
|
|
175 |
using A
|
|
176 |
proof induct
|
|
177 |
case refl thus ?case .
|
|
178 |
next
|
|
179 |
case step thus ?case by(blast intro: rtc.step)
|
|
180 |
qed
|
|
181 |
text{*\noindent Rule induction is triggered by a fact $(x_1,\dots,x_n)
|
|
182 |
\in R$ piped into the proof, here \isakeyword{using}~@{text A}. The
|
|
183 |
proof itself follows the inductive definition very
|
|
184 |
closely: there is one case for each rule, and it has the same name as
|
|
185 |
the rule, analogous to structural induction.
|
|
186 |
|
|
187 |
However, this proof is rather terse. Here is a more readable version:
|
|
188 |
*}
|
|
189 |
|
|
190 |
lemma assumes A: "(x,y) \<in> r*" and B: "(y,z) \<in> r*"
|
|
191 |
shows "(x,z) \<in> r*"
|
|
192 |
proof -
|
|
193 |
from A B show ?thesis
|
|
194 |
proof induct
|
|
195 |
fix x assume "(x,z) \<in> r*" -- {*@{text B}[@{text y} := @{text x}]*}
|
|
196 |
thus "(x,z) \<in> r*" .
|
|
197 |
next
|
|
198 |
fix x' x y
|
|
199 |
assume 1: "(x',x) \<in> r" and
|
|
200 |
IH: "(y,z) \<in> r* \<Longrightarrow> (x,z) \<in> r*" and
|
|
201 |
B: "(y,z) \<in> r*"
|
|
202 |
from 1 IH[OF B] show "(x',z) \<in> r*" by(rule rtc.step)
|
|
203 |
qed
|
|
204 |
qed
|
|
205 |
text{*\noindent We start the proof with \isakeyword{from}~@{text"A
|
|
206 |
B"}. Only @{text A} is ``consumed'' by the induction step.
|
|
207 |
Since @{text B} is left over we don't just prove @{text
|
|
208 |
?thesis} but @{text"B \<Longrightarrow> ?thesis"}, just as in the previous proof. The
|
|
209 |
base case is trivial. In the assumptions for the induction step we can
|
|
210 |
see very clearly how things fit together and permit ourselves the
|
|
211 |
obvious forward step @{text"IH[OF B]"}. *}
|
|
212 |
|
|
213 |
subsection{*More induction*}
|
|
214 |
|
|
215 |
text{* We close the section by demonstrating how arbitrary induction rules
|
|
216 |
are applied. As a simple example we have chosen recursion induction, i.e.\
|
|
217 |
induction based on a recursive function definition. The example is an unusual
|
|
218 |
definition of rotation: *}
|
|
219 |
|
|
220 |
consts rot :: "'a list \<Rightarrow> 'a list"
|
|
221 |
recdef rot "measure length"
|
|
222 |
"rot [] = []"
|
|
223 |
"rot [x] = [x]"
|
|
224 |
"rot (x#y#zs) = y # rot(x#zs)"
|
|
225 |
|
|
226 |
text{* In the first proof we set up each case explicitly, merely using
|
|
227 |
pattern matching to abbreviate the statement: *}
|
|
228 |
|
|
229 |
lemma "length(rot xs) = length xs" (is "?P xs")
|
|
230 |
proof (induct xs rule: rot.induct)
|
|
231 |
show "?P []" by simp
|
|
232 |
next
|
|
233 |
fix x show "?P [x]" by simp
|
|
234 |
next
|
|
235 |
fix x y zs assume "?P (x#zs)"
|
|
236 |
thus "?P (x#y#zs)" by simp
|
|
237 |
qed
|
|
238 |
text{*\noindent
|
|
239 |
This proof skeleton works for arbitrary induction rules, not just
|
|
240 |
@{thm[source]rot.induct}.
|
|
241 |
|
|
242 |
In the following proof we rely on a default naming scheme for cases: they are
|
|
243 |
called 1, 2, etc, unless they have been named explicitly. The latter happens
|
|
244 |
only with datatypes and inductively defined sets, but not with recursive
|
|
245 |
functions. *}
|
|
246 |
|
|
247 |
lemma "xs \<noteq> [] \<Longrightarrow> rot xs = tl xs @ [hd xs]"
|
|
248 |
proof (induct xs rule: rot.induct)
|
|
249 |
case 1 thus ?case by simp
|
|
250 |
next
|
|
251 |
case 2 show ?case by simp
|
|
252 |
next
|
|
253 |
case 3 thus ?case by simp
|
|
254 |
qed
|
|
255 |
|
|
256 |
text{*\noindent Why can case 2 get away with \isakeyword{show} instead of
|
|
257 |
\isakeyword{thus}?
|
|
258 |
|
|
259 |
Of course both proofs are so simple that they can be condensed to*}
|
|
260 |
(*<*)lemma "xs \<noteq> [] \<Longrightarrow> rot xs = tl xs @ [hd xs]"(*>*)
|
|
261 |
by (induct xs rule: rot.induct, simp_all)
|
|
262 |
(*<*)end(*>*)
|