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
lemma fib_Suc_mono: "fib m \ fib (Suc m)" by(induction m) auto
lemma fib_mono: "m \ n \ fib m \ fib n" by (simp add: fib_Suc_mono lift_Suc_mono_le)
subsection \<open>More efficient code\<close>
text\<open>
The naive approach is very inefficient since the branching recursion leads to many
values of \<^term>\<open>fib\<close> 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
time required to multiply two $n$-bit integers), but much better than the naive version,
which is exponential. \<close>
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 (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 (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
declare fib_conv_gen_fib [code]
subsection \<open>A Few Elementary Results\<close>
text\<open> \<^medskip> Concrete Mathematics, page 278: Cassini's identity. The proof is
much easier using integers, not natural numbers! \<close>
lemma gcd_fib_add: "gcd (fib m) (fib (n + m)) = gcd (fib m) (fib n)" proof (cases m) case 0 thenshow ?thesis by simp next case (Suc q) from coprime_fib_Suc_nat [of q] have"coprime (fib (Suc q)) (fib q)" by (simp add: ac_simps) have"gcd (fib q) (fib (Suc q)) = Suc 0" using coprime_fib_Suc_nat [of q] by simp thenhave *: "gcd (fib n * fib q) (fib n * fib (Suc q)) = fib n" by (simp add: gcd_mult_distrib_nat [symmetric]) moreoverhave"gcd (fib (Suc q)) (fib n * fib q + fib (Suc n) * fib (Suc q)) =
gcd (fib (Suc q)) (fib n * fib q)" using gcd_add_mult [of "fib (Suc q)"] by (simp add: ac_simps) moreoverhave"gcd (fib (Suc q)) (fib n * fib (Suc q)) = fib (Suc q)" by simp ultimatelyshow ?thesis using Suc \<open>coprime (fib (Suc q)) (fib q)\<close> by (auto simp add: fib_add algebra_simps gcd_mult_right_right_cancel) qed
lemma gcd_fib_diff: "m \ n \ gcd (fib m) (fib (n - m)) = gcd (fib m) (fib n)" by (simp add: gcd_fib_add [symmetric, of _ "n-m"])
lemma gcd_fib_mod: "0 < m \ gcd (fib m) (fib (n mod m)) = gcd (fib m) (fib n)" proof (induct n rule: less_induct) case (less n) show"gcd (fib m) (fib (n mod m)) = gcd (fib m) (fib n)" proof (cases "m < n") case True thenhave"m \ n" by auto with\<open>0 < m\<close> have "0 < n" by auto with\<open>0 < m\<close> \<open>m < n\<close> 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]) (use\<open>m < n\<close> in auto) alsohave"\ = gcd (fib m) (fib (n - m))" by (simp add: less.hyps * \<open>0 < m\<close>) alsohave"\ = gcd (fib m) (fib n)" by (simp add: gcd_fib_diff \<open>m \<le> n\<close>) finallyshow"gcd (fib m) (fib (n mod m)) = gcd (fib m) (fib n)" . next case False thenshow"gcd (fib m) (fib (n mod m)) = gcd (fib m) (fib n)" by (cases "m = n") auto qed qed
lemma fib_gcd: "fib (gcd m n) = gcd (fib m) (fib n)"\<comment> \<open>Law 6.111\<close> 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)" by (induct n rule: nat.induct) (auto simp add: field_simps)
text\<open>
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 isthen actually spent on the
multiplication, since the output number is exponential in the input number. \<close>
lemma fib_rec: "fib n =
(if n = 0 then 0 else if n = 1 then 1
else if even n thenlet 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)
subsection \<open>Fibonacci and Binomial Coefficients\<close>
lemma sum_drop_zero: "(\k = 0..Suc n. if 0j = 0..n. f j)" 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)) =
(\<Sum>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)" proof (induct n rule: fib.induct) case 1 show ?caseby simp next case 2 show ?caseby simp next case (3 n) have"(\k = 0..Suc n. Suc (Suc n) - k choose k) =
(\<Sum>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) alsohave"\ =
(\<Sum>k = 0..Suc n. Suc n - k choose k) +
(\<Sum>k = 0..Suc n. if k=0 then 0 else (Suc n - k choose (k - 1)))" by (simp add: sum.distrib) alsohave"\ = (\k = 0..Suc n. Suc n - k choose k) + (\j = 0..n. n - j choose j)" by (metis sum_choose_drop_zero) finallyshow ?caseusing 3 by simp qed
end
¤ Dauer der Verarbeitung: 0.1 Sekunden
(vorverarbeitet)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung ist noch experimentell.