In this lecture, we build the natural numbers from scratch. We define:
Our goal is to prove the correctness of the iterative version of the Fibonacci function. This involves properties of addition, multiplication, and the less-than-or-equal-to relation. We also need to prove the strong induction principle. With these tools, we can prove the correctness of the iterative version of the Fibonacci function.
Definition of natural numbers using inductive data type
Inductive nat :=
| O : nat
| S : nat -> nat.
Define some natural numbers
Definition zero := O. Definition one := S O. Definition two := S (S O). Definition three := S (S (S O)).
Recursive definition of addition
Fixpoint add n m :=
match n with
| O => m
| S n' => S (add n' m)
end.
Compute 2 + 3
Coq can partially evaluate functions
It's not magic: it only applies reduction rules for function application and match on constructors
Check computes the type of a term
We prove simple lemmas about addition by partial evaluation
n: natadd O n = nn: natadd O n = nreflexivity. (* Prove equality by reflexivity *) Qed.n: natn = nn, m: natadd (S n) m = S (add n m)n, m: natadd (S n) m = S (add n m)reflexivity. Qed.n, m: natS (add n m) = S (add n m)
We prove that add is associative:
a, b, c: natadd (add a b) c = add a (add b c)a, b, c: natadd (add a b) c = add a (add b c)b, c: natadd (add O b) c = add O (add b c)a, b, c: nat
IHa: add (add a b) c = add a (add b c)add (add (S a) b) c = add (S a) (add b c)b, c: natadd (add O b) c = add O (add b c)reflexivity.b, c: natadd b c = add b ca, b, c: nat
IHa: add (add a b) c = add a (add b c)add (add (S a) b) c = add (S a) (add b c)a, b, c: nat
IHa: add (add a b) c = add a (add b c)S (add (add a b) c) = S (add a (add b c))reflexivity. Qed.a, b, c: nat
IHa: add (add a b) c = add a (add b c)S (add a (add b c)) = S (add a (add b c))
Proving that add is commutative is harder! Let's build up to it.
We first need to prove a lemma about adding O
on the right:
n: natadd n O = nn: natadd n O = nn: natadd n O = nadd O O = On: nat
IHn: add n O = nadd (S n) O = S nadd O O = Oreflexivity.O = On: nat
IHn: add n O = nadd (S n) O = S nn: nat
IHn: add n O = nS (add n O) = S nreflexivity. Qed.n: nat
IHn: add n O = nS n = S n
An inductive proof about S m
on the right:
n, m: natadd n (S m) = S (add n m)n, m: natadd n (S m) = S (add n m)m: natadd O (S m) = S (add O m)n, m: nat
IHn: add n (S m) = S (add n m)add (S n) (S m) = S (add (S n) m)m: natadd O (S m) = S (add O m)reflexivity.m: natS m = S mn, m: nat
IHn: add n (S m) = S (add n m)add (S n) (S m) = S (add (S n) m)n, m: nat
IHn: add n (S m) = S (add n m)S (add n (S m)) = S (S (add n m))reflexivity. Qed.n, m: nat
IHn: add n (S m) = S (add n m)S (S (add n m)) = S (S (add n m))
Let's define an alternative version of addition that matches on m instead of n:
Fixpoint add' n m :=
match m with
| O => n
| S m' => S (add' n m')
end.
We prove that the two definitions of addition are equivalent:
n, m: natadd n m = add' n mn, m: natadd n m = add' n mn: natadd n O = add' n On, m: nat
IHm: add n m = add' n madd n (S m) = add' n (S m)n: natadd n O = add' n O(* We could use rewrite & reflexivity here, *) (* but apply does it in one step *) apply add_n_0.n: natadd n O = nn, m: nat
IHm: add n m = add' n madd n (S m) = add' n (S m)n, m: nat
IHm: add n m = add' n madd n (S m) = S (add' n m)n, m: nat
IHm: add n m = add' n mS (add n m) = S (add' n m)reflexivity. Qed.n, m: nat
IHm: add n m = add' n mS (add' n m) = S (add' n m)
We can also prove commutativity of addition by induction:
n, m: natadd n m = add m nn, m: natadd n m = add m nm: natadd O m = add m On, m: nat
IHn: add n m = add m nadd (S n) m = add m (S n)m: natadd O m = add m Om: natm = add m Oreflexivity.m: natm = mn, m: nat
IHn: add n m = add m nadd (S n) m = add m (S n)n, m: nat
IHn: add n m = add m nS (add n m) = add m (S n)n, m: nat
IHn: add n m = add m nS (add n m) = S (add m n)reflexivity. Qed.n, m: nat
IHn: add n m = add m nS (add m n) = S (add m n)
We can prove that if the sum of two numbers is zero, then both numbers must be zero:
n, m: natadd n m = O -> n = O /\ m = On, m: natadd n m = O -> n = O /\ m = On, m: nat
H: add n m = On = O /\ m = Om: nat
H: add O m = OO = O /\ m = On, m: nat
H: add (S n) m = OS n = O /\ m = Om: nat
H: add O m = OO = O /\ m = Om: nat
H: add O m = OO = Om: nat
H: add O m = Om = Oreflexivity.m: nat
H: add O m = OO = Om: nat
H: add O m = Om = Oapply H.m: nat
H: m = Om = On, m: nat
H: add (S n) m = OS n = O /\ m = O(* Now H is a contradiction: S and O can't be equal *) (* Discriminate proves the goal by contradiction *) discriminate. Qed.n, m: nat
H: S (add n m) = OS n = O /\ m = O
The discriminate tactic is not necessary! We can prove the goal without using
discriminate
. To do that, we first define an alternative equality for natural
numbers:
Definition nat_eq n m :=
match n with
| O => m = O
| S n' =>
match m with
| O => False
| S m' => n' = m'
end
end.
We then prove that nat_eq
implies equality:
n, m: natnat_eq n m -> n = mn, m: natnat_eq n m -> n = mn, m: nat
H: nat_eq n mn = mm: nat
H: nat_eq O mO = mn, m: nat
H: nat_eq (S n) mS n = mm: nat
H: nat_eq O mO = mm: nat
H: m = OO = mreflexivity.m: nat
H: m = OO = On, m: nat
H: nat_eq (S n) mS n = mn, m: nat
H: match m with | O => False | S m' => n = m' endS n = mn: nat
H: FalseS n = On, m: nat
H: n = mS n = S mdestruct H.n: nat
H: FalseS n = On, m: nat
H: n = mS n = S mreflexivity. Qed.n, m: nat
H: n = mS m = S m
Now we can finally prove that S n
is not equal to O
, without using discriminate
:
n: natS n = O -> Falsen: natS n = O -> Falsen: nat
H: S n = OFalsen: nat
H: S n = Onat_eq (S n) On: nat
H: S n = O
H': nat_eq (S n) OFalsen: nat
H: S n = Onat_eq (S n) On: nat
H: S n = Onat_eq O Oconstructor.n: nat
H: S n = OO = On: nat
H: S n = O
H': nat_eq (S n) OFalseapply H'. Qed.n: nat
H: S n = O
H': FalseFalse
We can use the same definition of nat_eq
to prove injectivity of S
:
n, m: natS n = S m -> n = mn, m: natS n = S m -> n = mn, m: nat
H: S n = S mn = mn, m: nat
H: S n = S mnat_eq (S n) (S m)n, m: nat
H: S n = S m
H': nat_eq (S n) (S m)n = mn, m: nat
H: S n = S mnat_eq (S n) (S m)n, m: nat
H: S n = S mnat_eq (S m) (S m)constructor.n, m: nat
H: S n = S mm = mn, m: nat
H: S n = S m
H': nat_eq (S n) (S m)n = mapply H'. Qed.n, m: nat
H: S n = S m
H': n = mn = m
We can also use the injection tactic:
n, m: natS n = S m -> n = mn, m: natS n = S m -> n = mn, m: nat
H: S n = S mn = mapply H'. Qed.n, m: nat
H': n = mn = m
Using the injectivity of S
, we can prove that n
is not equal to its successor:
n: natS n = n -> Falsen: natS n = n -> FalseS O = O -> Falsen: nat
IHn: S n = n -> FalseS (S n) = S n -> Falseapply S_not_O.S O = O -> Falsen: nat
IHn: S n = n -> FalseS (S n) = S n -> Falsen: nat
IHn: S n = n -> False
H: S (S n) = S nFalsen: nat
IHn: S n = n -> False
H: S (S n) = S nS n = napply H. Qed.n: nat
IHn: S n = n -> False
H: S n = nS n = n
We define multiplication:
Fixpoint mul n m :=
match n with
| O => O
| S n' => add m (mul n' m)
end.
Coq allows us to use operator notation:
Infix "+" := add. Infix "*" := mul.
Some examples:
Some lemmas about multiplication:
n: natn * zero = zeron: natn * zero = zeroO * zero = zeron: nat
IHn: n * zero = zeroS n * zero = zeroO * zero = zeroreflexivity.O = zeron: nat
IHn: n * zero = zeroS n * zero = zeron: nat
IHn: n * zero = zeron * zero = zeroreflexivity. Qed.n: nat
IHn: n * zero = zerozero = zeron: natn * one = nn: natn * one = nO * one = On: nat
IHn: n * one = nS n * one = S nO * one = Oreflexivity.O = On: nat
IHn: n * one = nS n * one = S nn: nat
IHn: n * one = nS (n * one) = S nreflexivity. Qed.n: nat
IHn: n * one = nS n = S nn: natone * n = nn: natone * n = nn: natn + O = nreflexivity. Qed.n: natn = nn, m, k: nat(n + m) * k = n * k + m * kn, m, k: nat(n + m) * k = n * k + m * km, k: nat(O + m) * k = O * k + m * kn, m, k: nat
IHn: (n + m) * k = n * k + m * k(S n + m) * k = S n * k + m * km, k: nat(O + m) * k = O * k + m * kreflexivity.m, k: natm * k = m * kn, m, k: nat
IHn: (n + m) * k = n * k + m * k(S n + m) * k = S n * k + m * kn, m, k: nat
IHn: (n + m) * k = n * k + m * kk + (n + m) * k = k + n * k + m * kn, m, k: nat
IHn: (n + m) * k = n * k + m * kk + (n * k + m * k) = k + n * k + m * kreflexivity. Qed.n, m, k: nat
IHn: (n + m) * k = n * k + m * kk + (n * k + m * k) = k + (n * k + m * k)n, m, k: natn * (m + k) = n * m + n * kn, m, k: natn * (m + k) = n * m + n * km, k: natO * (m + k) = O * m + O * kn, m, k: nat
IHn: n * (m + k) = n * m + n * kS n * (m + k) = S n * m + S n * km, k: natO * (m + k) = O * m + O * kreflexivity.m, k: natO = On, m, k: nat
IHn: n * (m + k) = n * m + n * kS n * (m + k) = S n * m + S n * kn, m, k: nat
IHn: n * (m + k) = n * m + n * km + k + n * (m + k) = m + n * m + (k + n * k)n, m, k: nat
IHn: n * (m + k) = n * m + n * km + k + (n * m + n * k) = m + n * m + (k + n * k)n, m, k: nat
IHn: n * (m + k) = n * m + n * km + k + n * m + n * k = m + n * m + k + n * kn, m, k: nat
IHn: n * (m + k) = n * m + n * km + k + n * m = m + n * m + kn, m, k: nat
IHn: n * (m + k) = n * m + n * km + (k + n * m) = m + (n * m + k)apply add_comm. Qed.n, m, k: nat
IHn: n * (m + k) = n * m + n * kk + n * m = n * m + k
We define le x y
as a function, and define the notation x <= y
to be le x y
.
Fixpoint le n m := match n with | O => True | S n' => match m with | O => False | S m' => le n' m' end end. Notation "n <= m" := (le n m).n: natn <= nn: natn <= nO <= On: nat
IHn: n <= nS n <= S nO <= Oconstructor.Truen: nat
IHn: n <= nS n <= S napply IHn. Qed.n: nat
IHn: n <= nn <= nn, m, k: natn <= m -> m <= k -> n <= kn, m, k: natn <= m -> m <= k -> n <= kn: natforall m k : nat, n <= m -> m <= k -> n <= kforall m k : nat, O <= m -> m <= k -> O <= kn: nat
IHn: forall m k : nat, n <= m -> m <= k -> n <= kforall m k : nat, S n <= m -> m <= k -> S n <= kforall m k : nat, O <= m -> m <= k -> O <= km, k: nat
Hnm: O <= m
Hmk: m <= kO <= kconstructor.m, k: nat
Hnm: O <= m
Hmk: m <= kTruen: nat
IHn: forall m k : nat, n <= m -> m <= k -> n <= kforall m k : nat, S n <= m -> m <= k -> S n <= kn: nat
IHn: forall m k : nat, n <= m -> m <= k -> n <= k
m, k: nat
Hnm: S n <= m
Hmk: m <= kS n <= kn: nat
IHn: forall m k : nat, n <= m -> m <= k -> n <= k
m, k: nat
Hnm: match m with | O => False | S m' => n <= m' end
Hmk: m <= kmatch k with | O => False | S m' => n <= m' endn: nat
IHn: forall m k : nat, n <= m -> m <= k -> n <= k
k: nat
Hnm: False
Hmk: O <= kmatch k with | O => False | S m' => n <= m' endn: nat
IHn: forall m k : nat, n <= m -> m <= k -> n <= k
m, k: nat
Hnm: n <= m
Hmk: S m <= kmatch k with | O => False | S m' => n <= m' enddestruct Hnm.n: nat
IHn: forall m k : nat, n <= m -> m <= k -> n <= k
k: nat
Hnm: False
Hmk: O <= kmatch k with | O => False | S m' => n <= m' endn: nat
IHn: forall m k : nat, n <= m -> m <= k -> n <= k
m, k: nat
Hnm: n <= m
Hmk: S m <= kmatch k with | O => False | S m' => n <= m' endn: nat
IHn: forall m k : nat, n <= m -> m <= k -> n <= k
m: nat
Hnm: n <= m
Hmk: S m <= OFalsen: nat
IHn: forall m k : nat, n <= m -> m <= k -> n <= k
m, k: nat
Hnm: n <= m
Hmk: S m <= S kn <= kdestruct Hmk.n: nat
IHn: forall m k : nat, n <= m -> m <= k -> n <= k
m: nat
Hnm: n <= m
Hmk: S m <= OFalsen: nat
IHn: forall m k : nat, n <= m -> m <= k -> n <= k
m, k: nat
Hnm: n <= m
Hmk: S m <= S kn <= kn: nat
IHn: forall m k : nat, n <= m -> m <= k -> n <= k
m, k: nat
Hnm: n <= m
Hmk: m <= kn <= kn: nat
IHn: forall m k : nat, n <= m -> m <= k -> n <= k
m, k: nat
Hnm: n <= m
Hmk: m <= kn <= mn: nat
IHn: forall m k : nat, n <= m -> m <= k -> n <= k
m, k: nat
Hnm: n <= m
Hmk: m <= km <= kapply Hnm.n: nat
IHn: forall m k : nat, n <= m -> m <= k -> n <= k
m, k: nat
Hnm: n <= m
Hmk: m <= kn <= mapply Hmk. Qed.n: nat
IHn: forall m k : nat, n <= m -> m <= k -> n <= k
m, k: nat
Hnm: n <= m
Hmk: m <= km <= k
Define strict inequality:
Definition lt n m := S n <= m. (* n < m iff n+1 <= m, for nat *) Notation "n < m" := (lt n m).
n: nat
P: nat -> Prop(forall n : nat, (forall m : nat, m < n -> P m) -> P n) -> P nn: nat
P: nat -> Prop(forall n : nat, (forall m : nat, m < n -> P m) -> P n) -> P nn: nat
P: nat -> Prop
H: forall n : nat, (forall m : nat, m < n -> P m) -> P nP nn: nat
P: nat -> Prop
H: forall n : nat, (forall m : nat, m < n -> P m) -> P nforall m : nat, m < n -> P mP: nat -> Prop
H: forall n : nat, (forall m : nat, m < n -> P m) -> P nforall m : nat, m < O -> P mn: nat
P: nat -> Prop
H: forall n : nat, (forall m : nat, m < n -> P m) -> P n
IHn: forall m : nat, m < n -> P mforall m : nat, m < S n -> P mP: nat -> Prop
H: forall n : nat, (forall m : nat, m < n -> P m) -> P nforall m : nat, m < O -> P mP: nat -> Prop
H: forall n : nat, (forall m : nat, m < n -> P m) -> P n
m: nat
Hm: m < OP mP: nat -> Prop
H: forall n : nat, (forall m : nat, m < n -> P m) -> P n
m: nat
Hm: S m <= OP mdestruct Hm.P: nat -> Prop
H: forall n : nat, (forall m : nat, m < n -> P m) -> P n
m: nat
Hm: FalseP mn: nat
P: nat -> Prop
H: forall n : nat, (forall m : nat, m < n -> P m) -> P n
IHn: forall m : nat, m < n -> P mforall m : nat, m < S n -> P mn: nat
P: nat -> Prop
H: forall n : nat, (forall m : nat, m < n -> P m) -> P n
IHn: forall m : nat, m < n -> P m
m: nat
Hm: m < S nP mn: nat
P: nat -> Prop
H: forall n : nat, (forall m : nat, m < n -> P m) -> P n
IHn: forall m : nat, m < n -> P m
m: nat
Hm: S m <= S nP mn: nat
P: nat -> Prop
H: forall n : nat, (forall m : nat, m < n -> P m) -> P n
IHn: forall m : nat, m < n -> P m
m: nat
Hm: m <= nP mn: nat
P: nat -> Prop
H: forall n : nat, (forall m : nat, m < n -> P m) -> P n
IHn: forall m : nat, m < n -> P m
m: nat
Hm: m <= nforall m0 : nat, m0 < m -> P m0n: nat
P: nat -> Prop
H: forall n : nat, (forall m : nat, m < n -> P m) -> P n
IHn: forall m : nat, m < n -> P m
m: nat
Hm: m <= n
k: nat
Hk: k < mP kn: nat
P: nat -> Prop
H: forall n : nat, (forall m : nat, m < n -> P m) -> P n
IHn: forall m : nat, m < n -> P m
m: nat
Hm: m <= n
k: nat
Hk: k < mk < nn: nat
P: nat -> Prop
H: forall n : nat, (forall m : nat, m < n -> P m) -> P n
IHn: forall m : nat, m < n -> P m
m: nat
Hm: m <= n
k: nat
Hk: k < mS k <= mn: nat
P: nat -> Prop
H: forall n : nat, (forall m : nat, m < n -> P m) -> P n
IHn: forall m : nat, m < n -> P m
m: nat
Hm: m <= n
k: nat
Hk: k < mm <= napply Hk.n: nat
P: nat -> Prop
H: forall n : nat, (forall m : nat, m < n -> P m) -> P n
IHn: forall m : nat, m < n -> P m
m: nat
Hm: m <= n
k: nat
Hk: k < mS k <= mapply Hm. Qed.n: nat
P: nat -> Prop
H: forall n : nat, (forall m : nat, m < n -> P m) -> P n
IHn: forall m : nat, m < n -> P m
m: nat
Hm: m <= n
k: nat
Hk: k < mm <= n
Let's define the Fibonacci function:
Fixpoint fib n := match n with | O => O | S n' => match n' with | O => S O | S n'' => fib n' + fib n'' end end.
An iterative version of Fibonacci:
Fixpoint fib_iter n a b := match n with | O => a | S m => fib_iter m b (a + b) end. Definition fib' n := fib_iter n zero one.
Exercise: Correctness of iterative Fibonacci
n: natfib' n = fib nAdmitted.n: natfib' n = fib n
Try it yourself before looking at the solution below!
n, a, a', b, b': natfib_iter n (a + a') (b + b') = fib_iter n a b + fib_iter n a' b'n, a, a', b, b': natfib_iter n (a + a') (b + b') = fib_iter n a b + fib_iter n a' b'n: natforall a a' b b' : nat, fib_iter n (a + a') (b + b') = fib_iter n a b + fib_iter n a' b'forall a a' b b' : nat, fib_iter O (a + a') (b + b') = fib_iter O a b + fib_iter O a' b'n: nat
IHn: forall a a' b b' : nat, fib_iter n (a + a') (b + b') = fib_iter n a b + fib_iter n a' b'forall a a' b b' : nat, fib_iter (S n) (a + a') (b + b') = fib_iter (S n) a b + fib_iter (S n) a' b'forall a a' b b' : nat, fib_iter O (a + a') (b + b') = fib_iter O a b + fib_iter O a' b'reflexivity.forall a a' : nat, nat -> nat -> a + a' = a + a'n: nat
IHn: forall a a' b b' : nat, fib_iter n (a + a') (b + b') = fib_iter n a b + fib_iter n a' b'forall a a' b b' : nat, fib_iter (S n) (a + a') (b + b') = fib_iter (S n) a b + fib_iter (S n) a' b'n: nat
IHn: forall a a' b b' : nat, fib_iter n (a + a') (b + b') = fib_iter n a b + fib_iter n a' b'
a, a', b, b': natfib_iter (S n) (a + a') (b + b') = fib_iter (S n) a b + fib_iter (S n) a' b'n: nat
IHn: forall a a' b b' : nat, fib_iter n (a + a') (b + b') = fib_iter n a b + fib_iter n a' b'
a, a', b, b': natfib_iter n (b + b') (a + a' + (b + b')) = fib_iter n b (a + b) + fib_iter n b' (a' + b')n: nat
IHn: forall a a' b b' : nat, fib_iter n (a + a') (b + b') = fib_iter n a b + fib_iter n a' b'
a, a', b, b': natfib_iter n (b + b') (a + a' + (b + b')) = fib_iter n (b + b') (a + b + (a' + b'))n: nat
IHn: forall a a' b b' : nat, fib_iter n (a + a') (b + b') = fib_iter n a b + fib_iter n a' b'
a, a', b, b': nata + a' + (b + b') = a + b + (a' + b')n: nat
IHn: forall a a' b b' : nat, fib_iter n (a + a') (b + b') = fib_iter n a b + fib_iter n a' b'
a, a', b, b': nata + a' + (b + b') = a + (a' + b) + b'n: nat
IHn: forall a a' b b' : nat, fib_iter n (a + a') (b + b') = fib_iter n a b + fib_iter n a' b'
a, a', b, b': nata + (a' + b) + b' = a + b + (a' + b')n: nat
IHn: forall a a' b b' : nat, fib_iter n (a + a') (b + b') = fib_iter n a b + fib_iter n a' b'
a, a', b, b': nata + a' + (b + b') = a + (a' + b) + b'reflexivity.n: nat
IHn: forall a a' b b' : nat, fib_iter n (a + a') (b + b') = fib_iter n a b + fib_iter n a' b'
a, a', b, b': nata + (a' + (b + b')) = a + (a' + (b + b'))n: nat
IHn: forall a a' b b' : nat, fib_iter n (a + a') (b + b') = fib_iter n a b + fib_iter n a' b'
a, a', b, b': nata + (a' + b) + b' = a + b + (a' + b')n: nat
IHn: forall a a' b b' : nat, fib_iter n (a + a') (b + b') = fib_iter n a b + fib_iter n a' b'
a, a', b, b': nata + b + (a' + b') = a + (b + a') + b'n: nat
IHn: forall a a' b b' : nat, fib_iter n (a + a') (b + b') = fib_iter n a b + fib_iter n a' b'
a, a', b, b': nata + (a' + b) + b' = a + (b + a') + b'n: nat
IHn: forall a a' b b' : nat, fib_iter n (a + a') (b + b') = fib_iter n a b + fib_iter n a' b'
a, a', b, b': nata + b + (a' + b') = a + (b + a') + b'reflexivity.n: nat
IHn: forall a a' b b' : nat, fib_iter n (a + a') (b + b') = fib_iter n a b + fib_iter n a' b'
a, a', b, b': nata + (b + (a' + b')) = a + (b + (a' + b'))n: nat
IHn: forall a a' b b' : nat, fib_iter n (a + a') (b + b') = fib_iter n a b + fib_iter n a' b'
a, a', b, b': nata + (a' + b) + b' = a + (b + a') + b'n: nat
IHn: forall a a' b b' : nat, fib_iter n (a + a') (b + b') = fib_iter n a b + fib_iter n a' b'
a, a', b, b': nata + (a' + b) = a + (b + a')apply add_comm. Qed. Fixpoint fib_rec n a b := match n with | O => a | S m => match m with | O => b | S k => fib_rec m a b + fib_rec k a b end end.n: nat
IHn: forall a a' b b' : nat, fib_iter n (a + a') (b + b') = fib_iter n a b + fib_iter n a' b'
a, a', b, b': nata' + b = b + a'n: natn <= S nn: natn <= S nO <= S On: nat
IHn: n <= S nS n <= S (S n)O <= S Oconstructor.Truen: nat
IHn: n <= S nS n <= S (S n)apply IHn. Qed.n: nat
IHn: n <= S nn <= S nn, a, b: natfib_iter n a b = fib_rec n a bn, a, b: natfib_iter n a b = fib_rec n a bn: natforall a b : nat, fib_iter n a b = fib_rec n a bn: nat
IH: forall m : nat, m < n -> forall a b : nat, fib_iter m a b = fib_rec m a bforall a b : nat, fib_iter n a b = fib_rec n a bn: nat
IH: forall m : nat, m < n -> forall a b : nat, fib_iter m a b = fib_rec m a b
a, b: natfib_iter n a b = fib_rec n a bIH: forall m : nat, m < O -> forall a b : nat, fib_iter m a b = fib_rec m a b
a, b: natfib_iter O a b = fib_rec O a bn: nat
IH: forall m : nat, m < S n -> forall a b : nat, fib_iter m a b = fib_rec m a b
a, b: natfib_iter (S n) a b = fib_rec (S n) a breflexivity.IH: forall m : nat, m < O -> forall a b : nat, fib_iter m a b = fib_rec m a b
a, b: natfib_iter O a b = fib_rec O a bn: nat
IH: forall m : nat, m < S n -> forall a b : nat, fib_iter m a b = fib_rec m a b
a, b: natfib_iter (S n) a b = fib_rec (S n) a bn: nat
IH: forall m : nat, m < S n -> forall a b : nat, fib_iter m a b = fib_rec m a b
a, b: natfib_iter n b (a + b) = match n with | O => b | S k => fib_rec n a b + fib_rec k a b endIH: forall m : nat, m < S O -> forall a b : nat, fib_iter m a b = fib_rec m a b
a, b: natfib_iter O b (a + b) = bn: nat
IH: forall m : nat, m < S (S n) -> forall a b : nat, fib_iter m a b = fib_rec m a b
a, b: natfib_iter (S n) b (a + b) = fib_rec (S n) a b + fib_rec n a bIH: forall m : nat, m < S O -> forall a b : nat, fib_iter m a b = fib_rec m a b
a, b: natfib_iter O b (a + b) = breflexivity.IH: forall m : nat, m < S O -> forall a b : nat, fib_iter m a b = fib_rec m a b
a, b: natb = bn: nat
IH: forall m : nat, m < S (S n) -> forall a b : nat, fib_iter m a b = fib_rec m a b
a, b: natfib_iter (S n) b (a + b) = fib_rec (S n) a b + fib_rec n a bn: nat
IH: forall m : nat, m < S (S n) -> forall a b : nat, fib_iter m a b = fib_rec m a b
a, b: natfib_iter (S n) b (a + b) = fib_iter (S n) a b + fib_iter n a bn: nat
IH: forall m : nat, m < S (S n) -> forall a b : nat, fib_iter m a b = fib_rec m a b
a, b: natn < S (S n)n: nat
IH: forall m : nat, m < S (S n) -> forall a b : nat, fib_iter m a b = fib_rec m a b
a, b: natS n < S (S n)n: nat
IH: forall m : nat, m < S (S n) -> forall a b : nat, fib_iter m a b = fib_rec m a b
a, b: natfib_iter (S n) b (a + b) = fib_iter (S n) a b + fib_iter n a bn: nat
IH: forall m : nat, m < S (S n) -> forall a b : nat, fib_iter m a b = fib_rec m a b
a, b: natfib_iter n (a + b) (b + (a + b)) = fib_iter n b (a + b) + fib_iter n a bapply add_comm.n: nat
IH: forall m : nat, m < S (S n) -> forall a b : nat, fib_iter m a b = fib_rec m a b
a, b: natfib_iter n a b + fib_iter n b (a + b) = fib_iter n b (a + b) + fib_iter n a bn: nat
IH: forall m : nat, m < S (S n) -> forall a b : nat, fib_iter m a b = fib_rec m a b
a, b: natn < S (S n)n: nat
IH: forall m : nat, m < S (S n) -> forall a b : nat, fib_iter m a b = fib_rec m a b
a, b: natS n <= S (S n)apply le_S.n: nat
IH: forall m : nat, m < S (S n) -> forall a b : nat, fib_iter m a b = fib_rec m a b
a, b: natn <= S nn: nat
IH: forall m : nat, m < S (S n) -> forall a b : nat, fib_iter m a b = fib_rec m a b
a, b: natS n < S (S n)n: nat
IH: forall m : nat, m < S (S n) -> forall a b : nat, fib_iter m a b = fib_rec m a b
a, b: natS (S n) <= S (S n)apply le_refl. Qed.n: nat
IH: forall m : nat, m < S (S n) -> forall a b : nat, fib_iter m a b = fib_rec m a b
a, b: natn <= nn: natfib n = fib_rec n zero onen: natfib n = fib_rec n zero onen: nat
H: forall m : nat, m < n -> fib m = fib_rec m zero onefib n = fib_rec n zero oneH: forall m : nat, m < O -> fib m = fib_rec m zero onefib O = fib_rec O zero onen: nat
H: forall m : nat, m < S n -> fib m = fib_rec m zero onefib (S n) = fib_rec (S n) zero onereflexivity.H: forall m : nat, m < O -> fib m = fib_rec m zero onefib O = fib_rec O zero onen: nat
H: forall m : nat, m < S n -> fib m = fib_rec m zero onefib (S n) = fib_rec (S n) zero onen: nat
H: forall m : nat, m < S n -> fib m = fib_rec m zero onematch n with | O => S O | S n'' => fib n + fib n'' end = match n with | O => one | S k => fib_rec n zero one + fib_rec k zero one endH: forall m : nat, m < S O -> fib m = fib_rec m zero oneS O = onen: nat
H: forall m : nat, m < S (S n) -> fib m = fib_rec m zero onefib (S n) + fib n = fib_rec (S n) zero one + fib_rec n zero onereflexivity.H: forall m : nat, m < S O -> fib m = fib_rec m zero oneS O = onen: nat
H: forall m : nat, m < S (S n) -> fib m = fib_rec m zero onefib (S n) + fib n = fib_rec (S n) zero one + fib_rec n zero onen: nat
H: forall m : nat, m < S (S n) -> fib m = fib_rec m zero onefib_rec (S n) zero one + fib_rec n zero one = fib_rec (S n) zero one + fib_rec n zero onen: nat
H: forall m : nat, m < S (S n) -> fib m = fib_rec m zero onen < S (S n)n: nat
H: forall m : nat, m < S (S n) -> fib m = fib_rec m zero oneS n < S (S n)reflexivity.n: nat
H: forall m : nat, m < S (S n) -> fib m = fib_rec m zero onefib_rec (S n) zero one + fib_rec n zero one = fib_rec (S n) zero one + fib_rec n zero onen: nat
H: forall m : nat, m < S (S n) -> fib m = fib_rec m zero onen < S (S n)n: nat
H: forall m : nat, m < S (S n) -> fib m = fib_rec m zero oneS n <= S (S n)apply le_S.n: nat
H: forall m : nat, m < S (S n) -> fib m = fib_rec m zero onen <= S nn: nat
H: forall m : nat, m < S (S n) -> fib m = fib_rec m zero oneS n < S (S n)n: nat
H: forall m : nat, m < S (S n) -> fib m = fib_rec m zero oneS (S n) <= S (S n)apply le_refl. Qed.n: nat
H: forall m : nat, m < S (S n) -> fib m = fib_rec m zero onen <= nn: natfib n = fib' nn: natfib n = fib' nn: natfib_rec n zero one = fib' nn: natfib_rec n zero one = fib_iter n zero onereflexivity. Qed.n: natfib_rec n zero one = fib_rec n zero one
n, a, b: natfib_iter n a b = a * fib_iter n one zero + b * fib_iter n zero onen, a, b: natfib_iter n a b = a * fib_iter n one zero + b * fib_iter n zero onen: natforall a b : nat, fib_iter n a b = a * fib_iter n one zero + b * fib_iter n zero oneforall a b : nat, fib_iter O a b = a * fib_iter O one zero + b * fib_iter O zero onen: nat
IHn: forall a b : nat, fib_iter n a b = a * fib_iter n one zero + b * fib_iter n zero oneforall a b : nat, fib_iter (S n) a b = a * fib_iter (S n) one zero + b * fib_iter (S n) zero oneforall a b : nat, fib_iter O a b = a * fib_iter O one zero + b * fib_iter O zero onea, b: natfib_iter O a b = a * fib_iter O one zero + b * fib_iter O zero onea, b: nata = a * one + b * zeroreflexivity.a, b: nata = an: nat
IHn: forall a b : nat, fib_iter n a b = a * fib_iter n one zero + b * fib_iter n zero oneforall a b : nat, fib_iter (S n) a b = a * fib_iter (S n) one zero + b * fib_iter (S n) zero onen: nat
IHn: forall a b : nat, fib_iter n a b = a * fib_iter n one zero + b * fib_iter n zero one
a, b: natfib_iter (S n) a b = a * fib_iter (S n) one zero + b * fib_iter (S n) zero onen: nat
IHn: forall a b : nat, fib_iter n a b = a * fib_iter n one zero + b * fib_iter n zero one
a, b: natfib_iter n b (a + b) = a * fib_iter n zero (S zero) + b * fib_iter n one onen: nat
IHn: forall a b : nat, fib_iter n a b = a * fib_iter n one zero + b * fib_iter n zero one
a, b: natb * fib_iter n one zero + (a + b) * fib_iter n zero one = a * fib_iter n zero (S zero) + b * fib_iter n one onen: nat
IHn: forall a b : nat, fib_iter n a b = a * fib_iter n one zero + b * fib_iter n zero one
a, b: natb * fib_iter n one zero + (a + b) * fib_iter n zero one = a * fib_iter n zero (S zero) + b * (one * fib_iter n one zero + one * fib_iter n zero one)n: nat
IHn: forall a b : nat, fib_iter n a b = a * fib_iter n one zero + b * fib_iter n zero one
a, b: natb * fib_iter n one zero + (a + b) * fib_iter n zero one = a * fib_iter n zero (S zero) + b * (fib_iter n one zero + fib_iter n zero one)n: nat
IHn: forall a b : nat, fib_iter n a b = a * fib_iter n one zero + b * fib_iter n zero one
a, b: natb * fib_iter n one zero + (a * fib_iter n zero one + b * fib_iter n zero one) = a * fib_iter n zero (S zero) + (b * fib_iter n one zero + b * fib_iter n zero one)n: nat
IHn: forall a b : nat, fib_iter n a b = a * fib_iter n one zero + b * fib_iter n zero one
a, b: natb * fib_iter n one zero + a * fib_iter n zero one + b * fib_iter n zero one = a * fib_iter n zero (S zero) + b * fib_iter n one zero + b * fib_iter n zero oneapply add_comm. Qed.n: nat
IHn: forall a b : nat, fib_iter n a b = a * fib_iter n one zero + b * fib_iter n zero one
a, b: natb * fib_iter n one zero + a * fib_iter n zero one = a * fib_iter n zero (S zero) + b * fib_iter n one zeron: natfib n = fib' nn: natfib n = fib' nn: natfib n = fib_iter n zero onen: nat
H: forall m : nat, m < n -> fib m = fib_iter m zero onefib n = fib_iter n zero oneH: forall m : nat, m < O -> fib m = fib_iter m zero onefib O = fib_iter O zero onen: nat
H: forall m : nat, m < S n -> fib m = fib_iter m zero onefib (S n) = fib_iter (S n) zero onereflexivity.H: forall m : nat, m < O -> fib m = fib_iter m zero onefib O = fib_iter O zero onen: nat
H: forall m : nat, m < S n -> fib m = fib_iter m zero onefib (S n) = fib_iter (S n) zero onen: nat
H: forall m : nat, m < S n -> fib m = fib_iter m zero onematch n with | O => S O | S n'' => fib n + fib n'' end = fib_iter n one oneH: forall m : nat, m < S O -> fib m = fib_iter m zero oneS O = fib_iter O one onen: nat
H: forall m : nat, m < S (S n) -> fib m = fib_iter m zero onefib (S n) + fib n = fib_iter (S n) one onereflexivity.H: forall m : nat, m < S O -> fib m = fib_iter m zero oneS O = fib_iter O one onen: nat
H: forall m : nat, m < S (S n) -> fib m = fib_iter m zero onefib (S n) + fib n = fib_iter (S n) one onen: nat
H: forall m : nat, m < S (S n) -> fib m = fib_iter m zero onefib (S n) + fib n = one * fib_iter (S n) one zero + one * fib_iter (S n) zero onen: nat
H: forall m : nat, m < S (S n) -> fib m = fib_iter m zero onefib_iter (S n) zero one + fib_iter n zero one = one * fib_iter (S n) one zero + one * fib_iter (S n) zero onen: nat
H: forall m : nat, m < S (S n) -> fib m = fib_iter m zero onen < S (S n)n: nat
H: forall m : nat, m < S (S n) -> fib m = fib_iter m zero oneS n < S (S n)n: nat
H: forall m : nat, m < S (S n) -> fib m = fib_iter m zero onefib_iter (S n) zero one + fib_iter n zero one = one * fib_iter (S n) one zero + one * fib_iter (S n) zero onen: nat
H: forall m : nat, m < S (S n) -> fib m = fib_iter m zero onefib_iter n one one + fib_iter n zero one = fib_iter n zero (S zero) + O + (fib_iter n one one + O)apply add_comm.n: nat
H: forall m : nat, m < S (S n) -> fib m = fib_iter m zero onefib_iter n one one + fib_iter n zero one = fib_iter n zero (S zero) + fib_iter n one onen: nat
H: forall m : nat, m < S (S n) -> fib m = fib_iter m zero onen < S (S n)n: nat
H: forall m : nat, m < S (S n) -> fib m = fib_iter m zero oneS n <= S (S n)apply le_S.n: nat
H: forall m : nat, m < S (S n) -> fib m = fib_iter m zero onen <= S nn: nat
H: forall m : nat, m < S (S n) -> fib m = fib_iter m zero oneS n < S (S n)n: nat
H: forall m : nat, m < S (S n) -> fib m = fib_iter m zero oneS (S n) <= S (S n)apply le_refl. Qed.n: nat
H: forall m : nat, m < S (S n) -> fib m = fib_iter m zero onen <= n