Theory Common_Patterns
section ‹Common patterns of induction›
theory Common_Patterns
imports Main
begin
text ‹
The subsequent Isar proof schemes illustrate common proof patterns
supported by the generic ‹induct› method.
To demonstrate variations on statement (goal) structure we refer to
the induction rule of Peano natural numbers: @{thm nat.induct
[no_vars]}, which is the simplest case of datatype induction. We
shall also see more complex (mutual) datatype inductions involving
several rules. Working with inductive predicates is similar, but
involves explicit facts about membership, instead of implicit
syntactic typing.
›
subsection ‹Variations on statement structure›
subsubsection ‹Local facts and parameters›
text ‹
Augmenting a problem by additional facts and locally fixed variables
is a bread-and-butter method in many applications. This is where
unwieldy object-level ‹∀› and ‹⟶› used to occur in
the past. The ‹induct› method works with primary means of
the proof language instead.
›
lemma
fixes n :: nat
and x :: 'a
assumes "A n x"
shows "P n x" using ‹A n x›
proof (induct n arbitrary: x)
case 0
note prem = ‹A 0 x›
show "P 0 x" \<proof>
next
case (Suc n)
note hyp = ‹⋀x. A n x ⟹ P n x›
and prem = ‹A (Suc n) x›
show "P (Suc n) x" \<proof>
qed
subsubsection ‹Local definitions›
text ‹
Here the idea is to turn sub-expressions of the problem into a
defined induction variable. This is often accompanied with fixing
of auxiliary parameters in the original expression, otherwise the
induction step would refer invariably to particular entities. This
combination essentially expresses a partially abstracted
representation of inductive expressions.
›
lemma
fixes a :: "'a ⇒ nat"
assumes "A (a x)"
shows "P (a x)" using ‹A (a x)›
proof (induct n ≡ "a x" arbitrary: x)
case 0
note prem = ‹A (a x)›
and defn = ‹0 = a x›
show "P (a x)" \<proof>
next
case (Suc n)
note hyp = ‹⋀x. n = a x ⟹ A (a x) ⟹ P (a x)›
and prem = ‹A (a x)›
and defn = ‹Suc n = a x›
show "P (a x)" \<proof>
qed
text ‹
Observe how the local definition ‹n = a x› recurs in the
inductive cases as ‹0 = a x› and ‹Suc n = a x›,
according to underlying induction rule.
›
subsubsection ‹Simple simultaneous goals›
text ‹
The most basic simultaneous induction operates on several goals
one-by-one, where each case refers to induction hypotheses that are
duplicated according to the number of conclusions.
›
lemma
fixes n :: nat
shows "P n" and "Q n"
proof (induct n)
case 0 case 1
show "P 0" \<proof>
next
case 0 case 2
show "Q 0" \<proof>
next
case (Suc n) case 1
note hyps = ‹P n› ‹Q n›
show "P (Suc n)" \<proof>
next
case (Suc n) case 2
note hyps = ‹P n› ‹Q n›
show "Q (Suc n)" \<proof>
qed
text ‹
The split into subcases may be deferred as follows -- this is
particularly relevant for goal statements with local premises.
›
lemma
fixes n :: nat
shows "A n ⟹ P n"
and "B n ⟹ Q n"
proof (induct n)
case 0
{
case 1
note ‹A 0›
show "P 0" \<proof>
next
case 2
note ‹B 0›
show "Q 0" \<proof>
}
next
case (Suc n)
note ‹A n ⟹ P n›
and ‹B n ⟹ Q n›
{
case 1
note ‹A (Suc n)›
show "P (Suc n)" \<proof>
next
case 2
note ‹B (Suc n)›
show "Q (Suc n)" \<proof>
}
qed
subsubsection ‹Compound simultaneous goals›
text ‹
The following pattern illustrates the slightly more complex
situation of simultaneous goals with individual local assumptions.
In compound simultaneous statements like this, local assumptions
need to be included into each goal, using ‹⟹› of the Pure
framework. In contrast, local parameters do not require separate
‹⋀› prefixes here, but may be moved into the common context
of the whole statement.
›
lemma
fixes n :: nat
and x :: 'a
and y :: 'b
shows "A n x ⟹ P n x"
and "B n y ⟹ Q n y"
proof (induct n arbitrary: x y)
case 0
{
case 1
note prem = ‹A 0 x›
show "P 0 x" \<proof>
}
{
case 2
note prem = ‹B 0 y›
show "Q 0 y" \<proof>
}
next
case (Suc n)
note hyps = ‹⋀x. A n x ⟹ P n x› ‹⋀y. B n y ⟹ Q n y›
then have some_intermediate_result \<proof>
{
case 1
note prem = ‹A (Suc n) x›
show "P (Suc n) x" \<proof>
}
{
case 2
note prem = ‹B (Suc n) y›
show "Q (Suc n) y" \<proof>
}
qed
text ‹
Here ‹induct› provides again nested cases with numbered
sub-cases, which allows to share common parts of the body context.
In typical applications, there could be a long intermediate proof of
general consequences of the induction hypotheses, before finishing
each conclusion separately.
›
subsection ‹Multiple rules›
text ‹
Multiple induction rules emerge from mutual definitions of
datatypes, inductive predicates, functions etc. The ‹induct› method accepts replicated arguments (with ‹and›
separator), corresponding to each projection of the induction
principle.
The goal statement essentially follows the same arrangement,
although it might be subdivided into simultaneous sub-problems as
before!
›