diff -r 0a1005435e11 -r 359b179fc963 doc-src/IsarOverview/Isar/Induction.thy --- a/doc-src/IsarOverview/Isar/Induction.thy Sun Nov 11 17:18:38 2007 +0100 +++ b/doc-src/IsarOverview/Isar/Induction.thy Sun Nov 11 19:41:26 2007 +0100 @@ -1,4 +1,8 @@ -(*<*)theory Induction imports Main begin(*>*) +(*<*)theory Induction imports Main begin +fun itrev where +"itrev [] ys = ys" | +"itrev (x#xs) ys = itrev xs (x#ys)" +(*>*) section{*Case distinction and induction \label{sec:Induct}*} @@ -72,11 +76,11 @@ In each \isakeyword{case} the assumption can be referred to inside the proof by the name of the constructor. In Section~\ref{sec:full-Ind} below we will come across an example -of this. *} +of this. -subsection{*Structural induction*} +\subsection{Structural induction} -text{* We start with an inductive proof where both cases are proved automatically: *} +We start with an inductive proof where both cases are proved automatically: *} lemma "2 * (\i::nat\n. i) = n*(n+1)" by (induct n, simp_all) @@ -121,63 +125,100 @@ text{* \noindent Of course we could again have written \isakeyword{thus}~@{text ?case} instead of giving the term explicitly -but we wanted to use @{term i} somewhere. *} +but we wanted to use @{term i} somewhere. + +\subsection{Generalization via @{text arbitrary}} + +It is frequently necessary to generalize a claim before it becomes +provable by induction. The tutorial~\cite{LNCS2283} demonstrates this +with @{prop"itrev xs ys = rev xs @ ys"}, where @{text ys} +needs to be universally quantified before induction succeeds.\footnote{@{thm rev.simps(1)},\quad @{thm rev.simps(2)[no_vars]},\\ @{thm itrev.simps(1)[no_vars]},\quad @{thm itrev.simps(2)[no_vars]}} But +strictly speaking, this quantification step is already part of the +proof and the quantifiers should not clutter the original claim. This +is how the quantification step can be combined with induction: *} +lemma "itrev xs ys = rev xs @ ys" +by (induct xs arbitrary: ys) auto +text{*\noindent The annotation @{text"arbitrary:"}~\emph{vars} +universally quantifies all \emph{vars} before the induction. Hence +they can be replaced by \emph{arbitrary} values in the proof. +This proof also demonstrates that \isakeyword{by} can take two arguments, +one to start and one to finish the proof --- the latter is optional. -subsection{*Induction formulae involving @{text"\"} or @{text"\"}\label{sec:full-Ind}*} +The nice thing about generalization via @{text"arbitrary:"} is that in +the induction step the claim is available in unquantified form but +with the generalized variables replaced by @{text"?"}-variables, ready +for instantiation. In the above example the +induction hypothesis is @{text"itrev xs ?ys = rev xs @ ?ys"}. + +For the curious: @{text"arbitrary:"} introduces @{text"\"} +behind the scenes. + +\subsection{Inductive proofs of conditional formulae} + +Induction also copes well with formulae involving @{text"\"}, for example +*} + +lemma "xs \ [] \ hd(rev xs) = last xs" +by (induct xs) auto + +text{*\noindent This is an improvement over that style the +tutorial~\cite{LNCS2283} advises, which requires @{text"\"}. +A further improvement is shown in the following proof: +*} -text{* Let us now consider the situation where the goal to be proved contains -@{text"\"} or @{text"\"}, say @{prop"\x. P x \ Q x"} --- motivation and a -real example follow shortly. This means that in each case of the induction, +lemma "map f xs = map f ys \ length xs = length ys" +proof (induct ys arbitrary: xs) + case Nil thus ?case by simp +next + case (Cons y ys) note Asm = Cons + show ?case + proof (cases xs) + case Nil + hence False using Asm(2) by simp + thus ?thesis .. + next + case (Cons x xs') + with Asm(2) have "map f xs' = map f ys" by auto + from Asm(1)[OF this] `xs = x#xs'` show ?thesis by simp + qed +qed + +text{*\noindent +The base case is trivial. In the step case Isar assumes +(under the name @{text Cons}) two propositions: +\begin{center} +\begin{tabular}{l} +@{text"map f ?xs = map f ys \ length ?xs = length ys"}\\ +@{prop"map f xs = map f (y # ys)"} +\end{tabular} +\end{center} +The first is the induction hypothesis, the second, and this is new, +is the premise of the induction step. The actual goal at this point is merely +@{prop"length xs = length (y#ys)"}. The assumptions are given the new name +@{text Asm} to avoid a name clash further down. The proof procedes with a case distinction on @{text xs}. In the case @{prop"xs = []"}, the second of our two +assumptions (@{text"Asm(2)"}) implies the contradiction @{text"0 = Suc(\)"}. + In the case @{prop"xs = x#xs'"}, we first obtain +@{prop"map f xs' = map f ys"}, from which a forward step with the first assumption (@{text"Asm(1)[OF this]"}) yields @{prop"length xs' = length ys"}. Together +with @{prop"xs = x#xs"} this yields the goal +@{prop"length xs = length (y#ys)"}. + + +\subsection{Induction formulae involving @{text"\"} or @{text"\"}} +\label{sec:full-Ind} + +Let us now consider abstractly the situation where the goal to be proved +contains both @{text"\"} and @{text"\"}, say @{prop"\x. P x \ Q x"}. +This means that in each case of the induction, @{text ?case} would be of the form @{prop"\x. P' x \ Q' x"}. Thus the first proof steps will be the canonical ones, fixing @{text x} and assuming -@{prop"P' x"}. To avoid this tedium, induction performs these steps -automatically: for example in case @{text"(Suc n)"}, @{text ?case} is only -@{prop"Q' x"} whereas the assumptions (named @{term Suc}!) contain both the -usual induction hypothesis \emph{and} @{prop"P' x"}. -It should be clear how this generalises to more complex formulae. - -As an example we will now prove complete induction via -structural induction. *} +@{prop"P' x"}. To avoid this tedium, induction performs the canonical steps +automatically: in each step case, the assumptions contain both the +usual induction hypothesis and @{prop"P' x"}, whereas @{text ?case} is only +@{prop"Q' x"}. -lemma assumes A: "(\n. (\m. m < n \ P m) \ P n)" - shows "P(n::nat)" -proof (rule A) - show "\m. m < n \ P m" - proof (induct n) - case 0 thus ?case by simp - next - case (Suc n) -- {*\isakeyword{fix} @{term m} \isakeyword{assume} @{text Suc}: @{text[source]"?m < n \ P ?m"} @{prop[source]"m < Suc n"}*} - show ?case -- {*@{term ?case}*} - proof cases - assume eq: "m = n" - from Suc and A have "P n" by blast - with eq show "P m" by simp - next - assume "m \ n" - with Suc have "m < n" by arith - thus "P m" by(rule Suc) - qed - qed -qed -text{* \noindent Given the explanations above and the comments in the -proof text (only necessary for novices), the proof should be quite -readable. +\subsection{Rule induction} -The statement of the lemma is interesting because it deviates from the style in -the Tutorial~\cite{LNCS2283}, which suggests to introduce @{text"\"} or -@{text"\"} into a theorem to strengthen it for induction. In Isar -proofs we can use @{text"\"} and @{text"\"} instead. This simplifies the -proof and means we do not have to convert between the two kinds of -connectives. - -Note that in a nested induction over the same data type, the inner -case labels hide the outer ones of the same name. If you want to refer -to the outer ones inside, you need to name them on the outside, e.g.\ -\isakeyword{note}~@{text"outer_IH = Suc"}. *} - -subsection{*Rule induction*} - -text{* HOL also supports inductively defined sets. See \cite{LNCS2283} +HOL also supports inductively defined sets. See \cite{LNCS2283} for details. As an example we define our own version of the reflexive transitive closure of a relation --- HOL provides a predefined one as well.*} inductive_set @@ -209,42 +250,41 @@ However, this proof is rather terse. Here is a more readable version: *} -lemma assumes A: "(x,y) \ r*" and B: "(y,z) \ r*" - shows "(x,z) \ r*" -proof - - from A B show ?thesis - proof induct - fix x assume "(x,z) \ r*" -- {*@{text B}[@{text y} := @{text x}]*} - thus "(x,z) \ r*" . - next - fix x' x y - assume 1: "(x',x) \ r" and - IH: "(y,z) \ r* \ (x,z) \ r*" and - B: "(y,z) \ r*" - from 1 IH[OF B] show "(x',z) \ r*" by(rule rtc.step) - qed +lemma assumes "(x,y) \ r*" and "(y,z) \ r*" shows "(x,z) \ r*" +using assms +proof induct + fix x assume "(x,z) \ r*" -- {*@{text B}[@{text y} := @{text x}]*} + thus "(x,z) \ r*" . +next + fix x' x y + assume 1: "(x',x) \ r" and + IH: "(y,z) \ r* \ (x,z) \ r*" and + B: "(y,z) \ r*" + from 1 IH[OF B] show "(x',z) \ r*" by(rule rtc.step) qed -text{*\noindent We start the proof with \isakeyword{from}~@{text"A -B"}. Only @{text A} is ``consumed'' by the induction step. -Since @{text B} is left over we don't just prove @{text -?thesis} but @{text"B \ ?thesis"}, just as in the previous proof. The -base case is trivial. In the assumptions for the induction step we can +text{*\noindent +This time, merely for a change, we start the proof with by feeding both +assumptions into the inductive proof. Only the first assumption is +``consumed'' by the induction. +Since the second one is left over we don't just prove @{text ?thesis} but +@{text"(y,z) \ r* \ ?thesis"}, just as in the previous proof. +The base case is trivial. In the assumptions for the induction step we can see very clearly how things fit together and permit ourselves the obvious forward step @{text"IH[OF B]"}. -The notation `\isakeyword{case}~\isa{(}\emph{constructor} \emph{vars}\isa{)}' -is also supported for inductive definitions. The \emph{constructor} is (the -name of) the rule and the \emph{vars} fix the free variables in the +The notation \isakeyword{case}~\isa{(}\emph{constructor} \emph{vars}\isa{)} +is also supported for inductive definitions. The \emph{constructor} is the +name of the rule and the \emph{vars} fix the free variables in the rule; the order of the \emph{vars} must correspond to the -\emph{alphabetical order} of the variables as they appear in the rule. +left-to-right order of the variables as they appear in the rule. For example, we could start the above detailed proof of the induction -with \isakeyword{case}~\isa{(step x' x y)}. However, we can then only -refer to the assumptions named \isa{step} collectively and not -individually, as the above proof requires. *} +with \isakeyword{case}~\isa{(step x' x y)}. In that case we don't need +to spell out the assumptions but can refer to them by @{text"step(.)"}, +although the resulting text will be quite cryptic. -subsection{*More induction*} +\subsection{More induction} -text{* We close the section by demonstrating how arbitrary induction +We close the section by demonstrating how arbitrary induction rules are applied. As a simple example we have chosen recursion induction, i.e.\ induction based on a recursive function definition. However, most of what we show works for induction in @@ -252,17 +292,16 @@ The example is an unusual definition of rotation: *} -consts rot :: "'a list \ 'a list" -recdef rot "measure length" --"for the internal termination proof" -"rot [] = []" -"rot [x] = [x]" +fun rot :: "'a list \ 'a list" where +"rot [] = []" | +"rot [x] = [x]" | "rot (x#y#zs) = y # rot(x#zs)" text{*\noindent This yields, among other things, the induction rule @{thm[source]rot.induct}: @{thm[display]rot.induct[no_vars]} -In the following proof we rely on a default naming scheme for cases: they are +The following proof relies on a default naming scheme for cases: they are called 1, 2, etc, unless they have been named explicitly. The latter happens -only with datatypes and inductively defined sets, but not with recursive -functions. *} +only with datatypes and inductively defined sets, but (usually) +not with recursive functions. *} lemma "xs \ [] \ rot xs = tl xs @ [hd xs]" proof (induct xs rule: rot.induct) @@ -280,11 +319,11 @@ text{*\noindent The third case is only shown in gory detail (see \cite{BauerW-TPHOLs01} for how to reason with chains of equations) to demonstrate that the -`\isakeyword{case}~\isa{(}\emph{constructor} \emph{vars}\isa{)}' notation also +\isakeyword{case}~\isa{(}\emph{constructor} \emph{vars}\isa{)} notation also works for arbitrary induction theorems with numbered cases. The order of the \emph{vars} corresponds to the order of the @{text"\"}-quantified variables in each case of the induction -theorem. For induction theorems produced by \isakeyword{recdef} it is +theorem. For induction theorems produced by \isakeyword{fun} it is the order in which the variables appear on the left-hand side of the equation. @@ -295,3 +334,25 @@ by (induct xs rule: rot.induct, simp_all) (*<*)end(*>*) +(* +lemma assumes A: "(\n. (\m. m < n \ P m) \ P n)" + shows "P(n::nat)" +proof (rule A) + show "\m. m < n \ P m" + proof (induct n) + case 0 thus ?case by simp + next + case (Suc n) -- {*\isakeyword{fix} @{term m} \isakeyword{assume} @{text Suc}: @{text[source]"?m < n \ P ?m"} @{prop[source]"m < Suc n"}*} + show ?case -- {*@{term ?case}*} + proof cases + assume eq: "m = n" + from Suc and A have "P n" by blast + with eq show "P m" by simp + next + assume "m \ n" + with Suc have "m < n" by arith + thus "P m" by(rule Suc) + qed + qed +qed +*) \ No newline at end of file