# Theory Fact

Up to index of Isabelle/HOL

theory Fact
imports Main
`(*  Title       : Fact.thy    Author      : Jacques D. Fleuriot    Copyright   : 1998  University of Cambridge    Conversion to Isar and new proofs by Lawrence C Paulson, 2004    The integer version of factorial and other additions by Jeremy Avigad.*)header{*Factorial Function*}theory Factimports Mainbeginclass fact =  fixes fact :: "'a => 'a"instantiation nat :: factbegin fun  fact_nat :: "nat => nat"where  fact_0_nat: "fact_nat 0 = Suc 0"| fact_Suc: "fact_nat (Suc x) = Suc x * fact x"instance ..end(* definitions for the integers *)instantiation int :: factbegin definition  fact_int :: "int => int"where    "fact_int x = (if x >= 0 then int (fact (nat x)) else 0)"instance proof qedendsubsection {* Set up Transfer *}lemma transfer_nat_int_factorial:  "(x::int) >= 0 ==> fact (nat x) = nat (fact x)"  unfolding fact_int_def  by autolemma transfer_nat_int_factorial_closure:  "x >= (0::int) ==> fact x >= 0"  by (auto simp add: fact_int_def)declare transfer_morphism_nat_int[transfer add return:     transfer_nat_int_factorial transfer_nat_int_factorial_closure]lemma transfer_int_nat_factorial:  "fact (int x) = int (fact x)"  unfolding fact_int_def by autolemma transfer_int_nat_factorial_closure:  "is_nat x ==> fact x >= 0"  by (auto simp add: fact_int_def)declare transfer_morphism_int_nat[transfer add return:     transfer_int_nat_factorial transfer_int_nat_factorial_closure]subsection {* Factorial *}lemma fact_0_int [simp]: "fact (0::int) = 1"  by (simp add: fact_int_def)lemma fact_1_nat [simp]: "fact (1::nat) = 1"  by simplemma fact_Suc_0_nat [simp]: "fact (Suc 0) = Suc 0"  by simplemma fact_1_int [simp]: "fact (1::int) = 1"  by (simp add: fact_int_def)lemma fact_plus_one_nat: "fact ((n::nat) + 1) = (n + 1) * fact n"  by simplemma fact_plus_one_int:   assumes "n >= 0"  shows "fact ((n::int) + 1) = (n + 1) * fact n"  using assms unfolding fact_int_def   by (simp add: nat_add_distrib algebra_simps int_mult)lemma fact_reduce_nat: "(n::nat) > 0 ==> fact n = n * fact (n - 1)"  apply (subgoal_tac "n = Suc (n - 1)")  apply (erule ssubst)  apply (subst fact_Suc)  apply simp_all  donelemma fact_reduce_int: "(n::int) > 0 ==> fact n = n * fact (n - 1)"  apply (subgoal_tac "n = (n - 1) + 1")  apply (erule ssubst)  apply (subst fact_plus_one_int)  apply simp_all  donelemma fact_nonzero_nat [simp]: "fact (n::nat) ≠ 0"  apply (induct n)  apply (auto simp add: fact_plus_one_nat)  donelemma fact_nonzero_int [simp]: "n >= 0 ==> fact (n::int) ~= 0"  by (simp add: fact_int_def)lemma fact_gt_zero_nat [simp]: "fact (n :: nat) > 0"  by (insert fact_nonzero_nat [of n], arith)lemma fact_gt_zero_int [simp]: "n >= 0 ==> fact (n :: int) > 0"  by (auto simp add: fact_int_def)lemma fact_ge_one_nat [simp]: "fact (n :: nat) >= 1"  by (insert fact_nonzero_nat [of n], arith)lemma fact_ge_Suc_0_nat [simp]: "fact (n :: nat) >= Suc 0"  by (insert fact_nonzero_nat [of n], arith)lemma fact_ge_one_int [simp]: "n >= 0 ==> fact (n :: int) >= 1"  apply (auto simp add: fact_int_def)  apply (subgoal_tac "1 = int 1")  apply (erule ssubst)  apply (subst zle_int)  apply auto  donelemma dvd_fact_nat [rule_format]: "1 <= m --> m <= n --> m dvd fact (n::nat)"  apply (induct n)  apply force  apply (auto simp only: fact_Suc)  apply (subgoal_tac "m = Suc n")  apply (erule ssubst)  apply (rule dvd_triv_left)  apply auto  donelemma dvd_fact_int [rule_format]: "1 <= m --> m <= n --> m dvd fact (n::int)"  apply (case_tac "1 <= n")  apply (induct n rule: int_ge_induct)  apply (auto simp add: fact_plus_one_int)  apply (subgoal_tac "m = i + 1")  apply auto  donelemma interval_plus_one_nat: "(i::nat) <= j + 1 ==>   {i..j+1} = {i..j} Un {j+1}"  by autolemma interval_Suc: "i <= Suc j ==> {i..Suc j} = {i..j} Un {Suc j}"  by autolemma interval_plus_one_int: "(i::int) <= j + 1 ==> {i..j+1} = {i..j} Un {j+1}"  by autolemma fact_altdef_nat: "fact (n::nat) = (PROD i:{1..n}. i)"  apply (induct n)  apply force  apply (subst fact_Suc)  apply (subst interval_Suc)  apply autodonelemma fact_altdef_int: "n >= 0 ==> fact (n::int) = (PROD i:{1..n}. i)"  apply (induct n rule: int_ge_induct)  apply force  apply (subst fact_plus_one_int, assumption)  apply (subst interval_plus_one_int)  apply autodonelemma fact_dvd: "n ≤ m ==> fact n dvd fact (m::nat)"  by (auto simp add: fact_altdef_nat intro!: setprod_dvd_setprod_subset)lemma fact_mod: "m ≤ (n::nat) ==> fact n mod fact m = 0"  by (auto simp add: dvd_imp_mod_0 fact_dvd)lemma fact_div_fact:  assumes "m ≥ (n :: nat)"  shows "(fact m) div (fact n) = ∏{n + 1..m}"proof -  obtain d where "d = m - n" by auto  from assms this 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 setprod_insert)    finally show ?case .  qed  from this `m = n + d` show ?thesis by simpqedlemma fact_mono_nat: "(m::nat) ≤ n ==> fact m ≤ fact n"apply (drule le_imp_less_or_eq)apply (auto dest!: less_imp_Suc_add)apply (induct_tac k, auto)donelemma fact_neg_int [simp]: "m < (0::int) ==> fact m = 0"  unfolding fact_int_def by autolemma fact_ge_zero_int [simp]: "fact m >= (0::int)"  apply (case_tac "m >= 0")  apply auto  apply (frule fact_gt_zero_int)  apply arithdonelemma fact_mono_int_aux [rule_format]: "k >= (0::int) ==>     fact (m + k) >= fact m"  apply (case_tac "m < 0")  apply auto  apply (induct k rule: int_ge_induct)  apply auto  apply (subst add_assoc [symmetric])  apply (subst fact_plus_one_int)  apply auto  apply (erule order_trans)  apply (subst mult_le_cancel_right1)  apply (subgoal_tac "fact (m + i) >= 0")  apply arith  apply autodonelemma fact_mono_int: "(m::int) <= n ==> fact m <= fact n"  apply (insert fact_mono_int_aux [of "n - m" "m"])  apply autodonetext{*Note that @{term "fact 0 = fact 1"}*}lemma fact_less_mono_nat: "[| (0::nat) < m; m < n |] ==> fact m < fact n"apply (drule_tac m = m in less_imp_Suc_add, auto)apply (induct_tac k, auto)donelemma fact_less_mono_int_aux: "k >= 0 ==> (0::int) < m ==>    fact m < fact ((m + 1) + k)"  apply (induct k rule: int_ge_induct)  apply (simp add: fact_plus_one_int)  apply (subst (2) fact_reduce_int)  apply (auto simp add: add_ac)  apply (erule order_less_le_trans)  apply (subst mult_le_cancel_right1)  apply auto  apply (subgoal_tac "fact (i + (1 + m)) >= 0")  apply force  apply (rule fact_ge_zero_int)donelemma fact_less_mono_int: "(0::int) < m ==> m < n ==> fact m < fact n"  apply (insert fact_less_mono_int_aux [of "n - (m + 1)" "m"])  apply autodonelemma fact_num_eq_if_nat: "fact (m::nat) =   (if m=0 then 1 else m * fact (m - 1))"by (cases m) autolemma fact_add_num_eq_if_nat:  "fact ((m::nat) + n) = (if m + n = 0 then 1 else (m + n) * fact (m + n - 1))"by (cases "m + n") autolemma fact_add_num_eq_if2_nat:  "fact ((m::nat) + n) =     (if m = 0 then fact n else (m + n) * fact ((m - 1) + n))"by (cases m) autolemma fact_le_power: "fact n ≤ n^n"proof (induct n)  case (Suc n)  then have "fact n ≤ Suc n ^ n" by (rule le_trans) (simp add: power_mono)  then show ?case by (simp add: add_le_mono)qed simpsubsection {* @{term fact} and @{term of_nat} *}lemma of_nat_fact_not_zero [simp]: "of_nat (fact n) ≠ (0::'a::semiring_char_0)"by autolemma of_nat_fact_gt_zero [simp]: "(0::'a::{linordered_semidom}) < of_nat(fact n)" by autolemma of_nat_fact_ge_zero [simp]: "(0::'a::linordered_semidom) ≤ of_nat(fact n)"by simplemma inv_of_nat_fact_gt_zero [simp]: "(0::'a::linordered_field) < inverse (of_nat (fact n))"by (auto simp add: positive_imp_inverse_positive)lemma inv_of_nat_fact_ge_zero [simp]: "(0::'a::linordered_field) ≤ inverse (of_nat (fact n))"by (auto intro: order_less_imp_le)lemma fact_eq_rev_setprod_nat: "fact (k::nat) = (∏i<k. k - i)"  unfolding fact_altdef_natproof (rule strong_setprod_reindex_cong)  { fix i assume "Suc 0 ≤ i" "i ≤ k" then have "∃j∈{..<k}. i = k - j"      by (intro bexI[of _ "k - i"]) simp_all }  then show "{1..k} = (λi. k - i) ` {..<k}"    by (auto simp: image_iff)qed (auto intro: inj_onI)lemma fact_div_fact_le_pow:  assumes "r ≤ n" shows "fact n div fact (n - r) ≤ n ^ r"proof -  have "!!r. r ≤ n ==> ∏{n - r..n} = (n - r) * ∏{Suc (n - r)..n}"    by (subst setprod_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)qedend`