src/HOL/Library/Stirling.thy
author nipkow
Fri, 08 Jul 2016 16:38:31 +0200
changeset 63413 9fe2d9dc095e
parent 63145 703edebd1d92
child 63487 6e29fb72e659
permissions -rw-r--r--
added path_len
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
63071
3ca3bc795908 move Stirling numbers from AFP/Discrete_Summation
hoelzl
parents:
diff changeset
     1
(* Authors: Amine Chaieb & Florian Haftmann, TU Muenchen
3ca3bc795908 move Stirling numbers from AFP/Discrete_Summation
hoelzl
parents:
diff changeset
     2
            with contributions by Lukas Bulwahn and Manuel Eberl*)
3ca3bc795908 move Stirling numbers from AFP/Discrete_Summation
hoelzl
parents:
diff changeset
     3
63145
703edebd1d92 isabelle update_cartouches -c -t;
wenzelm
parents: 63071
diff changeset
     4
section \<open>Stirling numbers of first and second kind\<close>
63071
3ca3bc795908 move Stirling numbers from AFP/Discrete_Summation
hoelzl
parents:
diff changeset
     5
3ca3bc795908 move Stirling numbers from AFP/Discrete_Summation
hoelzl
parents:
diff changeset
     6
theory Stirling
3ca3bc795908 move Stirling numbers from AFP/Discrete_Summation
hoelzl
parents:
diff changeset
     7
imports Binomial
3ca3bc795908 move Stirling numbers from AFP/Discrete_Summation
hoelzl
parents:
diff changeset
     8
begin
3ca3bc795908 move Stirling numbers from AFP/Discrete_Summation
hoelzl
parents:
diff changeset
     9
63145
703edebd1d92 isabelle update_cartouches -c -t;
wenzelm
parents: 63071
diff changeset
    10
subsection \<open>Stirling numbers of the second kind\<close>
63071
3ca3bc795908 move Stirling numbers from AFP/Discrete_Summation
hoelzl
parents:
diff changeset
    11
3ca3bc795908 move Stirling numbers from AFP/Discrete_Summation
hoelzl
parents:
diff changeset
    12
fun Stirling :: "nat \<Rightarrow> nat \<Rightarrow> nat"
3ca3bc795908 move Stirling numbers from AFP/Discrete_Summation
hoelzl
parents:
diff changeset
    13
where
3ca3bc795908 move Stirling numbers from AFP/Discrete_Summation
hoelzl
parents:
diff changeset
    14
  "Stirling 0 0 = 1"
3ca3bc795908 move Stirling numbers from AFP/Discrete_Summation
hoelzl
parents:
diff changeset
    15
| "Stirling 0 (Suc k) = 0"
3ca3bc795908 move Stirling numbers from AFP/Discrete_Summation
hoelzl
parents:
diff changeset
    16
| "Stirling (Suc n) 0 = 0"
3ca3bc795908 move Stirling numbers from AFP/Discrete_Summation
hoelzl
parents:
diff changeset
    17
| "Stirling (Suc n) (Suc k) = Suc k * Stirling n (Suc k) + Stirling n k"
3ca3bc795908 move Stirling numbers from AFP/Discrete_Summation
hoelzl
parents:
diff changeset
    18
3ca3bc795908 move Stirling numbers from AFP/Discrete_Summation
hoelzl
parents:
diff changeset
    19
lemma Stirling_1 [simp]:
3ca3bc795908 move Stirling numbers from AFP/Discrete_Summation
hoelzl
parents:
diff changeset
    20
  "Stirling (Suc n) (Suc 0) = 1"
3ca3bc795908 move Stirling numbers from AFP/Discrete_Summation
hoelzl
parents:
diff changeset
    21
  by (induct n) simp_all
3ca3bc795908 move Stirling numbers from AFP/Discrete_Summation
hoelzl
parents:
diff changeset
    22
3ca3bc795908 move Stirling numbers from AFP/Discrete_Summation
hoelzl
parents:
diff changeset
    23
lemma Stirling_less [simp]:
3ca3bc795908 move Stirling numbers from AFP/Discrete_Summation
hoelzl
parents:
diff changeset
    24
  "n < k \<Longrightarrow> Stirling n k = 0"
3ca3bc795908 move Stirling numbers from AFP/Discrete_Summation
hoelzl
parents:
diff changeset
    25
  by (induct n k rule: Stirling.induct) simp_all
3ca3bc795908 move Stirling numbers from AFP/Discrete_Summation
hoelzl
parents:
diff changeset
    26
3ca3bc795908 move Stirling numbers from AFP/Discrete_Summation
hoelzl
parents:
diff changeset
    27
lemma Stirling_same [simp]:
3ca3bc795908 move Stirling numbers from AFP/Discrete_Summation
hoelzl
parents:
diff changeset
    28
  "Stirling n n = 1"
3ca3bc795908 move Stirling numbers from AFP/Discrete_Summation
hoelzl
parents:
diff changeset
    29
  by (induct n) simp_all
3ca3bc795908 move Stirling numbers from AFP/Discrete_Summation
hoelzl
parents:
diff changeset
    30
3ca3bc795908 move Stirling numbers from AFP/Discrete_Summation
hoelzl
parents:
diff changeset
    31
lemma Stirling_2_2:
3ca3bc795908 move Stirling numbers from AFP/Discrete_Summation
hoelzl
parents:
diff changeset
    32
  "Stirling (Suc (Suc n)) (Suc (Suc 0)) = 2 ^ Suc n - 1"
3ca3bc795908 move Stirling numbers from AFP/Discrete_Summation
hoelzl
parents:
diff changeset
    33
proof (induct n)
3ca3bc795908 move Stirling numbers from AFP/Discrete_Summation
hoelzl
parents:
diff changeset
    34
  case 0 then show ?case by simp
3ca3bc795908 move Stirling numbers from AFP/Discrete_Summation
hoelzl
parents:
diff changeset
    35
next
3ca3bc795908 move Stirling numbers from AFP/Discrete_Summation
hoelzl
parents:
diff changeset
    36
  case (Suc n)
3ca3bc795908 move Stirling numbers from AFP/Discrete_Summation
hoelzl
parents:
diff changeset
    37
  have "Stirling (Suc (Suc (Suc n))) (Suc (Suc 0)) =
3ca3bc795908 move Stirling numbers from AFP/Discrete_Summation
hoelzl
parents:
diff changeset
    38
    2 * Stirling (Suc (Suc n)) (Suc (Suc 0)) + Stirling (Suc (Suc n)) (Suc 0)" by simp
3ca3bc795908 move Stirling numbers from AFP/Discrete_Summation
hoelzl
parents:
diff changeset
    39
  also have "\<dots> = 2 * (2 ^ Suc n - 1) + 1"
3ca3bc795908 move Stirling numbers from AFP/Discrete_Summation
hoelzl
parents:
diff changeset
    40
    by (simp only: Suc Stirling_1)
3ca3bc795908 move Stirling numbers from AFP/Discrete_Summation
hoelzl
parents:
diff changeset
    41
  also have "\<dots> = 2 ^ Suc (Suc n) - 1"
3ca3bc795908 move Stirling numbers from AFP/Discrete_Summation
hoelzl
parents:
diff changeset
    42
  proof -
3ca3bc795908 move Stirling numbers from AFP/Discrete_Summation
hoelzl
parents:
diff changeset
    43
    have "(2::nat) ^ Suc n - 1 > 0" by (induct n) simp_all
3ca3bc795908 move Stirling numbers from AFP/Discrete_Summation
hoelzl
parents:
diff changeset
    44
    then have "2 * ((2::nat) ^ Suc n - 1) > 0" by simp
3ca3bc795908 move Stirling numbers from AFP/Discrete_Summation
hoelzl
parents:
diff changeset
    45
    then have "2 \<le> 2 * ((2::nat) ^ Suc n)" by simp
3ca3bc795908 move Stirling numbers from AFP/Discrete_Summation
hoelzl
parents:
diff changeset
    46
    with add_diff_assoc2 [of 2 "2 * 2 ^ Suc n" 1]
3ca3bc795908 move Stirling numbers from AFP/Discrete_Summation
hoelzl
parents:
diff changeset
    47
      have "2 * 2 ^ Suc n - 2 + (1::nat) = 2 * 2 ^ Suc n + 1 - 2" .
3ca3bc795908 move Stirling numbers from AFP/Discrete_Summation
hoelzl
parents:
diff changeset
    48
    then show ?thesis by (simp add: nat_distrib)
3ca3bc795908 move Stirling numbers from AFP/Discrete_Summation
hoelzl
parents:
diff changeset
    49
  qed
3ca3bc795908 move Stirling numbers from AFP/Discrete_Summation
hoelzl
parents:
diff changeset
    50
  finally show ?case by simp
3ca3bc795908 move Stirling numbers from AFP/Discrete_Summation
hoelzl
parents:
diff changeset
    51
qed
3ca3bc795908 move Stirling numbers from AFP/Discrete_Summation
hoelzl
parents:
diff changeset
    52
3ca3bc795908 move Stirling numbers from AFP/Discrete_Summation
hoelzl
parents:
diff changeset
    53
lemma Stirling_2:
3ca3bc795908 move Stirling numbers from AFP/Discrete_Summation
hoelzl
parents:
diff changeset
    54
  "Stirling (Suc n) (Suc (Suc 0)) = 2 ^ n - 1"
3ca3bc795908 move Stirling numbers from AFP/Discrete_Summation
hoelzl
parents:
diff changeset
    55
  using Stirling_2_2 by (cases n) simp_all
3ca3bc795908 move Stirling numbers from AFP/Discrete_Summation
hoelzl
parents:
diff changeset
    56
63145
703edebd1d92 isabelle update_cartouches -c -t;
wenzelm
parents: 63071
diff changeset
    57
subsection \<open>Stirling numbers of the first kind\<close>
63071
3ca3bc795908 move Stirling numbers from AFP/Discrete_Summation
hoelzl
parents:
diff changeset
    58
3ca3bc795908 move Stirling numbers from AFP/Discrete_Summation
hoelzl
parents:
diff changeset
    59
fun stirling :: "nat \<Rightarrow> nat \<Rightarrow> nat"
3ca3bc795908 move Stirling numbers from AFP/Discrete_Summation
hoelzl
parents:
diff changeset
    60
where
3ca3bc795908 move Stirling numbers from AFP/Discrete_Summation
hoelzl
parents:
diff changeset
    61
  "stirling 0 0 = 1"
3ca3bc795908 move Stirling numbers from AFP/Discrete_Summation
hoelzl
parents:
diff changeset
    62
| "stirling 0 (Suc k) = 0"
3ca3bc795908 move Stirling numbers from AFP/Discrete_Summation
hoelzl
parents:
diff changeset
    63
| "stirling (Suc n) 0 = 0"
3ca3bc795908 move Stirling numbers from AFP/Discrete_Summation
hoelzl
parents:
diff changeset
    64
| "stirling (Suc n) (Suc k) = n * stirling n (Suc k) + stirling n k"
3ca3bc795908 move Stirling numbers from AFP/Discrete_Summation
hoelzl
parents:
diff changeset
    65
3ca3bc795908 move Stirling numbers from AFP/Discrete_Summation
hoelzl
parents:
diff changeset
    66
lemma stirling_0 [simp]: "n > 0 \<Longrightarrow> stirling n 0 = 0"
3ca3bc795908 move Stirling numbers from AFP/Discrete_Summation
hoelzl
parents:
diff changeset
    67
  by (cases n) simp_all
3ca3bc795908 move Stirling numbers from AFP/Discrete_Summation
hoelzl
parents:
diff changeset
    68
3ca3bc795908 move Stirling numbers from AFP/Discrete_Summation
hoelzl
parents:
diff changeset
    69
lemma stirling_less [simp]:
3ca3bc795908 move Stirling numbers from AFP/Discrete_Summation
hoelzl
parents:
diff changeset
    70
  "n < k \<Longrightarrow> stirling n k = 0"
3ca3bc795908 move Stirling numbers from AFP/Discrete_Summation
hoelzl
parents:
diff changeset
    71
  by (induct n k rule: stirling.induct) simp_all
3ca3bc795908 move Stirling numbers from AFP/Discrete_Summation
hoelzl
parents:
diff changeset
    72
3ca3bc795908 move Stirling numbers from AFP/Discrete_Summation
hoelzl
parents:
diff changeset
    73
lemma stirling_same [simp]:
3ca3bc795908 move Stirling numbers from AFP/Discrete_Summation
hoelzl
parents:
diff changeset
    74
  "stirling n n = 1"
3ca3bc795908 move Stirling numbers from AFP/Discrete_Summation
hoelzl
parents:
diff changeset
    75
  by (induct n) simp_all
3ca3bc795908 move Stirling numbers from AFP/Discrete_Summation
hoelzl
parents:
diff changeset
    76
3ca3bc795908 move Stirling numbers from AFP/Discrete_Summation
hoelzl
parents:
diff changeset
    77
lemma stirling_Suc_n_1:
3ca3bc795908 move Stirling numbers from AFP/Discrete_Summation
hoelzl
parents:
diff changeset
    78
  "stirling (Suc n) (Suc 0) = fact n"
3ca3bc795908 move Stirling numbers from AFP/Discrete_Summation
hoelzl
parents:
diff changeset
    79
  by (induct n) auto
3ca3bc795908 move Stirling numbers from AFP/Discrete_Summation
hoelzl
parents:
diff changeset
    80
3ca3bc795908 move Stirling numbers from AFP/Discrete_Summation
hoelzl
parents:
diff changeset
    81
lemma stirling_Suc_n_n:
3ca3bc795908 move Stirling numbers from AFP/Discrete_Summation
hoelzl
parents:
diff changeset
    82
  shows "stirling (Suc n) n = Suc n choose 2"
3ca3bc795908 move Stirling numbers from AFP/Discrete_Summation
hoelzl
parents:
diff changeset
    83
by (induct n) (auto simp add: numerals(2))
3ca3bc795908 move Stirling numbers from AFP/Discrete_Summation
hoelzl
parents:
diff changeset
    84
3ca3bc795908 move Stirling numbers from AFP/Discrete_Summation
hoelzl
parents:
diff changeset
    85
lemma stirling_Suc_n_2:
3ca3bc795908 move Stirling numbers from AFP/Discrete_Summation
hoelzl
parents:
diff changeset
    86
  assumes "n \<ge> Suc 0"
3ca3bc795908 move Stirling numbers from AFP/Discrete_Summation
hoelzl
parents:
diff changeset
    87
  shows "stirling (Suc n) 2 = (\<Sum>k=1..n. fact n div k)"
3ca3bc795908 move Stirling numbers from AFP/Discrete_Summation
hoelzl
parents:
diff changeset
    88
using assms
3ca3bc795908 move Stirling numbers from AFP/Discrete_Summation
hoelzl
parents:
diff changeset
    89
proof (induct n)
3ca3bc795908 move Stirling numbers from AFP/Discrete_Summation
hoelzl
parents:
diff changeset
    90
  case 0 from this show ?case by simp
3ca3bc795908 move Stirling numbers from AFP/Discrete_Summation
hoelzl
parents:
diff changeset
    91
next
3ca3bc795908 move Stirling numbers from AFP/Discrete_Summation
hoelzl
parents:
diff changeset
    92
  case (Suc n)
3ca3bc795908 move Stirling numbers from AFP/Discrete_Summation
hoelzl
parents:
diff changeset
    93
  show ?case
3ca3bc795908 move Stirling numbers from AFP/Discrete_Summation
hoelzl
parents:
diff changeset
    94
  proof (cases n)
3ca3bc795908 move Stirling numbers from AFP/Discrete_Summation
hoelzl
parents:
diff changeset
    95
    case 0 from this show ?thesis by (simp add: numerals(2))
3ca3bc795908 move Stirling numbers from AFP/Discrete_Summation
hoelzl
parents:
diff changeset
    96
  next
3ca3bc795908 move Stirling numbers from AFP/Discrete_Summation
hoelzl
parents:
diff changeset
    97
    case Suc
3ca3bc795908 move Stirling numbers from AFP/Discrete_Summation
hoelzl
parents:
diff changeset
    98
    from this have geq1: "Suc 0 \<le> n" by simp
3ca3bc795908 move Stirling numbers from AFP/Discrete_Summation
hoelzl
parents:
diff changeset
    99
    have "stirling (Suc (Suc n)) 2 = Suc n * stirling (Suc n) 2 + stirling (Suc n) (Suc 0)"
3ca3bc795908 move Stirling numbers from AFP/Discrete_Summation
hoelzl
parents:
diff changeset
   100
      by (simp only: stirling.simps(4)[of "Suc n"] numerals(2))
3ca3bc795908 move Stirling numbers from AFP/Discrete_Summation
hoelzl
parents:
diff changeset
   101
    also have "... = Suc n * (\<Sum>k=1..n. fact n div k) + fact n"
3ca3bc795908 move Stirling numbers from AFP/Discrete_Summation
hoelzl
parents:
diff changeset
   102
      using Suc.hyps[OF geq1]
3ca3bc795908 move Stirling numbers from AFP/Discrete_Summation
hoelzl
parents:
diff changeset
   103
      by (simp only: stirling_Suc_n_1 of_nat_fact of_nat_add of_nat_mult)
3ca3bc795908 move Stirling numbers from AFP/Discrete_Summation
hoelzl
parents:
diff changeset
   104
    also have "... = Suc n * (\<Sum>k=1..n. fact n div k) + Suc n * fact n div Suc n"
3ca3bc795908 move Stirling numbers from AFP/Discrete_Summation
hoelzl
parents:
diff changeset
   105
      by (metis nat.distinct(1) nonzero_mult_divide_cancel_left)
3ca3bc795908 move Stirling numbers from AFP/Discrete_Summation
hoelzl
parents:
diff changeset
   106
    also have "... = (\<Sum>k=1..n. fact (Suc n) div k) + fact (Suc n) div Suc n"
3ca3bc795908 move Stirling numbers from AFP/Discrete_Summation
hoelzl
parents:
diff changeset
   107
      by (simp add: setsum_right_distrib div_mult_swap dvd_fact)
3ca3bc795908 move Stirling numbers from AFP/Discrete_Summation
hoelzl
parents:
diff changeset
   108
    also have "... = (\<Sum>k=1..Suc n. fact (Suc n) div k)" by simp
3ca3bc795908 move Stirling numbers from AFP/Discrete_Summation
hoelzl
parents:
diff changeset
   109
    finally show ?thesis .
3ca3bc795908 move Stirling numbers from AFP/Discrete_Summation
hoelzl
parents:
diff changeset
   110
  qed
3ca3bc795908 move Stirling numbers from AFP/Discrete_Summation
hoelzl
parents:
diff changeset
   111
qed
3ca3bc795908 move Stirling numbers from AFP/Discrete_Summation
hoelzl
parents:
diff changeset
   112
3ca3bc795908 move Stirling numbers from AFP/Discrete_Summation
hoelzl
parents:
diff changeset
   113
lemma of_nat_stirling_Suc_n_2:
3ca3bc795908 move Stirling numbers from AFP/Discrete_Summation
hoelzl
parents:
diff changeset
   114
  assumes "n \<ge> Suc 0"
3ca3bc795908 move Stirling numbers from AFP/Discrete_Summation
hoelzl
parents:
diff changeset
   115
  shows "(of_nat (stirling (Suc n) 2)::'a::field_char_0) = fact n * (\<Sum>k=1..n. (1 / of_nat k))"
3ca3bc795908 move Stirling numbers from AFP/Discrete_Summation
hoelzl
parents:
diff changeset
   116
using assms
3ca3bc795908 move Stirling numbers from AFP/Discrete_Summation
hoelzl
parents:
diff changeset
   117
proof (induct n)
3ca3bc795908 move Stirling numbers from AFP/Discrete_Summation
hoelzl
parents:
diff changeset
   118
  case 0 from this show ?case by simp
3ca3bc795908 move Stirling numbers from AFP/Discrete_Summation
hoelzl
parents:
diff changeset
   119
next
3ca3bc795908 move Stirling numbers from AFP/Discrete_Summation
hoelzl
parents:
diff changeset
   120
  case (Suc n)
3ca3bc795908 move Stirling numbers from AFP/Discrete_Summation
hoelzl
parents:
diff changeset
   121
  show ?case
3ca3bc795908 move Stirling numbers from AFP/Discrete_Summation
hoelzl
parents:
diff changeset
   122
  proof (cases n)
3ca3bc795908 move Stirling numbers from AFP/Discrete_Summation
hoelzl
parents:
diff changeset
   123
    case 0 from this show ?thesis by (auto simp add: numerals(2))
3ca3bc795908 move Stirling numbers from AFP/Discrete_Summation
hoelzl
parents:
diff changeset
   124
  next
3ca3bc795908 move Stirling numbers from AFP/Discrete_Summation
hoelzl
parents:
diff changeset
   125
    case Suc
3ca3bc795908 move Stirling numbers from AFP/Discrete_Summation
hoelzl
parents:
diff changeset
   126
    from this have geq1: "Suc 0 \<le> n" by simp
3ca3bc795908 move Stirling numbers from AFP/Discrete_Summation
hoelzl
parents:
diff changeset
   127
    have "(of_nat (stirling (Suc (Suc n)) 2)::'a) =
3ca3bc795908 move Stirling numbers from AFP/Discrete_Summation
hoelzl
parents:
diff changeset
   128
      of_nat (Suc n * stirling (Suc n) 2 + stirling (Suc n) (Suc 0))"
3ca3bc795908 move Stirling numbers from AFP/Discrete_Summation
hoelzl
parents:
diff changeset
   129
      by (simp only: stirling.simps(4)[of "Suc n"] numerals(2))
3ca3bc795908 move Stirling numbers from AFP/Discrete_Summation
hoelzl
parents:
diff changeset
   130
    also have "... = of_nat (Suc n) * (fact n * (\<Sum>k = 1..n. 1 / of_nat k)) + fact n"
3ca3bc795908 move Stirling numbers from AFP/Discrete_Summation
hoelzl
parents:
diff changeset
   131
      using Suc.hyps[OF geq1]
3ca3bc795908 move Stirling numbers from AFP/Discrete_Summation
hoelzl
parents:
diff changeset
   132
      by (simp only: stirling_Suc_n_1 of_nat_fact of_nat_add of_nat_mult)
3ca3bc795908 move Stirling numbers from AFP/Discrete_Summation
hoelzl
parents:
diff changeset
   133
    also have "... = fact (Suc n) * (\<Sum>k = 1..n. 1 / of_nat k) + fact (Suc n) * (1 / of_nat (Suc n))"
3ca3bc795908 move Stirling numbers from AFP/Discrete_Summation
hoelzl
parents:
diff changeset
   134
      using of_nat_neq_0 by auto
3ca3bc795908 move Stirling numbers from AFP/Discrete_Summation
hoelzl
parents:
diff changeset
   135
    also have "... = fact (Suc n) * (\<Sum>k = 1..Suc n. 1 / of_nat k)"
3ca3bc795908 move Stirling numbers from AFP/Discrete_Summation
hoelzl
parents:
diff changeset
   136
      by (simp add: distrib_left)
3ca3bc795908 move Stirling numbers from AFP/Discrete_Summation
hoelzl
parents:
diff changeset
   137
    finally show ?thesis .
3ca3bc795908 move Stirling numbers from AFP/Discrete_Summation
hoelzl
parents:
diff changeset
   138
  qed
3ca3bc795908 move Stirling numbers from AFP/Discrete_Summation
hoelzl
parents:
diff changeset
   139
qed
3ca3bc795908 move Stirling numbers from AFP/Discrete_Summation
hoelzl
parents:
diff changeset
   140
3ca3bc795908 move Stirling numbers from AFP/Discrete_Summation
hoelzl
parents:
diff changeset
   141
lemma setsum_stirling:
3ca3bc795908 move Stirling numbers from AFP/Discrete_Summation
hoelzl
parents:
diff changeset
   142
  "(\<Sum>k\<le>n. stirling n k) = fact n"
3ca3bc795908 move Stirling numbers from AFP/Discrete_Summation
hoelzl
parents:
diff changeset
   143
proof (induct n)
3ca3bc795908 move Stirling numbers from AFP/Discrete_Summation
hoelzl
parents:
diff changeset
   144
  case 0
3ca3bc795908 move Stirling numbers from AFP/Discrete_Summation
hoelzl
parents:
diff changeset
   145
  from this show ?case by simp
3ca3bc795908 move Stirling numbers from AFP/Discrete_Summation
hoelzl
parents:
diff changeset
   146
next
3ca3bc795908 move Stirling numbers from AFP/Discrete_Summation
hoelzl
parents:
diff changeset
   147
  case (Suc n)
3ca3bc795908 move Stirling numbers from AFP/Discrete_Summation
hoelzl
parents:
diff changeset
   148
  have "(\<Sum>k\<le>Suc n. stirling (Suc n) k) = stirling (Suc n) 0 + (\<Sum>k\<le>n. stirling (Suc n) (Suc k))"
3ca3bc795908 move Stirling numbers from AFP/Discrete_Summation
hoelzl
parents:
diff changeset
   149
    by (simp only: setsum_atMost_Suc_shift)
3ca3bc795908 move Stirling numbers from AFP/Discrete_Summation
hoelzl
parents:
diff changeset
   150
  also have "\<dots> = (\<Sum>k\<le>n. stirling (Suc n) (Suc k))" by simp
3ca3bc795908 move Stirling numbers from AFP/Discrete_Summation
hoelzl
parents:
diff changeset
   151
  also have "\<dots> = (\<Sum>k\<le>n. n * stirling n (Suc k) + stirling n k)" by simp
3ca3bc795908 move Stirling numbers from AFP/Discrete_Summation
hoelzl
parents:
diff changeset
   152
  also have "\<dots> = n * (\<Sum>k\<le>n. stirling n (Suc k)) + (\<Sum>k\<le>n. stirling n k)"
3ca3bc795908 move Stirling numbers from AFP/Discrete_Summation
hoelzl
parents:
diff changeset
   153
    by (simp add: setsum.distrib setsum_right_distrib)
3ca3bc795908 move Stirling numbers from AFP/Discrete_Summation
hoelzl
parents:
diff changeset
   154
  also have "\<dots> = n * fact n + fact n"
3ca3bc795908 move Stirling numbers from AFP/Discrete_Summation
hoelzl
parents:
diff changeset
   155
  proof -
3ca3bc795908 move Stirling numbers from AFP/Discrete_Summation
hoelzl
parents:
diff changeset
   156
    have "n * (\<Sum>k\<le>n. stirling n (Suc k)) = n * ((\<Sum>k\<le>Suc n. stirling n k) - stirling n 0)"
3ca3bc795908 move Stirling numbers from AFP/Discrete_Summation
hoelzl
parents:
diff changeset
   157
      by (metis add_diff_cancel_left' setsum_atMost_Suc_shift)
3ca3bc795908 move Stirling numbers from AFP/Discrete_Summation
hoelzl
parents:
diff changeset
   158
    also have "\<dots> = n * (\<Sum>k\<le>n. stirling n k)" by (cases n) simp+
3ca3bc795908 move Stirling numbers from AFP/Discrete_Summation
hoelzl
parents:
diff changeset
   159
    also have "\<dots> = n * fact n" using Suc.hyps by simp
3ca3bc795908 move Stirling numbers from AFP/Discrete_Summation
hoelzl
parents:
diff changeset
   160
    finally have "n * (\<Sum>k\<le>n. stirling n (Suc k)) = n * fact n" .
3ca3bc795908 move Stirling numbers from AFP/Discrete_Summation
hoelzl
parents:
diff changeset
   161
    moreover have "(\<Sum>k\<le>n. stirling n k) = fact n" using Suc.hyps .
3ca3bc795908 move Stirling numbers from AFP/Discrete_Summation
hoelzl
parents:
diff changeset
   162
    ultimately show ?thesis by simp
3ca3bc795908 move Stirling numbers from AFP/Discrete_Summation
hoelzl
parents:
diff changeset
   163
  qed
3ca3bc795908 move Stirling numbers from AFP/Discrete_Summation
hoelzl
parents:
diff changeset
   164
  also have "\<dots> = fact (Suc n)" by simp
3ca3bc795908 move Stirling numbers from AFP/Discrete_Summation
hoelzl
parents:
diff changeset
   165
  finally show ?case .
3ca3bc795908 move Stirling numbers from AFP/Discrete_Summation
hoelzl
parents:
diff changeset
   166
qed
3ca3bc795908 move Stirling numbers from AFP/Discrete_Summation
hoelzl
parents:
diff changeset
   167
3ca3bc795908 move Stirling numbers from AFP/Discrete_Summation
hoelzl
parents:
diff changeset
   168
lemma stirling_pochhammer:
3ca3bc795908 move Stirling numbers from AFP/Discrete_Summation
hoelzl
parents:
diff changeset
   169
  "(\<Sum>k\<le>n. of_nat (stirling n k) * x ^ k) = (pochhammer x n :: 'a :: comm_semiring_1)"
3ca3bc795908 move Stirling numbers from AFP/Discrete_Summation
hoelzl
parents:
diff changeset
   170
proof (induction n)
3ca3bc795908 move Stirling numbers from AFP/Discrete_Summation
hoelzl
parents:
diff changeset
   171
  case (Suc n)
3ca3bc795908 move Stirling numbers from AFP/Discrete_Summation
hoelzl
parents:
diff changeset
   172
  have "of_nat (n * stirling n 0) = (0 :: 'a)" by (cases n) simp_all
3ca3bc795908 move Stirling numbers from AFP/Discrete_Summation
hoelzl
parents:
diff changeset
   173
  hence "(\<Sum>k\<le>Suc n. of_nat (stirling (Suc n) k) * x ^ k) =
3ca3bc795908 move Stirling numbers from AFP/Discrete_Summation
hoelzl
parents:
diff changeset
   174
            (of_nat (n * stirling n 0) * x ^ 0 +
3ca3bc795908 move Stirling numbers from AFP/Discrete_Summation
hoelzl
parents:
diff changeset
   175
            (\<Sum>i\<le>n. of_nat (n * stirling n (Suc i)) * (x ^ Suc i))) +
3ca3bc795908 move Stirling numbers from AFP/Discrete_Summation
hoelzl
parents:
diff changeset
   176
            (\<Sum>i\<le>n. of_nat (stirling n i) * (x ^ Suc i))"
3ca3bc795908 move Stirling numbers from AFP/Discrete_Summation
hoelzl
parents:
diff changeset
   177
    by (subst setsum_atMost_Suc_shift) (simp add: setsum.distrib ring_distribs)
3ca3bc795908 move Stirling numbers from AFP/Discrete_Summation
hoelzl
parents:
diff changeset
   178
  also have "\<dots> = pochhammer x (Suc n)"
3ca3bc795908 move Stirling numbers from AFP/Discrete_Summation
hoelzl
parents:
diff changeset
   179
    by (subst setsum_atMost_Suc_shift [symmetric])
3ca3bc795908 move Stirling numbers from AFP/Discrete_Summation
hoelzl
parents:
diff changeset
   180
       (simp add: algebra_simps setsum.distrib setsum_right_distrib pochhammer_Suc Suc [symmetric])
3ca3bc795908 move Stirling numbers from AFP/Discrete_Summation
hoelzl
parents:
diff changeset
   181
  finally show ?case .
3ca3bc795908 move Stirling numbers from AFP/Discrete_Summation
hoelzl
parents:
diff changeset
   182
qed simp_all
3ca3bc795908 move Stirling numbers from AFP/Discrete_Summation
hoelzl
parents:
diff changeset
   183
3ca3bc795908 move Stirling numbers from AFP/Discrete_Summation
hoelzl
parents:
diff changeset
   184
3ca3bc795908 move Stirling numbers from AFP/Discrete_Summation
hoelzl
parents:
diff changeset
   185
text \<open>A row of the Stirling number triangle\<close>
3ca3bc795908 move Stirling numbers from AFP/Discrete_Summation
hoelzl
parents:
diff changeset
   186
3ca3bc795908 move Stirling numbers from AFP/Discrete_Summation
hoelzl
parents:
diff changeset
   187
definition stirling_row :: "nat \<Rightarrow> nat list" where
3ca3bc795908 move Stirling numbers from AFP/Discrete_Summation
hoelzl
parents:
diff changeset
   188
  "stirling_row n = [stirling n k. k \<leftarrow> [0..<Suc n]]"
3ca3bc795908 move Stirling numbers from AFP/Discrete_Summation
hoelzl
parents:
diff changeset
   189
3ca3bc795908 move Stirling numbers from AFP/Discrete_Summation
hoelzl
parents:
diff changeset
   190
lemma nth_stirling_row: "k \<le> n \<Longrightarrow> stirling_row n ! k = stirling n k"
3ca3bc795908 move Stirling numbers from AFP/Discrete_Summation
hoelzl
parents:
diff changeset
   191
  by (simp add: stirling_row_def del: upt_Suc)
3ca3bc795908 move Stirling numbers from AFP/Discrete_Summation
hoelzl
parents:
diff changeset
   192
3ca3bc795908 move Stirling numbers from AFP/Discrete_Summation
hoelzl
parents:
diff changeset
   193
lemma length_stirling_row [simp]: "length (stirling_row n) = Suc n"
3ca3bc795908 move Stirling numbers from AFP/Discrete_Summation
hoelzl
parents:
diff changeset
   194
  by (simp add: stirling_row_def)
3ca3bc795908 move Stirling numbers from AFP/Discrete_Summation
hoelzl
parents:
diff changeset
   195
3ca3bc795908 move Stirling numbers from AFP/Discrete_Summation
hoelzl
parents:
diff changeset
   196
lemma stirling_row_nonempty [simp]: "stirling_row n \<noteq> []"
3ca3bc795908 move Stirling numbers from AFP/Discrete_Summation
hoelzl
parents:
diff changeset
   197
  using length_stirling_row[of n] by (auto simp del: length_stirling_row)
3ca3bc795908 move Stirling numbers from AFP/Discrete_Summation
hoelzl
parents:
diff changeset
   198
3ca3bc795908 move Stirling numbers from AFP/Discrete_Summation
hoelzl
parents:
diff changeset
   199
(* TODO Move *)
3ca3bc795908 move Stirling numbers from AFP/Discrete_Summation
hoelzl
parents:
diff changeset
   200
lemma list_ext:
3ca3bc795908 move Stirling numbers from AFP/Discrete_Summation
hoelzl
parents:
diff changeset
   201
  assumes "length xs = length ys"
3ca3bc795908 move Stirling numbers from AFP/Discrete_Summation
hoelzl
parents:
diff changeset
   202
  assumes "\<And>i. i < length xs \<Longrightarrow> xs ! i = ys ! i"
3ca3bc795908 move Stirling numbers from AFP/Discrete_Summation
hoelzl
parents:
diff changeset
   203
  shows   "xs = ys"
3ca3bc795908 move Stirling numbers from AFP/Discrete_Summation
hoelzl
parents:
diff changeset
   204
using assms
3ca3bc795908 move Stirling numbers from AFP/Discrete_Summation
hoelzl
parents:
diff changeset
   205
proof (induction rule: list_induct2)
3ca3bc795908 move Stirling numbers from AFP/Discrete_Summation
hoelzl
parents:
diff changeset
   206
  case (Cons x xs y ys)
3ca3bc795908 move Stirling numbers from AFP/Discrete_Summation
hoelzl
parents:
diff changeset
   207
  from Cons.prems[of 0] have "x = y" by simp
3ca3bc795908 move Stirling numbers from AFP/Discrete_Summation
hoelzl
parents:
diff changeset
   208
  moreover from Cons.prems[of "Suc i" for i] have "xs = ys" by (intro Cons.IH) simp
3ca3bc795908 move Stirling numbers from AFP/Discrete_Summation
hoelzl
parents:
diff changeset
   209
  ultimately show ?case by simp
3ca3bc795908 move Stirling numbers from AFP/Discrete_Summation
hoelzl
parents:
diff changeset
   210
qed simp_all
3ca3bc795908 move Stirling numbers from AFP/Discrete_Summation
hoelzl
parents:
diff changeset
   211
3ca3bc795908 move Stirling numbers from AFP/Discrete_Summation
hoelzl
parents:
diff changeset
   212
3ca3bc795908 move Stirling numbers from AFP/Discrete_Summation
hoelzl
parents:
diff changeset
   213
subsubsection \<open>Efficient code\<close>
3ca3bc795908 move Stirling numbers from AFP/Discrete_Summation
hoelzl
parents:
diff changeset
   214
3ca3bc795908 move Stirling numbers from AFP/Discrete_Summation
hoelzl
parents:
diff changeset
   215
text \<open>
3ca3bc795908 move Stirling numbers from AFP/Discrete_Summation
hoelzl
parents:
diff changeset
   216
  Naively using the defining equations of the Stirling numbers of the first kind to
3ca3bc795908 move Stirling numbers from AFP/Discrete_Summation
hoelzl
parents:
diff changeset
   217
  compute them leads to exponential run time due to repeated computations.
3ca3bc795908 move Stirling numbers from AFP/Discrete_Summation
hoelzl
parents:
diff changeset
   218
  We can use memoisation to compute them row by row without repeating computations, at
3ca3bc795908 move Stirling numbers from AFP/Discrete_Summation
hoelzl
parents:
diff changeset
   219
  the cost of computing a few unneeded values.
3ca3bc795908 move Stirling numbers from AFP/Discrete_Summation
hoelzl
parents:
diff changeset
   220
3ca3bc795908 move Stirling numbers from AFP/Discrete_Summation
hoelzl
parents:
diff changeset
   221
  As a bonus, this is very efficient for applications where an entire row of
3ca3bc795908 move Stirling numbers from AFP/Discrete_Summation
hoelzl
parents:
diff changeset
   222
  Stirling numbers is needed..
3ca3bc795908 move Stirling numbers from AFP/Discrete_Summation
hoelzl
parents:
diff changeset
   223
\<close>
3ca3bc795908 move Stirling numbers from AFP/Discrete_Summation
hoelzl
parents:
diff changeset
   224
3ca3bc795908 move Stirling numbers from AFP/Discrete_Summation
hoelzl
parents:
diff changeset
   225
definition zip_with_prev :: "('a \<Rightarrow> 'a \<Rightarrow> 'b) \<Rightarrow> 'a \<Rightarrow> 'a list \<Rightarrow> 'b list" where
3ca3bc795908 move Stirling numbers from AFP/Discrete_Summation
hoelzl
parents:
diff changeset
   226
  "zip_with_prev f x xs = map (\<lambda>(x,y). f x y) (zip (x # xs) xs)"
3ca3bc795908 move Stirling numbers from AFP/Discrete_Summation
hoelzl
parents:
diff changeset
   227
3ca3bc795908 move Stirling numbers from AFP/Discrete_Summation
hoelzl
parents:
diff changeset
   228
lemma zip_with_prev_altdef:
3ca3bc795908 move Stirling numbers from AFP/Discrete_Summation
hoelzl
parents:
diff changeset
   229
  "zip_with_prev f x xs =
3ca3bc795908 move Stirling numbers from AFP/Discrete_Summation
hoelzl
parents:
diff changeset
   230
     (if xs = [] then [] else f x (hd xs) # [f (xs!i) (xs!(i+1)). i \<leftarrow> [0..<length xs - 1]])"
3ca3bc795908 move Stirling numbers from AFP/Discrete_Summation
hoelzl
parents:
diff changeset
   231
proof (cases xs)
3ca3bc795908 move Stirling numbers from AFP/Discrete_Summation
hoelzl
parents:
diff changeset
   232
  case (Cons y ys)
3ca3bc795908 move Stirling numbers from AFP/Discrete_Summation
hoelzl
parents:
diff changeset
   233
  hence "zip_with_prev f x xs = f x (hd xs) # zip_with_prev f y ys"
3ca3bc795908 move Stirling numbers from AFP/Discrete_Summation
hoelzl
parents:
diff changeset
   234
    by (simp add: zip_with_prev_def)
3ca3bc795908 move Stirling numbers from AFP/Discrete_Summation
hoelzl
parents:
diff changeset
   235
  also have "zip_with_prev f y ys = map (\<lambda>i. f (xs ! i) (xs ! (i + 1))) [0..<length xs - 1]"
3ca3bc795908 move Stirling numbers from AFP/Discrete_Summation
hoelzl
parents:
diff changeset
   236
    unfolding Cons
3ca3bc795908 move Stirling numbers from AFP/Discrete_Summation
hoelzl
parents:
diff changeset
   237
    by (induction ys arbitrary: y)
3ca3bc795908 move Stirling numbers from AFP/Discrete_Summation
hoelzl
parents:
diff changeset
   238
       (simp_all add: zip_with_prev_def upt_conv_Cons map_Suc_upt [symmetric] del: upt_Suc)
3ca3bc795908 move Stirling numbers from AFP/Discrete_Summation
hoelzl
parents:
diff changeset
   239
  finally show ?thesis using Cons by simp
3ca3bc795908 move Stirling numbers from AFP/Discrete_Summation
hoelzl
parents:
diff changeset
   240
qed (simp add: zip_with_prev_def)
3ca3bc795908 move Stirling numbers from AFP/Discrete_Summation
hoelzl
parents:
diff changeset
   241
3ca3bc795908 move Stirling numbers from AFP/Discrete_Summation
hoelzl
parents:
diff changeset
   242
3ca3bc795908 move Stirling numbers from AFP/Discrete_Summation
hoelzl
parents:
diff changeset
   243
primrec stirling_row_aux where
3ca3bc795908 move Stirling numbers from AFP/Discrete_Summation
hoelzl
parents:
diff changeset
   244
  "stirling_row_aux n y [] = [1]"
3ca3bc795908 move Stirling numbers from AFP/Discrete_Summation
hoelzl
parents:
diff changeset
   245
| "stirling_row_aux n y (x#xs) = (y + n * x) # stirling_row_aux n x xs"
3ca3bc795908 move Stirling numbers from AFP/Discrete_Summation
hoelzl
parents:
diff changeset
   246
3ca3bc795908 move Stirling numbers from AFP/Discrete_Summation
hoelzl
parents:
diff changeset
   247
lemma stirling_row_aux_correct:
3ca3bc795908 move Stirling numbers from AFP/Discrete_Summation
hoelzl
parents:
diff changeset
   248
  "stirling_row_aux n y xs = zip_with_prev (\<lambda>a b. a + n * b) y xs @ [1]"
3ca3bc795908 move Stirling numbers from AFP/Discrete_Summation
hoelzl
parents:
diff changeset
   249
  by (induction xs arbitrary: y) (simp_all add: zip_with_prev_def)
3ca3bc795908 move Stirling numbers from AFP/Discrete_Summation
hoelzl
parents:
diff changeset
   250
3ca3bc795908 move Stirling numbers from AFP/Discrete_Summation
hoelzl
parents:
diff changeset
   251
lemma stirling_row_code [code]:
3ca3bc795908 move Stirling numbers from AFP/Discrete_Summation
hoelzl
parents:
diff changeset
   252
  "stirling_row 0 = [1]"
3ca3bc795908 move Stirling numbers from AFP/Discrete_Summation
hoelzl
parents:
diff changeset
   253
  "stirling_row (Suc n) = stirling_row_aux n 0 (stirling_row n)"
3ca3bc795908 move Stirling numbers from AFP/Discrete_Summation
hoelzl
parents:
diff changeset
   254
proof -
3ca3bc795908 move Stirling numbers from AFP/Discrete_Summation
hoelzl
parents:
diff changeset
   255
  have "stirling_row (Suc n) =
3ca3bc795908 move Stirling numbers from AFP/Discrete_Summation
hoelzl
parents:
diff changeset
   256
          0 # [stirling_row n ! i + stirling_row n ! (i+1) * n. i \<leftarrow> [0..<n]] @ [1]"
3ca3bc795908 move Stirling numbers from AFP/Discrete_Summation
hoelzl
parents:
diff changeset
   257
  proof (rule list_ext, goal_cases length nth)
3ca3bc795908 move Stirling numbers from AFP/Discrete_Summation
hoelzl
parents:
diff changeset
   258
    case (nth i)
3ca3bc795908 move Stirling numbers from AFP/Discrete_Summation
hoelzl
parents:
diff changeset
   259
    from nth have "i \<le> Suc n" by simp
3ca3bc795908 move Stirling numbers from AFP/Discrete_Summation
hoelzl
parents:
diff changeset
   260
    then consider "i = 0" | j where "i > 0" "i \<le> n" | "i = Suc n" by linarith
3ca3bc795908 move Stirling numbers from AFP/Discrete_Summation
hoelzl
parents:
diff changeset
   261
    thus ?case
3ca3bc795908 move Stirling numbers from AFP/Discrete_Summation
hoelzl
parents:
diff changeset
   262
    proof cases
3ca3bc795908 move Stirling numbers from AFP/Discrete_Summation
hoelzl
parents:
diff changeset
   263
      assume i: "i > 0" "i \<le> n"
3ca3bc795908 move Stirling numbers from AFP/Discrete_Summation
hoelzl
parents:
diff changeset
   264
      from this show ?thesis by (cases i) (simp_all add: nth_append nth_stirling_row)
3ca3bc795908 move Stirling numbers from AFP/Discrete_Summation
hoelzl
parents:
diff changeset
   265
    qed (simp_all add: nth_stirling_row nth_append)
3ca3bc795908 move Stirling numbers from AFP/Discrete_Summation
hoelzl
parents:
diff changeset
   266
  qed simp
3ca3bc795908 move Stirling numbers from AFP/Discrete_Summation
hoelzl
parents:
diff changeset
   267
  also have "0 # [stirling_row n ! i + stirling_row n ! (i+1) * n. i \<leftarrow> [0..<n]] @ [1] =
3ca3bc795908 move Stirling numbers from AFP/Discrete_Summation
hoelzl
parents:
diff changeset
   268
               zip_with_prev (\<lambda>a b. a + n * b) 0 (stirling_row n) @ [1]"
3ca3bc795908 move Stirling numbers from AFP/Discrete_Summation
hoelzl
parents:
diff changeset
   269
    by (cases n) (auto simp add: zip_with_prev_altdef stirling_row_def hd_map simp del: upt_Suc)
3ca3bc795908 move Stirling numbers from AFP/Discrete_Summation
hoelzl
parents:
diff changeset
   270
  also have "\<dots> = stirling_row_aux n 0 (stirling_row n)"
3ca3bc795908 move Stirling numbers from AFP/Discrete_Summation
hoelzl
parents:
diff changeset
   271
    by (simp add: stirling_row_aux_correct)
3ca3bc795908 move Stirling numbers from AFP/Discrete_Summation
hoelzl
parents:
diff changeset
   272
  finally show "stirling_row (Suc n) = stirling_row_aux n 0 (stirling_row n)" .
3ca3bc795908 move Stirling numbers from AFP/Discrete_Summation
hoelzl
parents:
diff changeset
   273
qed (simp add: stirling_row_def)
3ca3bc795908 move Stirling numbers from AFP/Discrete_Summation
hoelzl
parents:
diff changeset
   274
3ca3bc795908 move Stirling numbers from AFP/Discrete_Summation
hoelzl
parents:
diff changeset
   275
lemma stirling_code [code]:
3ca3bc795908 move Stirling numbers from AFP/Discrete_Summation
hoelzl
parents:
diff changeset
   276
  "stirling n k = (if k = 0 then if n = 0 then 1 else 0
3ca3bc795908 move Stirling numbers from AFP/Discrete_Summation
hoelzl
parents:
diff changeset
   277
                   else if k > n then 0 else if k = n then 1
3ca3bc795908 move Stirling numbers from AFP/Discrete_Summation
hoelzl
parents:
diff changeset
   278
                   else stirling_row n ! k)"
3ca3bc795908 move Stirling numbers from AFP/Discrete_Summation
hoelzl
parents:
diff changeset
   279
  by (simp add: nth_stirling_row)
3ca3bc795908 move Stirling numbers from AFP/Discrete_Summation
hoelzl
parents:
diff changeset
   280
3ca3bc795908 move Stirling numbers from AFP/Discrete_Summation
hoelzl
parents:
diff changeset
   281
end