How do I prove that two Fibonacci implementations are equal in Coq?

后端 未结 6 1280
南方客
南方客 2021-01-03 16:36

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 ex

6条回答
  •  暖寄归人
    2021-01-03 16:50

    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 with

    cut (Q n /\ Q (S n))
    

    from

     Q n
    

    to

     Q n /\ Q (S n)
    

    This new goal trivially implies the original goal, but with it the induction hypothesis becomes stronger, so it becomes possible to rewrite more.

    IHn : Q n /\ Q (S n)
    =========================
    Q (S n) /\ Q (S (S n))
    

    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.

    Ltac nameit Q :=
      match goal with [ _:_ |- ?P ?n] => let X := fresh Q in remember P as X end.
    
    Require Import Ring Arith.
    

    (Btw, I renamed vistit_fib_v2 to fib_v2.) I needed a lemma about one step of fib_v2.

    Lemma fib_v2_lemma: forall n a b, fib_v2 (S (S n)) a b = fib_v2 (S n) a b + fib_v2 n a b.
      intro n.
      pattern n.
      nameit Q.
      cut (Q n /\ Q (S n)).
      tauto.                             (* Q n /\ Q (S n) -> Q n *)
    
      induction n.
      split; subst; simpl; intros; ring. (* Q 0 /\ Q 1  *)
      split; try tauto.                  (* Q (S n)     *)
    
      subst Q.                           (* Q (S (S n)) *)
      destruct IHn as [H1 H2].
      assert (L1: forall n a b, fib_v2 (S n) a b = fib_v2 n b (a+b)) by reflexivity.
      congruence.
    Qed.
    

    The congruence tactic handles goals that follow from a bunch of A = B assumptions and rewriting.

    Proving the theorem is very similar.

    Theorem fib_v1_fib_v2 : forall n, fib_v1 n = fib_v2 n 0 1.
      intro n.
      pattern n.
      nameit Q.
      cut (Q n /\ Q (S n)).
      tauto.                             (* Q n /\ Q (S n) -> Q n *)
    
      induction n.
      split; subst; simpl; intros; ring. (* Q 0 /\ Q 1  *)
      split; try tauto.                  (* Q (S n)     *)
    
      subst Q.                           (* Q (S (S n)) *)
      destruct IHn as [H1 H2].
      assert (fib_v1 (S (S n)) = fib_v1 (S n) + fib_v1 n) by reflexivity.
      assert (fib_v2 (S (S n)) 0 1 = fib_v2 (S n) 0 1 + fib_v2 n 0 1) by
          (pose fib_v2_lemma; congruence).
      congruence.
    Qed.  
    

    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.

提交回复
热议问题