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 avigad@32036: imports NatTransfer nipkow@15131: begin paulson@15094: avigad@32036: class fact = avigad@32036: avigad@32036: fixes avigad@32036: fact :: "'a \ 'a" avigad@32036: avigad@32036: instantiation nat :: fact avigad@32036: avigad@32036: begin avigad@32036: avigad@32036: fun avigad@32036: fact_nat :: "nat \ nat" avigad@32036: where avigad@32036: fact_0_nat: "fact_nat 0 = Suc 0" avigad@32036: | fact_Suc_nat: "fact_nat (Suc x) = Suc x * fact x" avigad@32036: avigad@32036: instance proof qed 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 \ 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 \ 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) \ fact x >= 0" avigad@32036: by (auto simp add: fact_int_def) avigad@32036: avigad@32036: declare TransferMorphism_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 \ fact x >= 0" avigad@32036: by (auto simp add: fact_int_def) avigad@32036: avigad@32036: declare TransferMorphism_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" avigad@32036: avigad@32036: using prems 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 \ fact n = n * fact (n - 1)" avigad@32036: apply (subgoal_tac "n = Suc (n - 1)") avigad@32036: apply (erule ssubst) avigad@32036: apply (subst fact_Suc_nat) avigad@32036: apply simp_all avigad@32036: done avigad@32036: avigad@32036: lemma fact_reduce_int: "(n::int) > 0 \ 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 avigad@32036: done avigad@32036: avigad@32036: lemma fact_nonzero_nat [simp]: "fact (n::nat) \ 0" avigad@32036: apply (induct n) avigad@32036: apply (auto simp add: fact_plus_one_nat) avigad@32036: done avigad@32036: avigad@32036: lemma fact_nonzero_int [simp]: "n >= 0 \ 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 \ 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 \ 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 avigad@32036: done avigad@32036: avigad@32036: lemma dvd_fact_nat [rule_format]: "1 <= m \ m <= n \ m dvd fact (n::nat)" avigad@32036: apply (induct n) avigad@32036: apply force avigad@32036: apply (auto simp only: fact_Suc_nat) avigad@32036: apply (subgoal_tac "m = Suc n") avigad@32036: apply (erule ssubst) avigad@32036: apply (rule dvd_triv_left) avigad@32036: apply auto avigad@32036: done avigad@32036: avigad@32036: lemma dvd_fact_int [rule_format]: "1 <= m \ m <= n \ 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 avigad@32036: done avigad@32036: avigad@32036: lemma interval_plus_one_nat: "(i::nat) <= j + 1 \ avigad@32036: {i..j+1} = {i..j} Un {j+1}" avigad@32036: by auto avigad@32036: avigad@32036: lemma interval_Suc: "i <= Suc j \ {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 \ {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@32036: apply (subst fact_Suc_nat) avigad@32036: apply (subst interval_Suc) avigad@32036: apply auto avigad@32036: done avigad@32036: avigad@32036: lemma fact_altdef_int: "n >= 0 \ 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: avigad@32036: lemma fact_mono_nat: "(m::nat) \ n \ fact m \ 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) \ 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) \ 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 \ 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 \ (0::int) < m \ 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 \ m < n \ 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) \ (0::'a::semiring_char_0)" nipkow@25134: by auto paulson@15094: chaieb@29693: class ordered_semiring_1 = ordered_semiring + semiring_1 chaieb@29693: class ordered_semiring_1_strict = ordered_semiring_strict + semiring_1 paulson@15094: chaieb@29693: lemma of_nat_fact_gt_zero [simp]: "(0::'a::{ordered_semidom}) < of_nat(fact n)" by auto chaieb@29693: chaieb@29693: lemma of_nat_fact_ge_zero [simp]: "(0::'a::ordered_semidom) \ of_nat(fact n)" nipkow@25134: by simp paulson@15094: chaieb@29693: lemma inv_of_nat_fact_gt_zero [simp]: "(0::'a::ordered_field) < inverse (of_nat (fact n))" nipkow@25134: by (auto simp add: positive_imp_inverse_positive) paulson@15094: chaieb@29693: lemma inv_of_nat_fact_ge_zero [simp]: "(0::'a::ordered_field) \ inverse (of_nat (fact n))" nipkow@25134: by (auto intro: order_less_imp_le) paulson@15094: nipkow@15131: end