# HG changeset patch # User wenzelm # Date 1491423918 -7200 # Node ID 079a6f850c0265c06227e143b4ca7bdc1e292a38 # Parent f365f61f2081266a5d00763679ec8ad6cbd41b76 misc tuning and modernization; diff -r f365f61f2081 -r 079a6f850c02 src/HOL/Number_Theory/Fib.thy --- a/src/HOL/Number_Theory/Fib.thy Wed Apr 05 22:00:44 2017 +0200 +++ b/src/HOL/Number_Theory/Fib.thy Wed Apr 05 22:25:18 2017 +0200 @@ -14,29 +14,28 @@ subsection \Fibonacci numbers\ fun fib :: "nat \ nat" -where - fib0: "fib 0 = 0" -| fib1: "fib (Suc 0) = 1" -| fib2: "fib (Suc (Suc n)) = fib (Suc n) + fib n" + where + fib0: "fib 0 = 0" + | fib1: "fib (Suc 0) = 1" + | fib2: "fib (Suc (Suc n)) = fib (Suc n) + fib n" subsection \Basic Properties\ -lemma fib_1 [simp]: "fib (1::nat) = 1" +lemma fib_1 [simp]: "fib 1 = 1" by (metis One_nat_def fib1) -lemma fib_2 [simp]: "fib (2::nat) = 1" - using fib.simps(3) [of 0] - by (simp add: numeral_2_eq_2) +lemma fib_2 [simp]: "fib 2 = 1" + using fib.simps(3) [of 0] by (simp add: numeral_2_eq_2) lemma fib_plus_2: "fib (n + 2) = fib (n + 1) + fib n" by (metis Suc_eq_plus1 add_2_eq_Suc' fib.simps(3)) -lemma fib_add: "fib (Suc (n+k)) = fib (Suc k) * fib (Suc n) + fib k * fib n" +lemma fib_add: "fib (Suc (n + k)) = fib (Suc k) * fib (Suc n) + fib k * fib n" by (induct n rule: fib.induct) (auto simp add: field_simps) lemma fib_neq_0_nat: "n > 0 \ fib n > 0" - by (induct n rule: fib.induct) (auto simp add: ) + by (induct n rule: fib.induct) auto subsection \More efficient code\ @@ -45,21 +44,22 @@ The naive approach is very inefficient since the branching recursion leads to many values of @{term fib} being computed multiple times. We can avoid this by ``remembering'' the last two values in the sequence, yielding a tail-recursive version. - This is far from optimal (it takes roughly $O(n\cdot M(n))$ time where $M(n)$ is the + This is far from optimal (it takes roughly $O(n\cdot M(n))$ time where $M(n)$ is the time required to multiply two $n$-bit integers), but much better than the naive version, which is exponential. \ -fun gen_fib :: "nat \ nat \ nat \ nat" where - "gen_fib a b 0 = a" -| "gen_fib a b (Suc 0) = b" -| "gen_fib a b (Suc (Suc n)) = gen_fib b (a + b) (Suc n)" +fun gen_fib :: "nat \ nat \ nat \ nat" + where + "gen_fib a b 0 = a" + | "gen_fib a b (Suc 0) = b" + | "gen_fib a b (Suc (Suc n)) = gen_fib b (a + b) (Suc n)" lemma gen_fib_recurrence: "gen_fib a b (Suc (Suc n)) = gen_fib a b n + gen_fib a b (Suc n)" - by (induction a b n rule: gen_fib.induct) simp_all - + by (induct a b n rule: gen_fib.induct) simp_all + lemma gen_fib_fib: "gen_fib (fib n) (fib (Suc n)) m = fib (n + m)" - by (induction m rule: fib.induct) (simp_all del: gen_fib.simps(3) add: gen_fib_recurrence) + by (induct m rule: fib.induct) (simp_all del: gen_fib.simps(3) add: gen_fib_recurrence) lemma fib_conv_gen_fib: "fib n = gen_fib 0 1 n" using gen_fib_fib[of 0 n] by simp @@ -70,22 +70,22 @@ subsection \A Few Elementary Results\ text \ - \medskip Concrete Mathematics, page 278: Cassini's identity. The proof is + \<^medskip> Concrete Mathematics, page 278: Cassini's identity. The proof is much easier using integers, not natural numbers! \ lemma fib_Cassini_int: "int (fib (Suc (Suc n)) * fib n) - int((fib (Suc n))\<^sup>2) = - ((-1)^n)" - by (induct n rule: fib.induct) (auto simp add: field_simps power2_eq_square power_add) + by (induct n rule: fib.induct) (auto simp add: field_simps power2_eq_square power_add) lemma fib_Cassini_nat: "fib (Suc (Suc n)) * fib n = (if even n then (fib (Suc n))\<^sup>2 - 1 else (fib (Suc n))\<^sup>2 + 1)" - using fib_Cassini_int [of n] by (auto simp del: of_nat_mult of_nat_power) + using fib_Cassini_int [of n] by (auto simp del: of_nat_mult of_nat_power) subsection \Law 6.111 of Concrete Mathematics\ -lemma coprime_fib_Suc_nat: "coprime (fib (n::nat)) (fib (Suc n))" +lemma coprime_fib_Suc_nat: "coprime (fib n) (fib (Suc n))" apply (induct n rule: fib.induct) apply auto apply (metis gcd_add1 add.commute) @@ -109,12 +109,12 @@ proof (cases "m < n") case True then have "m \ n" by auto - with \0 < m\ have pos_n: "0 < n" by auto - with \0 < m\ \m < n\ have diff: "n - m < n" by auto + with \0 < m\ have "0 < n" by auto + with \0 < m\ \m < n\ have *: "n - m < n" by auto have "gcd (fib m) (fib (n mod m)) = gcd (fib m) (fib ((n - m) mod m))" - by (simp add: mod_if [of n]) (insert \m < n\, auto) + by (simp add: mod_if [of n]) (use \m < n\ in auto) also have "\ = gcd (fib m) (fib (n - m))" - by (simp add: less.hyps diff \0 < m\) + by (simp add: less.hyps * \0 < m\) also have "\ = gcd (fib m) (fib n)" by (simp add: gcd_fib_diff \m \ n\) finally show "gcd (fib m) (fib (n mod m)) = gcd (fib m) (fib n)" . @@ -125,8 +125,7 @@ qed qed -lemma fib_gcd: "fib (gcd m n) = gcd (fib m) (fib n)" - \ \Law 6.111\ +lemma fib_gcd: "fib (gcd m n) = gcd (fib m) (fib n)" \ \Law 6.111\ by (induct m n rule: gcd_nat_induct) (simp_all add: gcd_non_0_nat gcd.commute gcd_fib_mod) theorem fib_mult_eq_sum_nat: "fib (Suc n) * fib n = (\k \ {..n}. fib k * fib k)" @@ -136,49 +135,55 @@ subsection \Closed form\ lemma fib_closed_form: - defines "\ \ (1 + sqrt 5) / (2::real)" and "\ \ (1 - sqrt 5) / (2::real)" - shows "of_nat (fib n) = (\ ^ n - \ ^ n) / sqrt 5" -proof (induction n rule: fib.induct) + fixes \ \ :: real + defines "\ \ (1 + sqrt 5) / 2" + and "\ \ (1 - sqrt 5) / 2" + shows "of_nat (fib n) = (\ ^ n - \ ^ n) / sqrt 5" +proof (induct n rule: fib.induct) fix n :: nat assume IH1: "of_nat (fib n) = (\ ^ n - \ ^ n) / sqrt 5" assume IH2: "of_nat (fib (Suc n)) = (\ ^ Suc n - \ ^ Suc n) / sqrt 5" have "of_nat (fib (Suc (Suc n))) = of_nat (fib (Suc n)) + of_nat (fib n)" by simp - also have "... = (\^n*(\ + 1) - \^n*(\ + 1)) / sqrt 5" + also have "\ = (\^n * (\ + 1) - \^n * (\ + 1)) / sqrt 5" by (simp add: IH1 IH2 field_simps) also have "\ + 1 = \\<^sup>2" by (simp add: \_def field_simps power2_eq_square) also have "\ + 1 = \\<^sup>2" by (simp add: \_def field_simps power2_eq_square) - also have "\^n * \\<^sup>2 - \^n * \\<^sup>2 = \ ^ Suc (Suc n) - \ ^ Suc (Suc n)" + also have "\^n * \\<^sup>2 - \^n * \\<^sup>2 = \ ^ Suc (Suc n) - \ ^ Suc (Suc n)" by (simp add: power2_eq_square) finally show "of_nat (fib (Suc (Suc n))) = (\ ^ Suc (Suc n) - \ ^ Suc (Suc n)) / sqrt 5" . qed (simp_all add: \_def \_def field_simps) lemma fib_closed_form': - defines "\ \ (1 + sqrt 5) / (2 :: real)" and "\ \ (1 - sqrt 5) / (2 :: real)" + fixes \ \ :: real + defines "\ \ (1 + sqrt 5) / 2" + and "\ \ (1 - sqrt 5) / 2" assumes "n > 0" - shows "fib n = round (\ ^ n / sqrt 5)" + shows "fib n = round (\ ^ n / sqrt 5)" proof (rule sym, rule round_unique') have "\\ ^ n / sqrt 5 - of_int (int (fib n))\ = \\\ ^ n / sqrt 5" by (simp add: fib_closed_form[folded \_def \_def] field_simps power_abs) also { from assms have "\\\^n \ \\\^1" by (intro power_decreasing) (simp_all add: algebra_simps real_le_lsqrt) - also have "... < sqrt 5 / 2" by (simp add: \_def field_simps) + also have "\ < sqrt 5 / 2" by (simp add: \_def field_simps) finally have "\\\^n / sqrt 5 < 1/2" by (simp add: field_simps) } finally show "\\ ^ n / sqrt 5 - of_int (int (fib n))\ < 1/2" . qed lemma fib_asymptotics: - defines "\ \ (1 + sqrt 5) / (2 :: real)" - shows "(\n. real (fib n) / (\ ^ n / sqrt 5)) \ 1" + fixes \ :: real + defines "\ \ (1 + sqrt 5) / 2" + shows "(\n. real (fib n) / (\ ^ n / sqrt 5)) \ 1" proof - - define \ where "\ \ (1 - sqrt 5) / (2 :: real)" + define \ :: real where "\ \ (1 - sqrt 5) / 2" have "\ > 1" by (simp add: \_def) - hence A: "\ \ 0" by auto + then have *: "\ \ 0" by auto have "(\n. (\ / \) ^ n) \ 0" by (rule LIMSEQ_power_zero) (simp_all add: \_def \_def field_simps add_pos_pos) - hence "(\n. 1 - (\ / \) ^ n) \ 1 - 0" by (intro tendsto_diff tendsto_const) - with A show ?thesis + then have "(\n. 1 - (\ / \) ^ n) \ 1 - 0" + by (intro tendsto_diff tendsto_const) + with * show ?thesis by (simp add: divide_simps fib_closed_form [folded \_def \_def]) qed @@ -186,58 +191,72 @@ subsection \Divide-and-Conquer recurrence\ text \ - The following divide-and-conquer recurrence allows for a more efficient computation - of Fibonacci numbers; however, it requires memoisation of values to be reasonably + The following divide-and-conquer recurrence allows for a more efficient computation + of Fibonacci numbers; however, it requires memoisation of values to be reasonably efficient, cutting the number of values to be computed to logarithmically many instead of - linearly many. The vast majority of the computation time is then actually spent on the + linearly many. The vast majority of the computation time is then actually spent on the multiplication, since the output number is exponential in the input number. \ lemma fib_rec_odd: - defines "\ \ (1 + sqrt 5) / (2 :: real)" and "\ \ (1 - sqrt 5) / (2 :: real)" - shows "fib (Suc (2*n)) = fib n^2 + fib (Suc n)^2" + fixes \ \ :: real + defines "\ \ (1 + sqrt 5) / 2" + and "\ \ (1 - sqrt 5) / 2" + shows "fib (Suc (2 * n)) = fib n^2 + fib (Suc n)^2" proof - have "of_nat (fib n^2 + fib (Suc n)^2) = ((\ ^ n - \ ^ n)\<^sup>2 + (\ * \ ^ n - \ * \ ^ n)\<^sup>2)/5" by (simp add: fib_closed_form[folded \_def \_def] field_simps power2_eq_square) - also have "(\ ^ n - \ ^ n)\<^sup>2 + (\ * \ ^ n - \ * \ ^ n)\<^sup>2 = - \^(2*n) + \^(2*n) - 2*(\*\)^n + \^(2*n+2) + \^(2*n+2) - 2*(\*\)^(n+1)" (is "_ = ?A") - by (simp add: power2_eq_square algebra_simps power_mult power_mult_distrib) - also have "\ * \ = -1" by (simp add: \_def \_def field_simps) - hence "?A = \^(2*n+1) * (\ + inverse \) + \^(2*n+1) * (\ + inverse \)" + also + let ?A = "\^(2 * n) + \^(2 * n) - 2*(\ * \)^n + \^(2 * n + 2) + \^(2 * n + 2) - 2*(\ * \)^(n + 1)" + have "(\ ^ n - \ ^ n)\<^sup>2 + (\ * \ ^ n - \ * \ ^ n)\<^sup>2 = ?A" + by (simp add: power2_eq_square algebra_simps power_mult power_mult_distrib) + also have "\ * \ = -1" + by (simp add: \_def \_def field_simps) + then have "?A = \^(2 * n + 1) * (\ + inverse \) + \^(2 * n + 1) * (\ + inverse \)" by (auto simp: field_simps power2_eq_square) - also have "1 + sqrt 5 > 0" by (auto intro: add_pos_pos) - hence "\ + inverse \ = sqrt 5" by (simp add: \_def field_simps) - also have "\ + inverse \ = -sqrt 5" by (simp add: \_def field_simps) - also have "(\ ^ (2*n+1) * sqrt 5 + \ ^ (2*n+1)* - sqrt 5) / 5 = - (\ ^ (2*n+1) - \ ^ (2*n+1)) * (sqrt 5 / 5)" by (simp add: field_simps) - also have "sqrt 5 / 5 = inverse (sqrt 5)" by (simp add: field_simps) - also have "(\ ^ (2*n+1) - \ ^ (2*n+1)) * ... = of_nat (fib (Suc (2*n)))" + also have "1 + sqrt 5 > 0" + by (auto intro: add_pos_pos) + then have "\ + inverse \ = sqrt 5" + by (simp add: \_def field_simps) + also have "\ + inverse \ = -sqrt 5" + by (simp add: \_def field_simps) + also have "(\ ^ (2 * n + 1) * sqrt 5 + \ ^ (2 * n + 1) * - sqrt 5) / 5 = + (\ ^ (2 * n + 1) - \ ^ (2 * n + 1)) * (sqrt 5 / 5)" + by (simp add: field_simps) + also have "sqrt 5 / 5 = inverse (sqrt 5)" + by (simp add: field_simps) + also have "(\ ^ (2 * n + 1) - \ ^ (2 * n + 1)) * \ = of_nat (fib (Suc (2 * n)))" by (simp add: fib_closed_form[folded \_def \_def] divide_inverse) - finally show ?thesis by (simp only: of_nat_eq_iff) + finally show ?thesis + by (simp only: of_nat_eq_iff) qed -lemma fib_rec_even: "fib (2*n) = (fib (n - 1) + fib (n + 1)) * fib n" -proof (induction n) +lemma fib_rec_even: "fib (2 * n) = (fib (n - 1) + fib (n + 1)) * fib n" +proof (induct n) + case 0 + then show ?case by simp +next case (Suc n) let ?rfib = "\x. real (fib x)" - have "2 * (Suc n) = Suc (Suc (2*n))" by simp - also have "real (fib ...) = ?rfib n^2 + ?rfib (Suc n)^2 + (?rfib (n - 1) + ?rfib (n + 1)) * ?rfib n" + have "2 * (Suc n) = Suc (Suc (2 * n))" by simp + also have "real (fib \) = ?rfib n^2 + ?rfib (Suc n)^2 + (?rfib (n - 1) + ?rfib (n + 1)) * ?rfib n" by (simp add: fib_rec_odd Suc) also have "(?rfib (n - 1) + ?rfib (n + 1)) * ?rfib n = (2 * ?rfib (n + 1) - ?rfib n) * ?rfib n" by (cases n) simp_all - also have "?rfib n^2 + ?rfib (Suc n)^2 + ... = (?rfib (Suc n) + 2 * ?rfib n) * ?rfib (Suc n)" + also have "?rfib n^2 + ?rfib (Suc n)^2 + \ = (?rfib (Suc n) + 2 * ?rfib n) * ?rfib (Suc n)" by (simp add: algebra_simps power2_eq_square) - also have "... = real ((fib (Suc n - 1) + fib (Suc n + 1)) * fib (Suc n))" by simp + also have "\ = real ((fib (Suc n - 1) + fib (Suc n + 1)) * fib (Suc n))" by simp finally show ?case by (simp only: of_nat_eq_iff) -qed simp +qed -lemma fib_rec_even': "fib (2*n) = (2*fib (n - 1) + fib n) * fib n" +lemma fib_rec_even': "fib (2 * n) = (2 * fib (n - 1) + fib n) * fib n" by (subst fib_rec_even, cases n) simp_all lemma fib_rec: - "fib n = (if n = 0 then 0 else if n = 1 then 1 else - if even n then let n' = n div 2; fn = fib n' in (2 * fib (n' - 1) + fn) * fn - else let n' = n div 2 in fib n' ^ 2 + fib (Suc n') ^ 2)" + "fib n = + (if n = 0 then 0 else if n = 1 then 1 + else if even n then let n' = n div 2; fn = fib n' in (2 * fib (n' - 1) + fn) * fn + else let n' = n div 2 in fib n' ^ 2 + fib (Suc n') ^ 2)" by (auto elim: evenE oddE simp: fib_rec_odd fib_rec_even' Let_def) @@ -247,7 +266,8 @@ by (induct n) auto lemma sum_choose_drop_zero: - "(\k = 0..Suc n. if k=0 then 0 else (Suc n - k) choose (k - 1)) = (\j = 0..n. (n-j) choose j)" + "(\k = 0..Suc n. if k = 0 then 0 else (Suc n - k) choose (k - 1)) = + (\j = 0..n. (n-j) choose j)" by (rule trans [OF sum.cong sum_drop_zero]) auto lemma ne_diagonal_fib: "(\k = 0..n. (n-k) choose k) = fib (Suc n)" @@ -260,17 +280,16 @@ next case (3 n) have "(\k = 0..Suc n. Suc (Suc n) - k choose k) = - (\k = 0..Suc n. (Suc n - k choose k) + (if k=0 then 0 else (Suc n - k choose (k - 1))))" + (\k = 0..Suc n. (Suc n - k choose k) + (if k = 0 then 0 else (Suc n - k choose (k - 1))))" by (rule sum.cong) (simp_all add: choose_reduce_nat) - also have "\ = (\k = 0..Suc n. Suc n - k choose k) + - (\k = 0..Suc n. if k=0 then 0 else (Suc n - k choose (k - 1)))" + also have "\ = + (\k = 0..Suc n. Suc n - k choose k) + + (\k = 0..Suc n. if k=0 then 0 else (Suc n - k choose (k - 1)))" by (simp add: sum.distrib) - also have "\ = (\k = 0..Suc n. Suc n - k choose k) + - (\j = 0..n. n - j choose j)" + also have "\ = (\k = 0..Suc n. Suc n - k choose k) + (\j = 0..n. n - j choose j)" by (metis sum_choose_drop_zero) finally show ?case using 3 by simp qed end -