I've two Fibonacci implementations, seen below, that I want to prove are functionally equivalent.
I've already proved properties about natural numbers, but this exercise requires another approach that I cannot figure out.
The textbook I'm using have introduced the following syntax of Coq, so it should be possible to prove equality using this notation:
<definition> ::= <keyword> <identifier> : <statement> <proof>
<keyword> ::= Proposition | Lemma | Theorem | Corollary
<statement> ::= {<quantifier>,}* <expression>
<quantifier> ::= forall {<identifier>}+ : <type>
| forall {({<identifier>}+ : <type>)}+
<proof> ::= Proof. {<tactic>.}* <end-of-proof>
<end-of-proof> ::= Qed. | Admitted. | Abort.
Here are the two implementations:
Fixpoint fib_v1 (n : nat) : nat :=
match n with
| 0 => O
| S n' => match n' with
| O => 1
| S n'' => (fib_v1 n') + (fib_v1 n'')
end
end.
Fixpoint visit_fib_v2 (n a1 a2 : nat) : nat :=
match n with
| 0 => a1
| S n' => visit_fib_v2 n' a2 (a1 + a2)
end.
It is pretty obvious that these functions compute the same value for the base case n = 0
, but the induction case is much harder?
I've tried proving the following Lemma, but I'm stuck in induction case:
Lemma about_visit_fib_v2 :
forall i j : nat,
visit_fib_v2 i (fib_v1 (S j)) ((fib_v1 j) + (fib_v1 (S j))) = (fib_v1 (add_v1 i (S j))).
Proof.
induction i as [| i' IHi'].
intro j.
rewrite -> (unfold_visit_fib_v2_0 (fib_v1 (S j)) ((fib_v1 j) + (fib_v1 (S j)))).
rewrite -> (add_v1_0_n (S j)).
reflexivity.
intro j.
rewrite -> (unfold_visit_fib_v2_S i' (fib_v1 (S j)) ((fib_v1 j) + (fib_v1 (S j)))).
Admitted.
Where:
Fixpoint add_v1 (i j : nat) : nat :=
match i with
| O => j
| S i' => S (add_v1 i' j)
end.
@larsr's answer inspired this alternative answer.
First of all, let's define
fib_v2
:Then, we are going to need a lemma, which is the same as
fib_v2_lemma
in @larsr's answer. I'm including it here for consistency and to show an alternative proof.As suggested in the comments by larsr, the
visit_fib_v2_main_property
lemma can be also proved by the following impressive one-liner:Because of the nature of the numbers in the Fibonacci series it's very convenient to define an alternative induction principle:
The
pair_induction
principle basically says that if we can prove some propertyP
for0
and1
and if for every natural numberk > 1
, we can proveP k
holds under the assumption thatP (k - 1)
andP (k - 2)
hold, then we can proveforall n, P n
.Using our custom induction principle, we get the proof as follows:
Here is yet another answer, similar to the one using mathcomp, but this one uses "vanilla" Coq.
First of all, we need some imports, additional definitions, and a couple of helper lemmas:
To prove the main lemma we are going to use the standard well-founded induction
lt_wf_ind
principle for natural numbers with the<
relation (a.k.a. complete induction):This time we need to prove only one subgoal, since the
n = 0
case for complete induction is always vacuously true. Our induction hypothesis, unsurprisingly, looks like this:Here is the proof:
This proof script only shows the proof structure. It could be useful to explain the idea of the proof.
A note of warning: in what follows I'll to try to show the main idea of such a proof, so I'm not going to stick to some subset of Coq and I won't do arithmetic manually. Instead I'll use some proof automation, viz. the
ring
tactic. However, feel free to ask additional questions, so you could convert the proof to somewhat that would suit your purposes.I think it's easier to start with some generalization:
If using
ring
doesn't suit your needs, you can perform multiplerewrite
steps using the lemmas of theArith
module.Now, let's get to our goal:
There is a very powerful library -- math-comp written in the Ssreflect formal proof language that is in its turn based on Coq. In this answer I present a version that uses its facilities. It's just a simplified piece of this development. All credit goes to the original author.
Let's do some imports and the definitions of our two functions, math-comp (ssreflect) style:
A helper lemma expressing the basic property of Fibonacci numbers:
Now, let's tackle equivalence of the two implementations. The main idea here, that distinguish the following proof from the other proofs has been presented as of time of this writing, is that we perform kind of complete induction, using
elim: n {-2}n (leqnn n)
. This gives us the following (strong) induction hypothesis:Here is the main lemma and its proof:
Anton's proof is very beautiful, and better than mine, but it might be useful, anyway.
Instead of coming up with the generalisation lemma, I strengthened the induction hypothesis.
Say the original goal is
Q n
. I then changed the goal withfrom
to
This new goal trivially implies the original goal, but with it the induction hypothesis becomes stronger, so it becomes possible to rewrite more.
This idea is explained in Software Foundations in the chapter where one does proofs over even numbers.
Because the propostion often is very long, I made an
Ltac
tactic that names the long and messy term.(Btw, I renamed
vistit_fib_v2
tofib_v2
.) I needed a lemma about one step of fib_v2.The
congruence
tactic handles goals that follow from a bunch ofA = B
assumptions and rewriting.Proving the theorem is very similar.
All the boiler plate code could be put in a tactic, but I didn't want to go crazy with the
Ltac
, since that was not what the question was about.