# HG changeset patch # User haftmann # Date 1494568415 -7200 # Node ID 04ba6d530c87f5eeb6ddf391ae863ad19930fbca # Parent 2653f1cd8775ea4bcb2fde75c3555f61d60e2d95 explicit theory for factorials diff -r 2653f1cd8775 -r 04ba6d530c87 src/HOL/Binomial.thy --- a/src/HOL/Binomial.thy Thu May 11 16:47:53 2017 +0200 +++ b/src/HOL/Binomial.thy Fri May 12 07:53:35 2017 +0200 @@ -6,180 +6,12 @@ Author: Manuel Eberl *) -section \Combinatorial Functions: Factorial Function, Rising Factorials, Binomial Coefficients and Binomial Theorem\ +section \Binomial Coefficients and Binomial Theorem\ theory Binomial - imports Pre_Main -begin - -subsection \Factorial\ - -context semiring_char_0 -begin - -definition fact :: "nat \ 'a" - where fact_prod: "fact n = of_nat (\{1..n})" - -lemma fact_prod_Suc: "fact n = of_nat (prod Suc {0..i = 0..i. i" 1 n] - by (cases n) - (simp_all add: fact_prod_Suc prod.atLeast_Suc_atMost_Suc_shift - atLeastLessThanSuc_atLeastAtMost) - -lemma fact_0 [simp]: "fact 0 = 1" - by (simp add: fact_prod) - -lemma fact_1 [simp]: "fact 1 = 1" - by (simp add: fact_prod) - -lemma fact_Suc_0 [simp]: "fact (Suc 0) = 1" - by (simp add: fact_prod) - -lemma fact_Suc [simp]: "fact (Suc n) = of_nat (Suc n) * fact n" - by (simp add: fact_prod atLeastAtMostSuc_conv algebra_simps) - -lemma fact_2 [simp]: "fact 2 = 2" - by (simp add: numeral_2_eq_2) - -lemma fact_split: "k \ n \ fact n = of_nat (prod Suc {n - k.. 0 \ fact n = of_nat n * fact (n - 1)" - by (cases n) auto - -lemma fact_nonzero [simp]: "fact n \ (0::'a::{semiring_char_0,semiring_no_zero_divisors})" - apply (induct n) - apply auto - using of_nat_eq_0_iff - apply fastforce - done - -lemma fact_mono_nat: "m \ n \ fact m \ (fact n :: nat)" - by (induct n) (auto simp: le_Suc_eq) - -lemma fact_in_Nats: "fact n \ \" - by (induct n) auto - -lemma fact_in_Ints: "fact n \ \" - by (induct n) auto - -context - assumes "SORT_CONSTRAINT('a::linordered_semidom)" + imports Factorial begin -lemma fact_mono: "m \ n \ fact m \ (fact n :: 'a)" - by (metis of_nat_fact of_nat_le_iff fact_mono_nat) - -lemma fact_ge_1 [simp]: "fact n \ (1 :: 'a)" - by (metis le0 fact_0 fact_mono) - -lemma fact_gt_zero [simp]: "fact n > (0 :: 'a)" - using fact_ge_1 less_le_trans zero_less_one by blast - -lemma fact_ge_zero [simp]: "fact n \ (0 :: 'a)" - by (simp add: less_imp_le) - -lemma fact_not_neg [simp]: "\ fact n < (0 :: 'a)" - by (simp add: not_less_iff_gr_or_eq) - -lemma fact_le_power: "fact n \ (of_nat (n^n) :: 'a)" -proof (induct n) - case 0 - then show ?case by simp -next - case (Suc n) - then have *: "fact n \ (of_nat (Suc n ^ n) ::'a)" - by (rule order_trans) (simp add: power_mono del: of_nat_power) - have "fact (Suc n) = (of_nat (Suc n) * fact n ::'a)" - by (simp add: algebra_simps) - also have "\ \ of_nat (Suc n) * of_nat (Suc n ^ n)" - by (simp add: * ordered_comm_semiring_class.comm_mult_left_mono del: of_nat_power) - also have "\ \ of_nat (Suc n ^ Suc n)" - by (metis of_nat_mult order_refl power_Suc) - finally show ?case . -qed - -end - -text \Note that @{term "fact 0 = fact 1"}\ -lemma fact_less_mono_nat: "0 < m \ m < n \ fact m < (fact n :: nat)" - by (induct n) (auto simp: less_Suc_eq) - -lemma fact_less_mono: "0 < m \ m < n \ fact m < (fact n :: 'a::linordered_semidom)" - by (metis of_nat_fact of_nat_less_iff fact_less_mono_nat) - -lemma fact_ge_Suc_0_nat [simp]: "fact n \ Suc 0" - by (metis One_nat_def fact_ge_1) - -lemma dvd_fact: "1 \ m \ m \ n \ m dvd fact n" - by (induct n) (auto simp: dvdI le_Suc_eq) - -lemma fact_ge_self: "fact n \ n" - by (cases "n = 0") (simp_all add: dvd_imp_le dvd_fact) - -lemma fact_dvd: "n \ m \ fact n dvd (fact m :: 'a::{semiring_div,linordered_semidom})" - by (induct m) (auto simp: le_Suc_eq) - -lemma fact_mod: "m \ n \ fact n mod (fact m :: 'a::{semiring_div,linordered_semidom}) = 0" - by (auto simp add: fact_dvd) - -lemma fact_div_fact: - assumes "m \ n" - shows "fact m div fact n = \{n + 1..m}" -proof - - obtain d where "d = m - n" - by auto - with assms have "m = n + d" - by auto - have "fact (n + d) div (fact n) = \{n + 1..n + d}" - proof (induct d) - case 0 - show ?case by simp - next - case (Suc d') - have "fact (n + Suc d') div fact n = Suc (n + d') * fact (n + d') div fact n" - by simp - also from Suc.hyps have "\ = Suc (n + d') * \{n + 1..n + d'}" - unfolding div_mult1_eq[of _ "fact (n + d')"] by (simp add: fact_mod) - also have "\ = \{n + 1..n + Suc d'}" - by (simp add: atLeastAtMostSuc_conv) - finally show ?case . - qed - with \m = n + d\ show ?thesis by simp -qed - -lemma fact_num_eq_if: "fact m = (if m = 0 then 1 else of_nat m * fact (m - 1))" - by (cases m) auto - -lemma fact_div_fact_le_pow: - assumes "r \ n" - shows "fact n div fact (n - r) \ n ^ r" -proof - - have "r \ n \ \{n - r..n} = (n - r) * \{Suc (n - r)..n}" for r - by (subst prod.insert[symmetric]) (auto simp: atLeastAtMost_insertL) - with assms show ?thesis - by (induct r rule: nat.induct) (auto simp add: fact_div_fact Suc_diff_Suc mult_le_mono) -qed - -lemma fact_numeral: "fact (numeral k) = numeral k * fact (pred_numeral k)" - \ \Evaluation for specific numerals\ - by (metis fact_Suc numeral_eq_Suc of_nat_numeral) - - subsection \Binomial coefficients\ text \This development is based on the work of Andy Gordon and Florian Kammueller.\ @@ -500,208 +332,6 @@ qed -subsection \Pochhammer's symbol: generalized rising factorial\ - -text \See \<^url>\http://en.wikipedia.org/wiki/Pochhammer_symbol\.\ - -context comm_semiring_1 -begin - -definition pochhammer :: "'a \ nat \ 'a" - where pochhammer_prod: "pochhammer a n = prod (\i. a + of_nat i) {0..i. a + of_nat (n - i)) {1..n}" - using prod.atLeast_lessThan_rev_at_least_Suc_atMost [of "\i. a + of_nat i" 0 n] - by (simp add: pochhammer_prod) - -lemma pochhammer_Suc_prod: "pochhammer a (Suc n) = prod (\i. a + of_nat i) {0..n}" - by (simp add: pochhammer_prod atLeastLessThanSuc_atLeastAtMost) - -lemma pochhammer_Suc_prod_rev: "pochhammer a (Suc n) = prod (\i. a + of_nat (n - i)) {0..n}" - by (simp add: pochhammer_prod_rev prod.atLeast_Suc_atMost_Suc_shift) - -lemma pochhammer_0 [simp]: "pochhammer a 0 = 1" - by (simp add: pochhammer_prod) - -lemma pochhammer_1 [simp]: "pochhammer a 1 = a" - by (simp add: pochhammer_prod lessThan_Suc) - -lemma pochhammer_Suc0 [simp]: "pochhammer a (Suc 0) = a" - by (simp add: pochhammer_prod lessThan_Suc) - -lemma pochhammer_Suc: "pochhammer a (Suc n) = pochhammer a n * (a + of_nat n)" - by (simp add: pochhammer_prod atLeast0_lessThan_Suc ac_simps) - -end - -lemma pochhammer_nonneg: - fixes x :: "'a :: linordered_semidom" - shows "x > 0 \ pochhammer x n \ 0" - by (induction n) (auto simp: pochhammer_Suc intro!: mult_nonneg_nonneg add_nonneg_nonneg) - -lemma pochhammer_pos: - fixes x :: "'a :: linordered_semidom" - shows "x > 0 \ pochhammer x n > 0" - by (induction n) (auto simp: pochhammer_Suc intro!: mult_pos_pos add_pos_nonneg) - -lemma pochhammer_of_nat: "pochhammer (of_nat x) n = of_nat (pochhammer x n)" - by (simp add: pochhammer_prod) - -lemma pochhammer_of_int: "pochhammer (of_int x) n = of_int (pochhammer x n)" - by (simp add: pochhammer_prod) - -lemma pochhammer_rec: "pochhammer a (Suc n) = a * pochhammer (a + 1) n" - by (simp add: pochhammer_prod prod.atLeast0_lessThan_Suc_shift ac_simps) - -lemma pochhammer_rec': "pochhammer z (Suc n) = (z + of_nat n) * pochhammer z n" - by (simp add: pochhammer_prod prod.atLeast0_lessThan_Suc ac_simps) - -lemma pochhammer_fact: "fact n = pochhammer 1 n" - by (simp add: pochhammer_prod fact_prod_Suc) - -lemma pochhammer_of_nat_eq_0_lemma: "k > n \ pochhammer (- (of_nat n :: 'a:: idom)) k = 0" - by (auto simp add: pochhammer_prod) - -lemma pochhammer_of_nat_eq_0_lemma': - assumes kn: "k \ n" - shows "pochhammer (- (of_nat n :: 'a::{idom,ring_char_0})) k \ 0" -proof (cases k) - case 0 - then show ?thesis by simp -next - case (Suc h) - then show ?thesis - apply (simp add: pochhammer_Suc_prod) - using Suc kn - apply (auto simp add: algebra_simps) - done -qed - -lemma pochhammer_of_nat_eq_0_iff: - "pochhammer (- (of_nat n :: 'a::{idom,ring_char_0})) k = 0 \ k > n" - (is "?l = ?r") - using pochhammer_of_nat_eq_0_lemma[of n k, where ?'a='a] - pochhammer_of_nat_eq_0_lemma'[of k n, where ?'a = 'a] - by (auto simp add: not_le[symmetric]) - -lemma pochhammer_eq_0_iff: "pochhammer a n = (0::'a::field_char_0) \ (\k < n. a = - of_nat k)" - by (auto simp add: pochhammer_prod eq_neg_iff_add_eq_0) - -lemma pochhammer_eq_0_mono: - "pochhammer a n = (0::'a::field_char_0) \ m \ n \ pochhammer a m = 0" - unfolding pochhammer_eq_0_iff by auto - -lemma pochhammer_neq_0_mono: - "pochhammer a m \ (0::'a::field_char_0) \ m \ n \ pochhammer a n \ 0" - unfolding pochhammer_eq_0_iff by auto - -lemma pochhammer_minus: - "pochhammer (- b) k = ((- 1) ^ k :: 'a::comm_ring_1) * pochhammer (b - of_nat k + 1) k" -proof (cases k) - case 0 - then show ?thesis by simp -next - case (Suc h) - have eq: "((- 1) ^ Suc h :: 'a) = (\i = 0..h. - 1)" - using prod_constant [where A="{0.. h}" and y="- 1 :: 'a"] - by auto - with Suc show ?thesis - using pochhammer_Suc_prod_rev [of "b - of_nat k + 1"] - by (auto simp add: pochhammer_Suc_prod prod.distrib [symmetric] eq of_nat_diff) -qed - -lemma pochhammer_minus': - "pochhammer (b - of_nat k + 1) k = ((- 1) ^ k :: 'a::comm_ring_1) * pochhammer (- b) k" - apply (simp only: pochhammer_minus [where b = b]) - apply (simp only: mult.assoc [symmetric]) - apply (simp only: power_add [symmetric]) - apply simp - done - -lemma pochhammer_same: "pochhammer (- of_nat n) n = - ((- 1) ^ n :: 'a::{semiring_char_0,comm_ring_1,semiring_no_zero_divisors}) * fact n" - unfolding pochhammer_minus - by (simp add: of_nat_diff pochhammer_fact) - -lemma pochhammer_product': "pochhammer z (n + m) = pochhammer z n * pochhammer (z + of_nat n) m" -proof (induct n arbitrary: z) - case 0 - then show ?case by simp -next - case (Suc n z) - have "pochhammer z (Suc n) * pochhammer (z + of_nat (Suc n)) m = - z * (pochhammer (z + 1) n * pochhammer (z + 1 + of_nat n) m)" - by (simp add: pochhammer_rec ac_simps) - also note Suc[symmetric] - also have "z * pochhammer (z + 1) (n + m) = pochhammer z (Suc (n + m))" - by (subst pochhammer_rec) simp - finally show ?case - by simp -qed - -lemma pochhammer_product: - "m \ n \ pochhammer z n = pochhammer z m * pochhammer (z + of_nat m) (n - m)" - using pochhammer_product'[of z m "n - m"] by simp - -lemma pochhammer_times_pochhammer_half: - fixes z :: "'a::field_char_0" - shows "pochhammer z (Suc n) * pochhammer (z + 1/2) (Suc n) = (\k=0..2*n+1. z + of_nat k / 2)" -proof (induct n) - case 0 - then show ?case - by (simp add: atLeast0_atMost_Suc) -next - case (Suc n) - define n' where "n' = Suc n" - have "pochhammer z (Suc n') * pochhammer (z + 1 / 2) (Suc n') = - (pochhammer z n' * pochhammer (z + 1 / 2) n') * ((z + of_nat n') * (z + 1/2 + of_nat n'))" - (is "_ = _ * ?A") - by (simp_all add: pochhammer_rec' mult_ac) - also have "?A = (z + of_nat (Suc (2 * n + 1)) / 2) * (z + of_nat (Suc (Suc (2 * n + 1))) / 2)" - (is "_ = ?B") - by (simp add: field_simps n'_def) - also note Suc[folded n'_def] - also have "(\k=0..2 * n + 1. z + of_nat k / 2) * ?B = (\k=0..2 * Suc n + 1. z + of_nat k / 2)" - by (simp add: atLeast0_atMost_Suc) - finally show ?case - by (simp add: n'_def) -qed - -lemma pochhammer_double: - fixes z :: "'a::field_char_0" - shows "pochhammer (2 * z) (2 * n) = of_nat (2^(2*n)) * pochhammer z n * pochhammer (z+1/2) n" -proof (induct n) - case 0 - then show ?case by simp -next - case (Suc n) - have "pochhammer (2 * z) (2 * (Suc n)) = pochhammer (2 * z) (2 * n) * - (2 * (z + of_nat n)) * (2 * (z + of_nat n) + 1)" - by (simp add: pochhammer_rec' ac_simps) - also note Suc - also have "of_nat (2 ^ (2 * n)) * pochhammer z n * pochhammer (z + 1/2) n * - (2 * (z + of_nat n)) * (2 * (z + of_nat n) + 1) = - of_nat (2 ^ (2 * (Suc n))) * pochhammer z (Suc n) * pochhammer (z + 1/2) (Suc n)" - by (simp add: field_simps pochhammer_rec') - finally show ?case . -qed - -lemma fact_double: - "fact (2 * n) = (2 ^ (2 * n) * pochhammer (1 / 2) n * fact n :: 'a::field_char_0)" - using pochhammer_double[of "1/2::'a" n] by (simp add: pochhammer_fact) - -lemma pochhammer_absorb_comp: "(r - of_nat k) * pochhammer (- r) k = r * pochhammer (-r + 1) k" - (is "?lhs = ?rhs") - for r :: "'a::comm_ring_1" -proof - - have "?lhs = - pochhammer (- r) (Suc k)" - by (subst pochhammer_rec') (simp add: algebra_simps) - also have "\ = ?rhs" - by (subst pochhammer_rec) simp - finally show ?thesis . -qed - - subsection \Generalized binomial coefficients\ definition gbinomial :: "'a::{semidom_divide,semiring_char_0} \ nat \ 'a" (infixl "gchoose" 65) @@ -1527,7 +1157,7 @@ let ?B' = "{l. length l = m \ sum_list l = N \ hd l \ 0}" let ?f = "\l. 0 # l" let ?g = "\l. (hd l + 1) # tl l" - have 1: "xs \ [] \ x = hd xs \ x # tl xs = xs" for x xs + have 1: "xs \ [] \ x = hd xs \ x # tl xs = xs" for x :: nat and xs by simp have 2: "xs \ [] \ sum_list(tl xs) = sum_list xs - hd xs" for xs :: "nat list" by (auto simp add: neq_Nil_conv) @@ -1660,26 +1290,6 @@ subsection \Misc\ -lemma fact_code [code]: - "fact n = (of_nat (fold_atLeastAtMost_nat (op *) 2 n 1) :: 'a::semiring_char_0)" -proof - - have "fact n = (of_nat (\{1..n}) :: 'a)" - by (simp add: fact_prod) - also have "\{1..n} = \{2..n}" - by (intro prod.mono_neutral_right) auto - also have "\ = fold_atLeastAtMost_nat (op *) 2 n 1" - by (simp add: prod_atLeastAtMost_code) - finally show ?thesis . -qed - -lemma pochhammer_code [code]: - "pochhammer a n = - (if n = 0 then 1 - else fold_atLeastAtMost_nat (\n acc. (a + of_nat n) * acc) 0 (n - 1) 1)" - by (cases n) - (simp_all add: pochhammer_prod prod_atLeastAtMost_code [symmetric] - atLeastLessThanSuc_atLeastAtMost) - lemma gbinomial_code [code]: "a gchoose n = (if n = 0 then 1 @@ -1688,7 +1298,7 @@ (simp_all add: gbinomial_prod_rev prod_atLeastAtMost_code [symmetric] atLeastLessThanSuc_atLeastAtMost) -lemmas [code del] = binomial_Suc_Suc binomial_n_0 binomial_0_Suc +declare [[code drop: binomial]] lemma binomial_code [code]: "(n choose k) = diff -r 2653f1cd8775 -r 04ba6d530c87 src/HOL/Factorial.thy --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/HOL/Factorial.thy Fri May 12 07:53:35 2017 +0200 @@ -0,0 +1,407 @@ +(* Title: HOL/Factoiral.thy + Author: Jacques D. Fleuriot + Author: Lawrence C Paulson + Author: Jeremy Avigad + Author: Chaitanya Mangla + Author: Manuel Eberl +*) + +section \Factorial Function, Rising Factorials\ + +theory Factorial + imports Pre_Main +begin + +subsection \Factorial Function\ + +context semiring_char_0 +begin + +definition fact :: "nat \ 'a" + where fact_prod: "fact n = of_nat (\{1..n})" + +lemma fact_prod_Suc: "fact n = of_nat (prod Suc {0..i = 0..i. i" 1 n] + by (cases n) + (simp_all add: fact_prod_Suc prod.atLeast_Suc_atMost_Suc_shift + atLeastLessThanSuc_atLeastAtMost) + +lemma fact_0 [simp]: "fact 0 = 1" + by (simp add: fact_prod) + +lemma fact_1 [simp]: "fact 1 = 1" + by (simp add: fact_prod) + +lemma fact_Suc_0 [simp]: "fact (Suc 0) = 1" + by (simp add: fact_prod) + +lemma fact_Suc [simp]: "fact (Suc n) = of_nat (Suc n) * fact n" + by (simp add: fact_prod atLeastAtMostSuc_conv algebra_simps) + +lemma fact_2 [simp]: "fact 2 = 2" + by (simp add: numeral_2_eq_2) + +lemma fact_split: "k \ n \ fact n = of_nat (prod Suc {n - k.. 0 \ fact n = of_nat n * fact (n - 1)" + by (cases n) auto + +lemma fact_nonzero [simp]: "fact n \ (0::'a::{semiring_char_0,semiring_no_zero_divisors})" + apply (induct n) + apply auto + using of_nat_eq_0_iff + apply fastforce + done + +lemma fact_mono_nat: "m \ n \ fact m \ (fact n :: nat)" + by (induct n) (auto simp: le_Suc_eq) + +lemma fact_in_Nats: "fact n \ \" + by (induct n) auto + +lemma fact_in_Ints: "fact n \ \" + by (induct n) auto + +context + assumes "SORT_CONSTRAINT('a::linordered_semidom)" +begin + +lemma fact_mono: "m \ n \ fact m \ (fact n :: 'a)" + by (metis of_nat_fact of_nat_le_iff fact_mono_nat) + +lemma fact_ge_1 [simp]: "fact n \ (1 :: 'a)" + by (metis le0 fact_0 fact_mono) + +lemma fact_gt_zero [simp]: "fact n > (0 :: 'a)" + using fact_ge_1 less_le_trans zero_less_one by blast + +lemma fact_ge_zero [simp]: "fact n \ (0 :: 'a)" + by (simp add: less_imp_le) + +lemma fact_not_neg [simp]: "\ fact n < (0 :: 'a)" + by (simp add: not_less_iff_gr_or_eq) + +lemma fact_le_power: "fact n \ (of_nat (n^n) :: 'a)" +proof (induct n) + case 0 + then show ?case by simp +next + case (Suc n) + then have *: "fact n \ (of_nat (Suc n ^ n) ::'a)" + by (rule order_trans) (simp add: power_mono del: of_nat_power) + have "fact (Suc n) = (of_nat (Suc n) * fact n ::'a)" + by (simp add: algebra_simps) + also have "\ \ of_nat (Suc n) * of_nat (Suc n ^ n)" + by (simp add: * ordered_comm_semiring_class.comm_mult_left_mono del: of_nat_power) + also have "\ \ of_nat (Suc n ^ Suc n)" + by (metis of_nat_mult order_refl power_Suc) + finally show ?case . +qed + +end + +lemma fact_less_mono_nat: "0 < m \ m < n \ fact m < (fact n :: nat)" + by (induct n) (auto simp: less_Suc_eq) + +lemma fact_less_mono: "0 < m \ m < n \ fact m < (fact n :: 'a::linordered_semidom)" + by (metis of_nat_fact of_nat_less_iff fact_less_mono_nat) + +lemma fact_ge_Suc_0_nat [simp]: "fact n \ Suc 0" + by (metis One_nat_def fact_ge_1) + +lemma dvd_fact: "1 \ m \ m \ n \ m dvd fact n" + by (induct n) (auto simp: dvdI le_Suc_eq) + +lemma fact_ge_self: "fact n \ n" + by (cases "n = 0") (simp_all add: dvd_imp_le dvd_fact) + +lemma fact_dvd: "n \ m \ fact n dvd (fact m :: 'a::{semiring_div,linordered_semidom})" + by (induct m) (auto simp: le_Suc_eq) + +lemma fact_mod: "m \ n \ fact n mod (fact m :: 'a::{semiring_div,linordered_semidom}) = 0" + by (auto simp add: fact_dvd) + +lemma fact_div_fact: + assumes "m \ n" + shows "fact m div fact n = \{n + 1..m}" +proof - + obtain d where "d = m - n" + by auto + with assms have "m = n + d" + by auto + have "fact (n + d) div (fact n) = \{n + 1..n + d}" + proof (induct d) + case 0 + show ?case by simp + next + case (Suc d') + have "fact (n + Suc d') div fact n = Suc (n + d') * fact (n + d') div fact n" + by simp + also from Suc.hyps have "\ = Suc (n + d') * \{n + 1..n + d'}" + unfolding div_mult1_eq[of _ "fact (n + d')"] by (simp add: fact_mod) + also have "\ = \{n + 1..n + Suc d'}" + by (simp add: atLeastAtMostSuc_conv) + finally show ?case . + qed + with \m = n + d\ show ?thesis by simp +qed + +lemma fact_num_eq_if: "fact m = (if m = 0 then 1 else of_nat m * fact (m - 1))" + by (cases m) auto + +lemma fact_div_fact_le_pow: + assumes "r \ n" + shows "fact n div fact (n - r) \ n ^ r" +proof - + have "r \ n \ \{n - r..n} = (n - r) * \{Suc (n - r)..n}" for r + by (subst prod.insert[symmetric]) (auto simp: atLeastAtMost_insertL) + with assms show ?thesis + by (induct r rule: nat.induct) (auto simp add: fact_div_fact Suc_diff_Suc mult_le_mono) +qed + +lemma fact_numeral: "fact (numeral k) = numeral k * fact (pred_numeral k)" + \ \Evaluation for specific numerals\ + by (metis fact_Suc numeral_eq_Suc of_nat_numeral) + + + +subsection \Pochhammer's symbol: generalized rising factorial\ + +text \See \<^url>\http://en.wikipedia.org/wiki/Pochhammer_symbol\.\ + +context comm_semiring_1 +begin + +definition pochhammer :: "'a \ nat \ 'a" + where pochhammer_prod: "pochhammer a n = prod (\i. a + of_nat i) {0..i. a + of_nat (n - i)) {1..n}" + using prod.atLeast_lessThan_rev_at_least_Suc_atMost [of "\i. a + of_nat i" 0 n] + by (simp add: pochhammer_prod) + +lemma pochhammer_Suc_prod: "pochhammer a (Suc n) = prod (\i. a + of_nat i) {0..n}" + by (simp add: pochhammer_prod atLeastLessThanSuc_atLeastAtMost) + +lemma pochhammer_Suc_prod_rev: "pochhammer a (Suc n) = prod (\i. a + of_nat (n - i)) {0..n}" + by (simp add: pochhammer_prod_rev prod.atLeast_Suc_atMost_Suc_shift) + +lemma pochhammer_0 [simp]: "pochhammer a 0 = 1" + by (simp add: pochhammer_prod) + +lemma pochhammer_1 [simp]: "pochhammer a 1 = a" + by (simp add: pochhammer_prod lessThan_Suc) + +lemma pochhammer_Suc0 [simp]: "pochhammer a (Suc 0) = a" + by (simp add: pochhammer_prod lessThan_Suc) + +lemma pochhammer_Suc: "pochhammer a (Suc n) = pochhammer a n * (a + of_nat n)" + by (simp add: pochhammer_prod atLeast0_lessThan_Suc ac_simps) + +end + +lemma pochhammer_nonneg: + fixes x :: "'a :: linordered_semidom" + shows "x > 0 \ pochhammer x n \ 0" + by (induction n) (auto simp: pochhammer_Suc intro!: mult_nonneg_nonneg add_nonneg_nonneg) + +lemma pochhammer_pos: + fixes x :: "'a :: linordered_semidom" + shows "x > 0 \ pochhammer x n > 0" + by (induction n) (auto simp: pochhammer_Suc intro!: mult_pos_pos add_pos_nonneg) + +lemma pochhammer_of_nat: "pochhammer (of_nat x) n = of_nat (pochhammer x n)" + by (simp add: pochhammer_prod) + +lemma pochhammer_of_int: "pochhammer (of_int x) n = of_int (pochhammer x n)" + by (simp add: pochhammer_prod) + +lemma pochhammer_rec: "pochhammer a (Suc n) = a * pochhammer (a + 1) n" + by (simp add: pochhammer_prod prod.atLeast0_lessThan_Suc_shift ac_simps) + +lemma pochhammer_rec': "pochhammer z (Suc n) = (z + of_nat n) * pochhammer z n" + by (simp add: pochhammer_prod prod.atLeast0_lessThan_Suc ac_simps) + +lemma pochhammer_fact: "fact n = pochhammer 1 n" + by (simp add: pochhammer_prod fact_prod_Suc) + +lemma pochhammer_of_nat_eq_0_lemma: "k > n \ pochhammer (- (of_nat n :: 'a:: idom)) k = 0" + by (auto simp add: pochhammer_prod) + +lemma pochhammer_of_nat_eq_0_lemma': + assumes kn: "k \ n" + shows "pochhammer (- (of_nat n :: 'a::{idom,ring_char_0})) k \ 0" +proof (cases k) + case 0 + then show ?thesis by simp +next + case (Suc h) + then show ?thesis + apply (simp add: pochhammer_Suc_prod) + using Suc kn + apply (auto simp add: algebra_simps) + done +qed + +lemma pochhammer_of_nat_eq_0_iff: + "pochhammer (- (of_nat n :: 'a::{idom,ring_char_0})) k = 0 \ k > n" + (is "?l = ?r") + using pochhammer_of_nat_eq_0_lemma[of n k, where ?'a='a] + pochhammer_of_nat_eq_0_lemma'[of k n, where ?'a = 'a] + by (auto simp add: not_le[symmetric]) + +lemma pochhammer_eq_0_iff: "pochhammer a n = (0::'a::field_char_0) \ (\k < n. a = - of_nat k)" + by (auto simp add: pochhammer_prod eq_neg_iff_add_eq_0) + +lemma pochhammer_eq_0_mono: + "pochhammer a n = (0::'a::field_char_0) \ m \ n \ pochhammer a m = 0" + unfolding pochhammer_eq_0_iff by auto + +lemma pochhammer_neq_0_mono: + "pochhammer a m \ (0::'a::field_char_0) \ m \ n \ pochhammer a n \ 0" + unfolding pochhammer_eq_0_iff by auto + +lemma pochhammer_minus: + "pochhammer (- b) k = ((- 1) ^ k :: 'a::comm_ring_1) * pochhammer (b - of_nat k + 1) k" +proof (cases k) + case 0 + then show ?thesis by simp +next + case (Suc h) + have eq: "((- 1) ^ Suc h :: 'a) = (\i = 0..h. - 1)" + using prod_constant [where A="{0.. h}" and y="- 1 :: 'a"] + by auto + with Suc show ?thesis + using pochhammer_Suc_prod_rev [of "b - of_nat k + 1"] + by (auto simp add: pochhammer_Suc_prod prod.distrib [symmetric] eq of_nat_diff) +qed + +lemma pochhammer_minus': + "pochhammer (b - of_nat k + 1) k = ((- 1) ^ k :: 'a::comm_ring_1) * pochhammer (- b) k" + apply (simp only: pochhammer_minus [where b = b]) + apply (simp only: mult.assoc [symmetric]) + apply (simp only: power_add [symmetric]) + apply simp + done + +lemma pochhammer_same: "pochhammer (- of_nat n) n = + ((- 1) ^ n :: 'a::{semiring_char_0,comm_ring_1,semiring_no_zero_divisors}) * fact n" + unfolding pochhammer_minus + by (simp add: of_nat_diff pochhammer_fact) + +lemma pochhammer_product': "pochhammer z (n + m) = pochhammer z n * pochhammer (z + of_nat n) m" +proof (induct n arbitrary: z) + case 0 + then show ?case by simp +next + case (Suc n z) + have "pochhammer z (Suc n) * pochhammer (z + of_nat (Suc n)) m = + z * (pochhammer (z + 1) n * pochhammer (z + 1 + of_nat n) m)" + by (simp add: pochhammer_rec ac_simps) + also note Suc[symmetric] + also have "z * pochhammer (z + 1) (n + m) = pochhammer z (Suc (n + m))" + by (subst pochhammer_rec) simp + finally show ?case + by simp +qed + +lemma pochhammer_product: + "m \ n \ pochhammer z n = pochhammer z m * pochhammer (z + of_nat m) (n - m)" + using pochhammer_product'[of z m "n - m"] by simp + +lemma pochhammer_times_pochhammer_half: + fixes z :: "'a::field_char_0" + shows "pochhammer z (Suc n) * pochhammer (z + 1/2) (Suc n) = (\k=0..2*n+1. z + of_nat k / 2)" +proof (induct n) + case 0 + then show ?case + by (simp add: atLeast0_atMost_Suc) +next + case (Suc n) + define n' where "n' = Suc n" + have "pochhammer z (Suc n') * pochhammer (z + 1 / 2) (Suc n') = + (pochhammer z n' * pochhammer (z + 1 / 2) n') * ((z + of_nat n') * (z + 1/2 + of_nat n'))" + (is "_ = _ * ?A") + by (simp_all add: pochhammer_rec' mult_ac) + also have "?A = (z + of_nat (Suc (2 * n + 1)) / 2) * (z + of_nat (Suc (Suc (2 * n + 1))) / 2)" + (is "_ = ?B") + by (simp add: field_simps n'_def) + also note Suc[folded n'_def] + also have "(\k=0..2 * n + 1. z + of_nat k / 2) * ?B = (\k=0..2 * Suc n + 1. z + of_nat k / 2)" + by (simp add: atLeast0_atMost_Suc) + finally show ?case + by (simp add: n'_def) +qed + +lemma pochhammer_double: + fixes z :: "'a::field_char_0" + shows "pochhammer (2 * z) (2 * n) = of_nat (2^(2*n)) * pochhammer z n * pochhammer (z+1/2) n" +proof (induct n) + case 0 + then show ?case by simp +next + case (Suc n) + have "pochhammer (2 * z) (2 * (Suc n)) = pochhammer (2 * z) (2 * n) * + (2 * (z + of_nat n)) * (2 * (z + of_nat n) + 1)" + by (simp add: pochhammer_rec' ac_simps) + also note Suc + also have "of_nat (2 ^ (2 * n)) * pochhammer z n * pochhammer (z + 1/2) n * + (2 * (z + of_nat n)) * (2 * (z + of_nat n) + 1) = + of_nat (2 ^ (2 * (Suc n))) * pochhammer z (Suc n) * pochhammer (z + 1/2) (Suc n)" + by (simp add: field_simps pochhammer_rec') + finally show ?case . +qed + +lemma fact_double: + "fact (2 * n) = (2 ^ (2 * n) * pochhammer (1 / 2) n * fact n :: 'a::field_char_0)" + using pochhammer_double[of "1/2::'a" n] by (simp add: pochhammer_fact) + +lemma pochhammer_absorb_comp: "(r - of_nat k) * pochhammer (- r) k = r * pochhammer (-r + 1) k" + (is "?lhs = ?rhs") + for r :: "'a::comm_ring_1" +proof - + have "?lhs = - pochhammer (- r) (Suc k)" + by (subst pochhammer_rec') (simp add: algebra_simps) + also have "\ = ?rhs" + by (subst pochhammer_rec) simp + finally show ?thesis . +qed + + +subsection \Misc\ + +lemma fact_code [code]: + "fact n = (of_nat (fold_atLeastAtMost_nat (op *) 2 n 1) :: 'a::semiring_char_0)" +proof - + have "fact n = (of_nat (\{1..n}) :: 'a)" + by (simp add: fact_prod) + also have "\{1..n} = \{2..n}" + by (intro prod.mono_neutral_right) auto + also have "\ = fold_atLeastAtMost_nat (op *) 2 n 1" + by (simp add: prod_atLeastAtMost_code) + finally show ?thesis . +qed + +lemma pochhammer_code [code]: + "pochhammer a n = + (if n = 0 then 1 + else fold_atLeastAtMost_nat (\n acc. (a + of_nat n) * acc) 0 (n - 1) 1)" + by (cases n) + (simp_all add: pochhammer_prod prod_atLeastAtMost_code [symmetric] + atLeastLessThanSuc_atLeastAtMost) + +end