src/HOL/Fact.thy
author haftmann
Sun Sep 21 16:56:11 2014 +0200 (2014-09-21)
changeset 58410 6d46ad54a2ab
parent 57514 bdc2c6b40bf2
child 58889 5b7a9633cfa8
permissions -rw-r--r--
explicit separation of signed and unsigned numerals using existing lexical categories num and xnum
paulson@15094
     1
(*  Title       : Fact.thy
paulson@12196
     2
    Author      : Jacques D. Fleuriot
paulson@12196
     3
    Copyright   : 1998  University of Cambridge
paulson@15094
     4
    Conversion to Isar and new proofs by Lawrence C Paulson, 2004
avigad@32036
     5
    The integer version of factorial and other additions by Jeremy Avigad.
paulson@12196
     6
*)
paulson@12196
     7
paulson@15094
     8
header{*Factorial Function*}
paulson@15094
     9
nipkow@15131
    10
theory Fact
haftmann@33319
    11
imports Main
nipkow@15131
    12
begin
paulson@15094
    13
avigad@32036
    14
class fact =
wenzelm@41550
    15
  fixes fact :: "'a \<Rightarrow> 'a"
avigad@32036
    16
avigad@32036
    17
instantiation nat :: fact
avigad@32036
    18
begin 
avigad@32036
    19
avigad@32036
    20
fun
avigad@32036
    21
  fact_nat :: "nat \<Rightarrow> nat"
avigad@32036
    22
where
avigad@32036
    23
  fact_0_nat: "fact_nat 0 = Suc 0"
avigad@32047
    24
| fact_Suc: "fact_nat (Suc x) = Suc x * fact x"
avigad@32036
    25
wenzelm@41550
    26
instance ..
avigad@32036
    27
avigad@32036
    28
end
avigad@32036
    29
avigad@32036
    30
(* definitions for the integers *)
avigad@32036
    31
avigad@32036
    32
instantiation int :: fact
avigad@32036
    33
avigad@32036
    34
begin 
avigad@32036
    35
avigad@32036
    36
definition
avigad@32036
    37
  fact_int :: "int \<Rightarrow> int"
avigad@32036
    38
where  
avigad@32036
    39
  "fact_int x = (if x >= 0 then int (fact (nat x)) else 0)"
avigad@32036
    40
avigad@32036
    41
instance proof qed
avigad@32036
    42
avigad@32036
    43
end
avigad@32036
    44
avigad@32036
    45
avigad@32036
    46
subsection {* Set up Transfer *}
avigad@32036
    47
avigad@32036
    48
lemma transfer_nat_int_factorial:
avigad@32036
    49
  "(x::int) >= 0 \<Longrightarrow> fact (nat x) = nat (fact x)"
avigad@32036
    50
  unfolding fact_int_def
avigad@32036
    51
  by auto
avigad@32036
    52
avigad@32036
    53
avigad@32036
    54
lemma transfer_nat_int_factorial_closure:
avigad@32036
    55
  "x >= (0::int) \<Longrightarrow> fact x >= 0"
avigad@32036
    56
  by (auto simp add: fact_int_def)
avigad@32036
    57
haftmann@35644
    58
declare transfer_morphism_nat_int[transfer add return: 
avigad@32036
    59
    transfer_nat_int_factorial transfer_nat_int_factorial_closure]
avigad@32036
    60
avigad@32036
    61
lemma transfer_int_nat_factorial:
avigad@32036
    62
  "fact (int x) = int (fact x)"
avigad@32036
    63
  unfolding fact_int_def by auto
avigad@32036
    64
avigad@32036
    65
lemma transfer_int_nat_factorial_closure:
avigad@32036
    66
  "is_nat x \<Longrightarrow> fact x >= 0"
avigad@32036
    67
  by (auto simp add: fact_int_def)
avigad@32036
    68
haftmann@35644
    69
declare transfer_morphism_int_nat[transfer add return: 
avigad@32036
    70
    transfer_int_nat_factorial transfer_int_nat_factorial_closure]
paulson@15094
    71
paulson@15094
    72
avigad@32036
    73
subsection {* Factorial *}
avigad@32036
    74
avigad@32036
    75
lemma fact_0_int [simp]: "fact (0::int) = 1"
avigad@32036
    76
  by (simp add: fact_int_def)
avigad@32036
    77
avigad@32036
    78
lemma fact_1_nat [simp]: "fact (1::nat) = 1"
avigad@32036
    79
  by simp
avigad@32036
    80
avigad@32036
    81
lemma fact_Suc_0_nat [simp]: "fact (Suc 0) = Suc 0"
avigad@32036
    82
  by simp
avigad@32036
    83
avigad@32036
    84
lemma fact_1_int [simp]: "fact (1::int) = 1"
avigad@32036
    85
  by (simp add: fact_int_def)
avigad@32036
    86
avigad@32036
    87
lemma fact_plus_one_nat: "fact ((n::nat) + 1) = (n + 1) * fact n"
avigad@32036
    88
  by simp
avigad@32036
    89
avigad@32036
    90
lemma fact_plus_one_int: 
avigad@32036
    91
  assumes "n >= 0"
avigad@32036
    92
  shows "fact ((n::int) + 1) = (n + 1) * fact n"
wenzelm@41550
    93
  using assms unfolding fact_int_def 
avigad@32036
    94
  by (simp add: nat_add_distrib algebra_simps int_mult)
avigad@32036
    95
avigad@32036
    96
lemma fact_reduce_nat: "(n::nat) > 0 \<Longrightarrow> fact n = n * fact (n - 1)"
avigad@32036
    97
  apply (subgoal_tac "n = Suc (n - 1)")
avigad@32036
    98
  apply (erule ssubst)
avigad@32047
    99
  apply (subst fact_Suc)
avigad@32036
   100
  apply simp_all
wenzelm@41550
   101
  done
avigad@32036
   102
avigad@32036
   103
lemma fact_reduce_int: "(n::int) > 0 \<Longrightarrow> fact n = n * fact (n - 1)"
avigad@32036
   104
  apply (subgoal_tac "n = (n - 1) + 1")
avigad@32036
   105
  apply (erule ssubst)
avigad@32036
   106
  apply (subst fact_plus_one_int)
avigad@32036
   107
  apply simp_all
wenzelm@41550
   108
  done
avigad@32036
   109
avigad@32036
   110
lemma fact_nonzero_nat [simp]: "fact (n::nat) \<noteq> 0"
avigad@32036
   111
  apply (induct n)
avigad@32036
   112
  apply (auto simp add: fact_plus_one_nat)
wenzelm@41550
   113
  done
avigad@32036
   114
avigad@32036
   115
lemma fact_nonzero_int [simp]: "n >= 0 \<Longrightarrow> fact (n::int) ~= 0"
avigad@32036
   116
  by (simp add: fact_int_def)
avigad@32036
   117
avigad@32036
   118
lemma fact_gt_zero_nat [simp]: "fact (n :: nat) > 0"
avigad@32036
   119
  by (insert fact_nonzero_nat [of n], arith)
avigad@32036
   120
avigad@32036
   121
lemma fact_gt_zero_int [simp]: "n >= 0 \<Longrightarrow> fact (n :: int) > 0"
avigad@32036
   122
  by (auto simp add: fact_int_def)
avigad@32036
   123
avigad@32036
   124
lemma fact_ge_one_nat [simp]: "fact (n :: nat) >= 1"
avigad@32036
   125
  by (insert fact_nonzero_nat [of n], arith)
avigad@32036
   126
avigad@32036
   127
lemma fact_ge_Suc_0_nat [simp]: "fact (n :: nat) >= Suc 0"
avigad@32036
   128
  by (insert fact_nonzero_nat [of n], arith)
avigad@32036
   129
avigad@32036
   130
lemma fact_ge_one_int [simp]: "n >= 0 \<Longrightarrow> fact (n :: int) >= 1"
avigad@32036
   131
  apply (auto simp add: fact_int_def)
avigad@32036
   132
  apply (subgoal_tac "1 = int 1")
avigad@32036
   133
  apply (erule ssubst)
avigad@32036
   134
  apply (subst zle_int)
avigad@32036
   135
  apply auto
wenzelm@41550
   136
  done
avigad@32036
   137
avigad@32036
   138
lemma dvd_fact_nat [rule_format]: "1 <= m \<longrightarrow> m <= n \<longrightarrow> m dvd fact (n::nat)"
avigad@32036
   139
  apply (induct n)
avigad@32036
   140
  apply force
avigad@32047
   141
  apply (auto simp only: fact_Suc)
avigad@32036
   142
  apply (subgoal_tac "m = Suc n")
avigad@32036
   143
  apply (erule ssubst)
avigad@32036
   144
  apply (rule dvd_triv_left)
avigad@32036
   145
  apply auto
wenzelm@41550
   146
  done
avigad@32036
   147
avigad@32036
   148
lemma dvd_fact_int [rule_format]: "1 <= m \<longrightarrow> m <= n \<longrightarrow> m dvd fact (n::int)"
avigad@32036
   149
  apply (case_tac "1 <= n")
avigad@32036
   150
  apply (induct n rule: int_ge_induct)
avigad@32036
   151
  apply (auto simp add: fact_plus_one_int)
avigad@32036
   152
  apply (subgoal_tac "m = i + 1")
avigad@32036
   153
  apply auto
wenzelm@41550
   154
  done
avigad@32036
   155
avigad@32036
   156
lemma interval_plus_one_nat: "(i::nat) <= j + 1 \<Longrightarrow> 
avigad@32036
   157
  {i..j+1} = {i..j} Un {j+1}"
avigad@32036
   158
  by auto
avigad@32036
   159
avigad@32036
   160
lemma interval_Suc: "i <= Suc j \<Longrightarrow> {i..Suc j} = {i..j} Un {Suc j}"
avigad@32036
   161
  by auto
avigad@32036
   162
avigad@32036
   163
lemma interval_plus_one_int: "(i::int) <= j + 1 \<Longrightarrow> {i..j+1} = {i..j} Un {j+1}"
avigad@32036
   164
  by auto
paulson@15094
   165
avigad@32036
   166
lemma fact_altdef_nat: "fact (n::nat) = (PROD i:{1..n}. i)"
avigad@32036
   167
  apply (induct n)
avigad@32036
   168
  apply force
avigad@32047
   169
  apply (subst fact_Suc)
avigad@32036
   170
  apply (subst interval_Suc)
avigad@32036
   171
  apply auto
avigad@32036
   172
done
avigad@32036
   173
avigad@32036
   174
lemma fact_altdef_int: "n >= 0 \<Longrightarrow> fact (n::int) = (PROD i:{1..n}. i)"
avigad@32036
   175
  apply (induct n rule: int_ge_induct)
avigad@32036
   176
  apply force
avigad@32036
   177
  apply (subst fact_plus_one_int, assumption)
avigad@32036
   178
  apply (subst interval_plus_one_int)
avigad@32036
   179
  apply auto
avigad@32036
   180
done
avigad@32036
   181
bulwahn@40033
   182
lemma fact_dvd: "n \<le> m \<Longrightarrow> fact n dvd fact (m::nat)"
bulwahn@40033
   183
  by (auto simp add: fact_altdef_nat intro!: setprod_dvd_setprod_subset)
bulwahn@40033
   184
bulwahn@40033
   185
lemma fact_mod: "m \<le> (n::nat) \<Longrightarrow> fact n mod fact m = 0"
bulwahn@40033
   186
  by (auto simp add: dvd_imp_mod_0 fact_dvd)
bulwahn@40033
   187
bulwahn@40033
   188
lemma fact_div_fact:
bulwahn@40033
   189
  assumes "m \<ge> (n :: nat)"
bulwahn@40033
   190
  shows "(fact m) div (fact n) = \<Prod>{n + 1..m}"
bulwahn@40033
   191
proof -
bulwahn@40033
   192
  obtain d where "d = m - n" by auto
bulwahn@40033
   193
  from assms this have "m = n + d" by auto
bulwahn@40033
   194
  have "fact (n + d) div (fact n) = \<Prod>{n + 1..n + d}"
bulwahn@40033
   195
  proof (induct d)
bulwahn@40033
   196
    case 0
bulwahn@40033
   197
    show ?case by simp
bulwahn@40033
   198
  next
bulwahn@40033
   199
    case (Suc d')
bulwahn@40033
   200
    have "fact (n + Suc d') div fact n = Suc (n + d') * fact (n + d') div fact n"
bulwahn@40033
   201
      by simp
bulwahn@40033
   202
    also from Suc.hyps have "... = Suc (n + d') * \<Prod>{n + 1..n + d'}" 
bulwahn@40033
   203
      unfolding div_mult1_eq[of _ "fact (n + d')"] by (simp add: fact_mod)
bulwahn@40033
   204
    also have "... = \<Prod>{n + 1..n + Suc d'}"
haftmann@57418
   205
      by (simp add: atLeastAtMostSuc_conv setprod.insert)
bulwahn@40033
   206
    finally show ?case .
bulwahn@40033
   207
  qed
bulwahn@40033
   208
  from this `m = n + d` show ?thesis by simp
bulwahn@40033
   209
qed
bulwahn@40033
   210
avigad@32036
   211
lemma fact_mono_nat: "(m::nat) \<le> n \<Longrightarrow> fact m \<le> fact n"
avigad@32036
   212
apply (drule le_imp_less_or_eq)
avigad@32036
   213
apply (auto dest!: less_imp_Suc_add)
avigad@32036
   214
apply (induct_tac k, auto)
avigad@32036
   215
done
avigad@32036
   216
avigad@32036
   217
lemma fact_neg_int [simp]: "m < (0::int) \<Longrightarrow> fact m = 0"
avigad@32036
   218
  unfolding fact_int_def by auto
avigad@32036
   219
avigad@32036
   220
lemma fact_ge_zero_int [simp]: "fact m >= (0::int)"
avigad@32036
   221
  apply (case_tac "m >= 0")
avigad@32036
   222
  apply auto
avigad@32036
   223
  apply (frule fact_gt_zero_int)
avigad@32036
   224
  apply arith
avigad@32036
   225
done
avigad@32036
   226
avigad@32036
   227
lemma fact_mono_int_aux [rule_format]: "k >= (0::int) \<Longrightarrow> 
avigad@32036
   228
    fact (m + k) >= fact m"
avigad@32036
   229
  apply (case_tac "m < 0")
avigad@32036
   230
  apply auto
avigad@32036
   231
  apply (induct k rule: int_ge_induct)
avigad@32036
   232
  apply auto
haftmann@57512
   233
  apply (subst add.assoc [symmetric])
avigad@32036
   234
  apply (subst fact_plus_one_int)
avigad@32036
   235
  apply auto
avigad@32036
   236
  apply (erule order_trans)
avigad@32036
   237
  apply (subst mult_le_cancel_right1)
avigad@32036
   238
  apply (subgoal_tac "fact (m + i) >= 0")
avigad@32036
   239
  apply arith
avigad@32036
   240
  apply auto
avigad@32036
   241
done
avigad@32036
   242
avigad@32036
   243
lemma fact_mono_int: "(m::int) <= n \<Longrightarrow> fact m <= fact n"
avigad@32036
   244
  apply (insert fact_mono_int_aux [of "n - m" "m"])
avigad@32036
   245
  apply auto
avigad@32036
   246
done
avigad@32036
   247
avigad@32036
   248
text{*Note that @{term "fact 0 = fact 1"}*}
avigad@32036
   249
lemma fact_less_mono_nat: "[| (0::nat) < m; m < n |] ==> fact m < fact n"
avigad@32036
   250
apply (drule_tac m = m in less_imp_Suc_add, auto)
avigad@32036
   251
apply (induct_tac k, auto)
avigad@32036
   252
done
avigad@32036
   253
avigad@32036
   254
lemma fact_less_mono_int_aux: "k >= 0 \<Longrightarrow> (0::int) < m \<Longrightarrow>
avigad@32036
   255
    fact m < fact ((m + 1) + k)"
avigad@32036
   256
  apply (induct k rule: int_ge_induct)
avigad@32036
   257
  apply (simp add: fact_plus_one_int)
avigad@32036
   258
  apply (subst (2) fact_reduce_int)
haftmann@57514
   259
  apply (auto simp add: ac_simps)
avigad@32036
   260
  apply (erule order_less_le_trans)
avigad@32036
   261
  apply auto
haftmann@57514
   262
  done
avigad@32036
   263
avigad@32036
   264
lemma fact_less_mono_int: "(0::int) < m \<Longrightarrow> m < n \<Longrightarrow> fact m < fact n"
avigad@32036
   265
  apply (insert fact_less_mono_int_aux [of "n - (m + 1)" "m"])
avigad@32036
   266
  apply auto
avigad@32036
   267
done
avigad@32036
   268
avigad@32036
   269
lemma fact_num_eq_if_nat: "fact (m::nat) = 
avigad@32036
   270
  (if m=0 then 1 else m * fact (m - 1))"
avigad@32036
   271
by (cases m) auto
avigad@32036
   272
avigad@32036
   273
lemma fact_add_num_eq_if_nat:
avigad@32036
   274
  "fact ((m::nat) + n) = (if m + n = 0 then 1 else (m + n) * fact (m + n - 1))"
avigad@32036
   275
by (cases "m + n") auto
avigad@32036
   276
avigad@32036
   277
lemma fact_add_num_eq_if2_nat:
avigad@32036
   278
  "fact ((m::nat) + n) = 
avigad@32036
   279
    (if m = 0 then fact n else (m + n) * fact ((m - 1) + n))"
avigad@32036
   280
by (cases m) auto
avigad@32036
   281
noschinl@45930
   282
lemma fact_le_power: "fact n \<le> n^n"
noschinl@45930
   283
proof (induct n)
noschinl@45930
   284
  case (Suc n)
noschinl@45930
   285
  then have "fact n \<le> Suc n ^ n" by (rule le_trans) (simp add: power_mono)
noschinl@45930
   286
  then show ?case by (simp add: add_le_mono)
noschinl@45930
   287
qed simp
avigad@32036
   288
berghofe@32039
   289
subsection {* @{term fact} and @{term of_nat} *}
paulson@15094
   290
chaieb@29693
   291
lemma of_nat_fact_not_zero [simp]: "of_nat (fact n) \<noteq> (0::'a::semiring_char_0)"
nipkow@25134
   292
by auto
paulson@15094
   293
haftmann@35028
   294
lemma of_nat_fact_gt_zero [simp]: "(0::'a::{linordered_semidom}) < of_nat(fact n)" by auto
chaieb@29693
   295
haftmann@35028
   296
lemma of_nat_fact_ge_zero [simp]: "(0::'a::linordered_semidom) \<le> of_nat(fact n)"
nipkow@25134
   297
by simp
paulson@15094
   298
haftmann@35028
   299
lemma inv_of_nat_fact_gt_zero [simp]: "(0::'a::linordered_field) < inverse (of_nat (fact n))"
nipkow@25134
   300
by (auto simp add: positive_imp_inverse_positive)
paulson@15094
   301
haftmann@35028
   302
lemma inv_of_nat_fact_ge_zero [simp]: "(0::'a::linordered_field) \<le> inverse (of_nat (fact n))"
nipkow@25134
   303
by (auto intro: order_less_imp_le)
paulson@15094
   304
hoelzl@50224
   305
lemma fact_eq_rev_setprod_nat: "fact (k::nat) = (\<Prod>i<k. k - i)"
hoelzl@50224
   306
  unfolding fact_altdef_nat
hoelzl@57129
   307
  by (rule setprod.reindex_bij_witness[where i="\<lambda>i. k - i" and j="\<lambda>i. k - i"]) auto
hoelzl@50224
   308
hoelzl@50240
   309
lemma fact_div_fact_le_pow:
hoelzl@50240
   310
  assumes "r \<le> n" shows "fact n div fact (n - r) \<le> n ^ r"
hoelzl@50240
   311
proof -
hoelzl@50240
   312
  have "\<And>r. r \<le> n \<Longrightarrow> \<Prod>{n - r..n} = (n - r) * \<Prod>{Suc (n - r)..n}"
haftmann@57418
   313
    by (subst setprod.insert[symmetric]) (auto simp: atLeastAtMost_insertL)
hoelzl@50240
   314
  with assms show ?thesis
hoelzl@50240
   315
    by (induct r rule: nat.induct) (auto simp add: fact_div_fact Suc_diff_Suc mult_le_mono)
hoelzl@50240
   316
qed
hoelzl@50240
   317
lp15@57113
   318
lemma fact_numeral:  --{*Evaluation for specific numerals*}
lp15@57113
   319
  "fact (numeral k) = (numeral k) * (fact (pred_numeral k))"
lp15@57113
   320
  by (simp add: numeral_eq_Suc)
lp15@57113
   321
nipkow@15131
   322
end