
paulson@15094: (*  Title       : Fact.thy
paulson@12196:     Author      : Jacques D. Fleuriot
paulson@12196:     Copyright   : 1998  University of Cambridge
paulson@15094:     Conversion to Isar and new proofs by Lawrence C Paulson, 2004
avigad@32036:     The integer version of factorial and other additions by Jeremy Avigad.
paulson@12196: *)
paulson@12196: 
paulson@15094: header{*Factorial Function*}
paulson@15094: 
nipkow@15131: theory Fact
haftmann@33319: imports Main
nipkow@15131: begin
paulson@15094: 
avigad@32036: class fact =
wenzelm@41550:   fixes fact :: "'a \<Rightarrow> 'a"
avigad@32036: 
avigad@32036: instantiation nat :: fact
avigad@32036: begin 
avigad@32036: 
avigad@32036: fun
avigad@32036:   fact_nat :: "nat \<Rightarrow> nat"
avigad@32036: where
avigad@32036:   fact_0_nat: "fact_nat 0 = Suc 0"
avigad@32047: | fact_Suc: "fact_nat (Suc x) = Suc x * fact x"
avigad@32036: 
wenzelm@41550: instance ..
avigad@32036: 
avigad@32036: end
avigad@32036: 
avigad@32036: (* definitions for the integers *)
avigad@32036: 
avigad@32036: instantiation int :: fact
avigad@32036: 
avigad@32036: begin 
avigad@32036: 
avigad@32036: definition
avigad@32036:   fact_int :: "int \<Rightarrow> int"
avigad@32036: where  
avigad@32036:   "fact_int x = (if x >= 0 then int (fact (nat x)) else 0)"
avigad@32036: 
avigad@32036: instance proof qed
avigad@32036: 
avigad@32036: end
avigad@32036: 
avigad@32036: 
avigad@32036: subsection {* Set up Transfer *}
avigad@32036: 
avigad@32036: lemma transfer_nat_int_factorial:
avigad@32036:   "(x::int) >= 0 \<Longrightarrow> fact (nat x) = nat (fact x)"
avigad@32036:   unfolding fact_int_def
avigad@32036:   by auto
avigad@32036: 
avigad@32036: 
avigad@32036: lemma transfer_nat_int_factorial_closure:
avigad@32036:   "x >= (0::int) \<Longrightarrow> fact x >= 0"
avigad@32036:   by (auto simp add: fact_int_def)
avigad@32036: 
haftmann@35644: declare transfer_morphism_nat_int[transfer add return: 
avigad@32036:     transfer_nat_int_factorial transfer_nat_int_factorial_closure]
avigad@32036: 
avigad@32036: lemma transfer_int_nat_factorial:
avigad@32036:   "fact (int x) = int (fact x)"
avigad@32036:   unfolding fact_int_def by auto
avigad@32036: 
avigad@32036: lemma transfer_int_nat_factorial_closure:
avigad@32036:   "is_nat x \<Longrightarrow> fact x >= 0"
avigad@32036:   by (auto simp add: fact_int_def)
avigad@32036: 
haftmann@35644: declare transfer_morphism_int_nat[transfer add return: 
avigad@32036:     transfer_int_nat_factorial transfer_int_nat_factorial_closure]
paulson@15094: 
paulson@15094: 
avigad@32036: subsection {* Factorial *}
avigad@32036: 
avigad@32036: lemma fact_0_int [simp]: "fact (0::int) = 1"
avigad@32036:   by (simp add: fact_int_def)
avigad@32036: 
avigad@32036: lemma fact_1_nat [simp]: "fact (1::nat) = 1"
avigad@32036:   by simp
avigad@32036: 
avigad@32036: lemma fact_Suc_0_nat [simp]: "fact (Suc 0) = Suc 0"
avigad@32036:   by simp
avigad@32036: 
avigad@32036: lemma fact_1_int [simp]: "fact (1::int) = 1"
avigad@32036:   by (simp add: fact_int_def)
avigad@32036: 
avigad@32036: lemma fact_plus_one_nat: "fact ((n::nat) + 1) = (n + 1) * fact n"
avigad@32036:   by simp
avigad@32036: 
avigad@32036: lemma fact_plus_one_int: 
avigad@32036:   assumes "n >= 0"
avigad@32036:   shows "fact ((n::int) + 1) = (n + 1) * fact n"
wenzelm@41550:   using assms unfolding fact_int_def 
avigad@32036:   by (simp add: nat_add_distrib algebra_simps int_mult)
avigad@32036: 
avigad@32036: lemma fact_reduce_nat: "(n::nat) > 0 \<Longrightarrow> fact n = n * fact (n - 1)"
avigad@32036:   apply (subgoal_tac "n = Suc (n - 1)")
avigad@32036:   apply (erule ssubst)
avigad@32047:   apply (subst fact_Suc)
avigad@32036:   apply simp_all
wenzelm@41550:   done
avigad@32036: 
avigad@32036: lemma fact_reduce_int: "(n::int) > 0 \<Longrightarrow> fact n = n * fact (n - 1)"
avigad@32036:   apply (subgoal_tac "n = (n - 1) + 1")
avigad@32036:   apply (erule ssubst)
avigad@32036:   apply (subst fact_plus_one_int)
avigad@32036:   apply simp_all
wenzelm@41550:   done
avigad@32036: 
avigad@32036: lemma fact_nonzero_nat [simp]: "fact (n::nat) \<noteq> 0"
avigad@32036:   apply (induct n)
avigad@32036:   apply (auto simp add: fact_plus_one_nat)
wenzelm@41550:   done
avigad@32036: 
avigad@32036: lemma fact_nonzero_int [simp]: "n >= 0 \<Longrightarrow> fact (n::int) ~= 0"
avigad@32036:   by (simp add: fact_int_def)
avigad@32036: 
avigad@32036: lemma fact_gt_zero_nat [simp]: "fact (n :: nat) > 0"
avigad@32036:   by (insert fact_nonzero_nat [of n], arith)
avigad@32036: 
avigad@32036: lemma fact_gt_zero_int [simp]: "n >= 0 \<Longrightarrow> fact (n :: int) > 0"
avigad@32036:   by (auto simp add: fact_int_def)
avigad@32036: 
avigad@32036: lemma fact_ge_one_nat [simp]: "fact (n :: nat) >= 1"
avigad@32036:   by (insert fact_nonzero_nat [of n], arith)
avigad@32036: 
avigad@32036: lemma fact_ge_Suc_0_nat [simp]: "fact (n :: nat) >= Suc 0"
avigad@32036:   by (insert fact_nonzero_nat [of n], arith)
avigad@32036: 
avigad@32036: lemma fact_ge_one_int [simp]: "n >= 0 \<Longrightarrow> fact (n :: int) >= 1"
avigad@32036:   apply (auto simp add: fact_int_def)
avigad@32036:   apply (subgoal_tac "1 = int 1")
avigad@32036:   apply (erule ssubst)
avigad@32036:   apply (subst zle_int)
avigad@32036:   apply auto
wenzelm@41550:   done
avigad@32036: 
avigad@32036: lemma dvd_fact_nat [rule_format]: "1 <= m \<longrightarrow> m <= n \<longrightarrow> m dvd fact (n::nat)"
avigad@32036:   apply (induct n)
avigad@32036:   apply force
avigad@32047:   apply (auto simp only: fact_Suc)
avigad@32036:   apply (subgoal_tac "m = Suc n")
avigad@32036:   apply (erule ssubst)
avigad@32036:   apply (rule dvd_triv_left)
avigad@32036:   apply auto
wenzelm@41550:   done
avigad@32036: 
avigad@32036: lemma dvd_fact_int [rule_format]: "1 <= m \<longrightarrow> m <= n \<longrightarrow> m dvd fact (n::int)"
avigad@32036:   apply (case_tac "1 <= n")
avigad@32036:   apply (induct n rule: int_ge_induct)
avigad@32036:   apply (auto simp add: fact_plus_one_int)
avigad@32036:   apply (subgoal_tac "m = i + 1")
avigad@32036:   apply auto
wenzelm@41550:   done
avigad@32036: 
avigad@32036: lemma interval_plus_one_nat: "(i::nat) <= j + 1 \<Longrightarrow> 
avigad@32036:   {i..j+1} = {i..j} Un {j+1}"
avigad@32036:   by auto
avigad@32036: 
avigad@32036: lemma interval_Suc: "i <= Suc j \<Longrightarrow> {i..Suc j} = {i..j} Un {Suc j}"
avigad@32036:   by auto
avigad@32036: 
avigad@32036: lemma interval_plus_one_int: "(i::int) <= j + 1 \<Longrightarrow> {i..j+1} = {i..j} Un {j+1}"
avigad@32036:   by auto
paulson@15094: 
avigad@32036: lemma fact_altdef_nat: "fact (n::nat) = (PROD i:{1..n}. i)"
avigad@32036:   apply (induct n)
avigad@32036:   apply force
avigad@32047:   apply (subst fact_Suc)
avigad@32036:   apply (subst interval_Suc)
avigad@32036:   apply auto
avigad@32036: done
avigad@32036: 
avigad@32036: lemma fact_altdef_int: "n >= 0 \<Longrightarrow> fact (n::int) = (PROD i:{1..n}. i)"
avigad@32036:   apply (induct n rule: int_ge_induct)
avigad@32036:   apply force
avigad@32036:   apply (subst fact_plus_one_int, assumption)
avigad@32036:   apply (subst interval_plus_one_int)
avigad@32036:   apply auto
avigad@32036: done
avigad@32036: 
bulwahn@40033: lemma fact_dvd: "n \<le> m \<Longrightarrow> fact n dvd fact (m::nat)"
bulwahn@40033:   by (auto simp add: fact_altdef_nat intro!: setprod_dvd_setprod_subset)
bulwahn@40033: 
bulwahn@40033: lemma fact_mod: "m \<le> (n::nat) \<Longrightarrow> fact n mod fact m = 0"
bulwahn@40033:   by (auto simp add: dvd_imp_mod_0 fact_dvd)
bulwahn@40033: 
bulwahn@40033: lemma fact_div_fact:
bulwahn@40033:   assumes "m \<ge> (n :: nat)"
bulwahn@40033:   shows "(fact m) div (fact n) = \<Prod>{n + 1..m}"
bulwahn@40033: proof -
bulwahn@40033:   obtain d where "d = m - n" by auto
bulwahn@40033:   from assms this have "m = n + d" by auto
bulwahn@40033:   have "fact (n + d) div (fact n) = \<Prod>{n + 1..n + d}"
bulwahn@40033:   proof (induct d)
bulwahn@40033:     case 0
bulwahn@40033:     show ?case by simp
bulwahn@40033:   next
bulwahn@40033:     case (Suc d')
bulwahn@40033:     have "fact (n + Suc d') div fact n = Suc (n + d') * fact (n + d') div fact n"
bulwahn@40033:       by simp
bulwahn@40033:     also from Suc.hyps have "... = Suc (n + d') * \<Prod>{n + 1..n + d'}" 
bulwahn@40033:       unfolding div_mult1_eq[of _ "fact (n + d')"] by (simp add: fact_mod)
bulwahn@40033:     also have "... = \<Prod>{n + 1..n + Suc d'}"
bulwahn@40033:       by (simp add: atLeastAtMostSuc_conv setprod_insert)
bulwahn@40033:     finally show ?case .
bulwahn@40033:   qed
bulwahn@40033:   from this `m = n + d` show ?thesis by simp
bulwahn@40033: qed
bulwahn@40033: 
avigad@32036: lemma fact_mono_nat: "(m::nat) \<le> n \<Longrightarrow> fact m \<le> fact n"
avigad@32036: apply (drule le_imp_less_or_eq)
avigad@32036: apply (auto dest!: less_imp_Suc_add)
avigad@32036: apply (induct_tac k, auto)
avigad@32036: done
avigad@32036: 
avigad@32036: lemma fact_neg_int [simp]: "m < (0::int) \<Longrightarrow> fact m = 0"
avigad@32036:   unfolding fact_int_def by auto
avigad@32036: 
avigad@32036: lemma fact_ge_zero_int [simp]: "fact m >= (0::int)"
avigad@32036:   apply (case_tac "m >= 0")
avigad@32036:   apply auto
avigad@32036:   apply (frule fact_gt_zero_int)
avigad@32036:   apply arith
avigad@32036: done
avigad@32036: 
avigad@32036: lemma fact_mono_int_aux [rule_format]: "k >= (0::int) \<Longrightarrow> 
avigad@32036:     fact (m + k) >= fact m"
avigad@32036:   apply (case_tac "m < 0")
avigad@32036:   apply auto
avigad@32036:   apply (induct k rule: int_ge_induct)
avigad@32036:   apply auto
avigad@32036:   apply (subst add_assoc [symmetric])
avigad@32036:   apply (subst fact_plus_one_int)
avigad@32036:   apply auto
avigad@32036:   apply (erule order_trans)
avigad@32036:   apply (subst mult_le_cancel_right1)
avigad@32036:   apply (subgoal_tac "fact (m + i) >= 0")
avigad@32036:   apply arith
avigad@32036:   apply auto
avigad@32036: done
avigad@32036: 
avigad@32036: lemma fact_mono_int: "(m::int) <= n \<Longrightarrow> fact m <= fact n"
avigad@32036:   apply (insert fact_mono_int_aux [of "n - m" "m"])
avigad@32036:   apply auto
avigad@32036: done
avigad@32036: 
avigad@32036: text{*Note that @{term "fact 0 = fact 1"}*}
avigad@32036: lemma fact_less_mono_nat: "[| (0::nat) < m; m < n |] ==> fact m < fact n"
avigad@32036: apply (drule_tac m = m in less_imp_Suc_add, auto)
avigad@32036: apply (induct_tac k, auto)
avigad@32036: done
avigad@32036: 
avigad@32036: lemma fact_less_mono_int_aux: "k >= 0 \<Longrightarrow> (0::int) < m \<Longrightarrow>
avigad@32036:     fact m < fact ((m + 1) + k)"
avigad@32036:   apply (induct k rule: int_ge_induct)
avigad@32036:   apply (simp add: fact_plus_one_int)
avigad@32036:   apply (subst mult_less_cancel_right1)
avigad@32036:   apply (insert fact_gt_zero_int [of m], arith)
avigad@32036:   apply (subst (2) fact_reduce_int)
avigad@32036:   apply (auto simp add: add_ac)
avigad@32036:   apply (erule order_less_le_trans)
avigad@32036:   apply (subst mult_le_cancel_right1)
avigad@32036:   apply auto
avigad@32036:   apply (subgoal_tac "fact (i + (1 + m)) >= 0")
avigad@32036:   apply force
avigad@32036:   apply (rule fact_ge_zero_int)
avigad@32036: done
avigad@32036: 
avigad@32036: lemma fact_less_mono_int: "(0::int) < m \<Longrightarrow> m < n \<Longrightarrow> fact m < fact n"
avigad@32036:   apply (insert fact_less_mono_int_aux [of "n - (m + 1)" "m"])
avigad@32036:   apply auto
avigad@32036: done
avigad@32036: 
avigad@32036: lemma fact_num_eq_if_nat: "fact (m::nat) = 
avigad@32036:   (if m=0 then 1 else m * fact (m - 1))"
avigad@32036: by (cases m) auto
avigad@32036: 
avigad@32036: lemma fact_add_num_eq_if_nat:
avigad@32036:   "fact ((m::nat) + n) = (if m + n = 0 then 1 else (m + n) * fact (m + n - 1))"
avigad@32036: by (cases "m + n") auto
avigad@32036: 
avigad@32036: lemma fact_add_num_eq_if2_nat:
avigad@32036:   "fact ((m::nat) + n) = 
avigad@32036:     (if m = 0 then fact n else (m + n) * fact ((m - 1) + n))"
avigad@32036: by (cases m) auto
avigad@32036: 
avigad@32036: 
berghofe@32039: subsection {* @{term fact} and @{term of_nat} *}
paulson@15094: 
chaieb@29693: lemma of_nat_fact_not_zero [simp]: "of_nat (fact n) \<noteq> (0::'a::semiring_char_0)"
nipkow@25134: by auto
paulson@15094: 
haftmann@35028: lemma of_nat_fact_gt_zero [simp]: "(0::'a::{linordered_semidom}) < of_nat(fact n)" by auto
chaieb@29693: 
haftmann@35028: lemma of_nat_fact_ge_zero [simp]: "(0::'a::linordered_semidom) \<le> of_nat(fact n)"
nipkow@25134: by simp
paulson@15094: 
haftmann@35028: lemma inv_of_nat_fact_gt_zero [simp]: "(0::'a::linordered_field) < inverse (of_nat (fact n))"
nipkow@25134: by (auto simp add: positive_imp_inverse_positive)
paulson@15094: 
haftmann@35028: lemma inv_of_nat_fact_ge_zero [simp]: "(0::'a::linordered_field) \<le> inverse (of_nat (fact n))"
nipkow@25134: by (auto intro: order_less_imp_le)
paulson@15094: 
nipkow@15131: end




