src/HOL/Isar_examples/Fibonacci.thy
author paulson
Mon, 04 Sep 2000 10:26:34 +0200
changeset 9826 5b5d9ee742ca
parent 9659 b9cf6801f3da
child 9870 2374ba026fc6
permissions -rw-r--r--
minor fixes for new version of Primes.thy

(*  Title:      HOL/Isar_examples/Fibonacci.thy
    ID:         $Id$
    Author:     Gertrud Bauer
    Copyright   1999 Technische Universitaet Muenchen

The Fibonacci function.  Demonstrates the use of recdef.  Original
tactic script by Lawrence C Paulson.

Fibonacci numbers: proofs of laws taken from

  R. L. Graham, D. E. Knuth, O. Patashnik.
  Concrete Mathematics.
  (Addison-Wesley, 1989)
*)

header {* Fib and Gcd commute *};

theory Fibonacci = Primes:;

text_raw {*
 \footnote{Isar version by Gertrud Bauer.  Original tactic script by
 Larry Paulson.  A few proofs of laws taken from
 \cite{Concrete-Math}.}
*};


subsection {* Fibonacci numbers *};

consts fib :: "nat => nat";
recdef fib less_than
 "fib 0 = 0"
 "fib 1 = 1"
 "fib (Suc (Suc x)) = fib x + fib (Suc x)";

lemma [simp]: "0 < fib (Suc n)";
  by (induct n rule: fib.induct) (simp+);


text {* Alternative induction rule. *};

theorem fib_induct:
    "P 0 ==> P 1 ==> (!!n. P (n + 1) ==> P n ==> P (n + 2)) ==> P n";
  by (induct rule: fib.induct, simp+);



subsection {* Fib and gcd commute *};

text {* A few laws taken from \cite{Concrete-Math}. *};

lemma fib_add:
  "fib (n + k + 1) = fib (k + 1) * fib (n + 1) + fib k * fib n"
  (is "?P n")
  -- {* see \cite[page 280]{Concrete-Math} *};
proof (induct ?P n rule: fib_induct);
  show "?P 0"; by simp;
  show "?P 1"; by simp;
  fix n;
  have "fib (n + 2 + k + 1)
    = fib (n + k + 1) + fib (n + 1 + k + 1)"; by simp;
  also; assume "fib (n + k + 1)
    = fib (k + 1) * fib (n + 1) + fib k * fib n"
      (is " _ = ?R1");
  also; assume "fib (n + 1 + k + 1)
    = fib (k + 1) * fib (n + 1 + 1) + fib k * fib (n + 1)"
      (is " _ = ?R2");
  also; have "?R1 + ?R2
    = fib (k + 1) * fib (n + 2 + 1) + fib k * fib (n + 2)";
    by (simp add: add_mult_distrib2);
  finally; show "?P (n + 2)"; .;
qed;

lemma gcd_fib_Suc_eq_1: "gcd (fib n, fib (n + 1)) = 1" (is "?P n");
proof (induct ?P n rule: fib_induct);
  show "?P 0"; by simp;
  show "?P 1"; by simp;
  fix n;
  have "fib (n + 2 + 1) = fib (n + 1) + fib (n + 2)";
    by simp;
  also; have "gcd (fib (n + 2), ...) = gcd (fib (n + 2), fib (n + 1))";
    by (simp only: gcd_add2');
  also; have "... = gcd (fib (n + 1), fib (n + 1 + 1))";
    by (simp add: gcd_commute);
  also; assume "... = 1";
  finally; show "?P (n + 2)"; .;
qed;

lemma gcd_mult_add: "0 < n ==> gcd (n * k + m, n) = gcd (m, n)";
proof -;
  assume "0 < n";
  hence "gcd (n * k + m, n) = gcd (n, m mod n)";
    by (simp add: gcd_non_0 add_commute);
  also; have "... = gcd (m, n)"; by (simp! add: gcd_non_0);
  finally; show ?thesis; .;
qed;

lemma gcd_fib_add: "gcd (fib m, fib (n + m)) = gcd (fib m, fib n)";
proof (cases m);
  assume "m = 0";
  thus ?thesis; by simp;
next;
  fix k; assume "m = Suc k";
  hence "gcd (fib m, fib (n + m)) = gcd (fib (n + k + 1), fib (k + 1))";
    by (simp add: gcd_commute);
  also; have "fib (n + k + 1)
    = fib (k + 1) * fib (n + 1) + fib k * fib n";
    by (rule fib_add);
  also; have "gcd (..., fib (k + 1)) = gcd (fib k * fib n, fib (k + 1))";
    by (simp add: gcd_mult_add);
  also; have "... = gcd (fib n, fib (k + 1))";
    by (simp only: gcd_fib_Suc_eq_1 gcd_mult_cancel);
  also; have "... = gcd (fib m, fib n)";
    by (simp! add: gcd_commute);
  finally; show ?thesis; .;
qed;

lemma gcd_fib_diff:
  "m <= n ==> gcd (fib m, fib (n - m)) = gcd (fib m, fib n)";
proof -;
  assume "m <= n";
  have "gcd (fib m, fib (n - m)) = gcd (fib m, fib (n - m + m))";
    by (simp add: gcd_fib_add);
  also; have "n - m + m = n"; by (simp!);
  finally; show ?thesis; .;
qed;

lemma gcd_fib_mod:
  "0 < m ==> gcd (fib m, fib (n mod m)) = gcd (fib m, fib n)";
proof (induct n rule: less_induct);
  fix n;
  assume m: "0 < m"
  and hyp: "ALL ma. ma < n
           --> gcd (fib m, fib (ma mod m)) = gcd (fib m, fib ma)";
  have "n mod m = (if n < m then n else (n - m) mod m)";
    by (rule mod_if);
  also; have "gcd (fib m, fib ...) = gcd (fib m, fib n)";
  proof cases;
    assume "n < m"; thus ?thesis; by simp;
  next;
    assume not_lt: "~ n < m"; hence le: "m <= n"; by simp;
    have "n - m < n"; by (simp! add: diff_less);
    with hyp; have "gcd (fib m, fib ((n - m) mod m))
       = gcd (fib m, fib (n - m))"; by simp;
    also; from le; have "... = gcd (fib m, fib n)";
      by (rule gcd_fib_diff);
    finally; have "gcd (fib m, fib ((n - m) mod m)) =
      gcd (fib m, fib n)"; .;
    with not_lt; show ?thesis; by simp;
  qed;
  finally; show "gcd (fib m, fib (n mod m)) = gcd (fib m, fib n)"; .;
qed;


theorem fib_gcd: "fib (gcd (m, n)) = gcd (fib m, fib n)" (is "?P m n");
proof (induct ?P m n rule: gcd_induct);
  fix m; show "fib (gcd (m, 0)) = gcd (fib m, fib 0)"; by simp;
  fix n :: nat; assume n: "0 < n";
  hence "gcd (m, n) = gcd (n, m mod n)"; by (rule gcd_non_0);
  also; assume hyp: "fib ... = gcd (fib n, fib (m mod n))";
  also; from n; have "... = gcd (fib n, fib m)"; by (rule gcd_fib_mod);
  also; have "... = gcd (fib m, fib n)"; by (rule gcd_commute);
  finally; show "fib (gcd (m, n)) = gcd (fib m, fib n)"; .;
qed;

end;