Theory Summation_Conversion
section ‹A barebone conversion for discrete summation›
theory Summation_Conversion
imports Factorials Discrete_Summation
begin
text ‹Extensible theorem collection for solving summation problems›
named_theorems summation "rules for solving summation problems"
declare
  Σ_const [summation] Σ_add [summation]
  Σ_factor [summation] monomial_ffact [summation]
lemma intervall_simps [summation]:
  "(∑k::nat = 0..0. f k) = f 0"
  "(∑k::nat = 0..Suc n. f k) = f (Suc n) + (∑k::nat = 0..n. f k)"
  by (simp_all add: add.commute)
lemma Δ_ffact:
  "Δ (ffact (Suc n)) k = of_nat (Suc n) * ffact n (of_int k :: 'a :: comm_ring_1)"
proof (induct n)
  case 0 then show ?case
    by (simp add: Δ_def ffact_Suc)
next
  case (Suc n)
  obtain m where "m = Suc n" by blast
  have "Δ (ffact (Suc m)) k =
    ffact (Suc m) (of_int (k + 1)) - ffact (Suc m) (of_int k :: 'a)" 
    by (simp add: Δ_def)
  also have "… = of_int (k + 1) * ffact m (of_int k)
    - (ffact m (of_int k) * (of_int k - of_nat m))"
    using ffact_Suc_rev [of m "(of_int k :: 'a :: comm_ring_1)"]
    by (simp add: ac_simps ffact_Suc)
  also have "… = (of_int k + 1 - of_int k + of_nat m) * ffact m (of_int k)"
    by (simp add: algebra_simps)
  also have "… = of_nat (Suc m) * ffact m (of_int k)" by simp
  also have "… = of_nat (Suc m) * ffact (Suc m - 1) (of_int k)" by simp
  finally show ?case by (simp only: ‹m = Suc n› diff_Suc_1)
qed
lemma Σ_ffact_divide [summation]:
  "Σ (ffact n) j l =
    (ffact (Suc n) (of_int l :: 'a :: {idom_divide, semiring_char_0}) - ffact (Suc n) (of_int j)) div of_nat (Suc n)"
proof -
  have *: "(of_nat (Suc n) * Σ (ffact n) j l) div of_nat (Suc n) = (Σ (ffact n) j l :: 'a)"
    using of_nat_neq_0 [where ?'a = 'a] by simp
  have "ffact (Suc n) (of_int l :: 'a) - ffact (Suc n) (of_int j) =
    Σ (λk. Δ (ffact (Suc n)) k) j l"
    by (simp add: Σ_Δ)
  also have "… = Σ (λk. of_nat (Suc n) * ffact n (of_int k)) j l"
    by (simp add: Δ_ffact)
  also have "… = of_nat (Suc n) * Σ (ffact n ∘ of_int) j l"
    by (simp add: Σ_factor comp_def)
  finally show ?thesis by (simp only: Σ_comp_of_int * of_nat_eq_0_iff)
qed
text ‹Various other rules›
lemma of_int_coeff:
  "(of_int l :: 'a::comm_ring_1) * numeral k = of_int (l * numeral k)"
  by simp
lemmas nat_simps =
  add_0_left add_0_right add_Suc add_Suc_right
  mult_Suc mult_Suc_right mult_zero_left mult_zero_right
  One_nat_def of_nat_simps
lemmas of_int_pull_out =
  of_int_add [symmetric] of_int_diff [symmetric] of_int_mult [symmetric]
  of_int_coeff
lemma of_nat_coeff:
  "(of_nat n :: 'a::comm_semiring_1) * numeral m = of_nat (n * numeral m)"
  by (induct n) simp_all
  
lemmas of_nat_pull_out =
  of_nat_add [symmetric] of_nat_mult [symmetric] of_nat_coeff
lemmas nat_pull_in =
  nat_int_add
lemmas of_int_pull_in =
  of_int_pull_out [symmetric] add_divide_distrib diff_divide_distrib of_int_power
  of_int_numeral of_int_neg_numeral times_divide_eq_left [symmetric]
  
text ‹Special for @{typ nat}›
definition lift_nat :: "(nat ⇒ nat) ⇒ int ⇒ int"
where
  "lift_nat f = int ∘ f ∘ nat"
definition Σ_nat :: "(nat ⇒ nat) ⇒ nat ⇒ nat ⇒ nat" (‹Σ⇩ℕ›)
where
  [summation]: "Σ⇩ℕ f m n = nat (Σ (lift_nat f) (int m) (int n))"  
definition pos_id :: "int ⇒ int"
where
  "pos_id k = (if k < 0 then 0 else k)"
lemma Σ_pos_id [summation]:
  "0 ≤ k ⟹ 0 ≤ l ⟹ Σ (λr. f (pos_id r)) k l = Σ f k l"
  by (simp add: Σ_def pos_id_def)
lemma [summation]:
  "(0::int) ≤ 0"
  "(0::int) ≤ 1"
  "(0::int) ≤ numeral m"
  "(0::int) ≤ int n"
  by simp_all
  
lemma [summation]:
  "lift_nat (λn. m) = (λk. int m)"
  by (simp add: lift_nat_def fun_eq_iff)
lemma [summation]:
  "lift_nat (λn. n) = pos_id"
  by (simp add: lift_nat_def fun_eq_iff pos_id_def)
lemma [summation]:
  "lift_nat (λn. f n + g n) = (λk. lift_nat f k + lift_nat g k)"
  by (simp add: lift_nat_def fun_eq_iff)
lemma [summation]:
  "lift_nat (λn. m * f n) = (λk. int m * lift_nat f k)"
  by (simp add: lift_nat_def fun_eq_iff)
lemma [summation]:
  "lift_nat (λn. f n * m) = (λk. lift_nat f k * int m)"
  by (simp add: lift_nat_def fun_eq_iff)
lemma [summation]:
  "lift_nat (λn. f n ^ m) = (λk. lift_nat f k ^ m)"
  by (simp add: lift_nat_def fun_eq_iff)
  
text ‹Generic conversion›  
ML ‹
signature SUMMATION =
sig
  val conv: Proof.context -> conv
end
structure Summation : SUMMATION =
struct
val simps2 = @{thms Stirling.simps ffact_0 ffact_Suc nat_simps};
val simpset3 =
  @{context}
  |> fold Simplifier.add_simp @{thms field_simps}
  |> Simplifier.simpset_of;
val simps4 = @{thms of_int_pull_out of_nat_pull_out nat_pull_in};
val simps6 = @{thms of_int_pull_in};
fun conv ctxt =
  let
    val ctxt1 =
      ctxt
      |> put_simpset HOL_basic_ss
      |> fold Simplifier.add_simp (Named_Theorems.get ctxt @{named_theorems summation})
    val ctxt2 =
      ctxt
      |> put_simpset HOL_basic_ss
      |> fold Simplifier.add_simp simps2
    val ctxt3 =
      ctxt
      |> put_simpset simpset3
    val ctxt4 =
      ctxt
      |> put_simpset HOL_basic_ss
      |> fold Simplifier.add_simp simps4
    val semiring_conv_base = Semiring_Normalizer.semiring_normalize_conv ctxt
    val semiring_conv = Conv.arg_conv (Conv.arg1_conv (Conv.arg_conv semiring_conv_base))
      else_conv Conv.arg1_conv (Conv.arg_conv semiring_conv_base)
      else_conv semiring_conv_base
    val ctxt6 =
      ctxt
      |> put_simpset HOL_basic_ss
      |> fold Simplifier.add_simp simps6
  in
     Simplifier.rewrite ctxt1
     then_conv Simplifier.rewrite ctxt2
     then_conv Simplifier.rewrite ctxt3
     then_conv Simplifier.rewrite ctxt4
     then_conv semiring_conv
     then_conv Simplifier.rewrite ctxt6
  end
end
›
hide_fact (open) nat_simps of_int_pull_out of_int_pull_in
end