Theory Lambert_Series_Library

section ‹Missing Library Material›
theory Lambert_Series_Library
imports 
  "HOL-Complex_Analysis.Complex_Analysis"
  "HOL-Library.Landau_Symbols"
  "HOL-Real_Asymp.Real_Asymp"
begin

subsection ‹Miscellaneous›

lemma power_less_1_iff: "x  0  (x :: real) ^ n < 1  x < 1  n > 0"
  by (metis not_gr_zero not_less_iff_gr_or_eq power_0 real_root_lt_1_iff real_root_pos2)

lemma fls_nth_sum: "fls_nth (xA. f x) n = (xA. fls_nth (f x) n)"
  by (induction A rule: infinite_finite_induct) auto

lemma two_times_choose_two: "2 * (n choose 2) = n * (n - 1)"
  unfolding choose_two by (simp add: algebra_simps)

lemma Nats_not_empty [simp]: "  {}"
  using Nats_1 by blast


subsection ‹Infinite sums›

lemma has_sum_iff: "(f has_sum S) A  f summable_on A  infsum f A = S"
  using infsumI summable_iff_has_sum_infsum by blast
  
lemma summable_on_reindex_bij_witness:
  assumes "a. a  S  i (j a) = a"
  assumes "a. a  S  j a  T"
  assumes "b. b  T  j (i b) = b"
  assumes "b. b  T  i b  S"
  assumes "a. a  S  h (j a) = g a"
  shows   "g summable_on S  h summable_on T"
  using has_sum_reindex_bij_witness[of S i j T h g, OF assms refl]
  by (simp add: summable_on_def)

lemma has_sum_diff:
  fixes f g :: "'a  'b::{topological_ab_group_add}"
  assumes (f has_sum a) A
  assumes (g has_sum b) A
  shows ((λx. f x - g x) has_sum (a - b)) A
  using has_sum_add[of f A a "λx. -g x" "-b"] assms by (simp add: has_sum_uminus)

lemma summable_on_diff:
  fixes f g :: "'a  'b::{topological_ab_group_add}"
  assumes f summable_on A
  assumes g summable_on A
  shows (λx. f x - g x) summable_on A
  by (metis (full_types) assms summable_on_def has_sum_diff)

lemma infsum_diff:
  fixes f g :: "'a  'b::{topological_ab_group_add, t2_space}"
  assumes f summable_on A
  assumes g summable_on A
  shows infsum (λx. f x - g x) A = infsum f A - infsum g A
proof -
  have ((λx. f x - g x) has_sum (infsum f A - infsum g A)) A
    by (simp add: assms has_sum_diff)
  then show ?thesis
    using infsumI by blast
qed

lemma summable_norm_add:
  assumes "summable (λn. norm (f n))" "summable (λn. norm (g n))"
  shows   "summable (λn. norm (f n + g n))"
proof (rule summable_comparison_test)
  show "summable (λn. norm (f n) + norm (g n))"
    by (intro summable_add assms)
  show "N. nN. norm (norm (f n + g n))  norm (f n) + norm (g n)"
    by (intro exI[of _ 0] allI impI) (auto simp: norm_triangle_ineq)
qed

lemma summable_norm_diff:
  assumes "summable (λn. norm (f n))" "summable (λn. norm (g n))"
  shows   "summable (λn. norm (f n - g n))"
  using summable_norm_add[of f "λn. -g n"] assms by simp

lemma sums_imp_has_prod_exp:
  fixes f :: "_ 'a::{real_normed_field,banach}"
  assumes "f sums F"
  shows   "(λn. exp (f n)) has_prod exp F"
proof -
  have "(λn. exp (in. f i))  exp F"
    by (intro tendsto_intros) (use assms in auto simp: sums_def' atLeast0AtMost)
  also have "(λn. exp (in. f i)) = (λn. in. exp (f i))"
    by (simp add: exp_sum)
  finally have "raw_has_prod (λn. exp (f n)) 0 (exp F)"
    unfolding raw_has_prod_def by auto
  thus ?thesis
    unfolding has_prod_def by blast
qed

lemma telescope_summable_iff:
  fixes f :: "nat  'a::{real_normed_vector}"
  shows "summable (λn. f (Suc n) - f n)  convergent f"
proof
  assume "convergent f"
  thus "summable (λn. f (Suc n) - f n)"
    using telescope_summable[of f] by (auto simp: convergent_def)
next
  assume "summable (λn. f (Suc n) - f n)"
  hence "convergent (λn. i<n. f (Suc i) - f i)"
    by (simp add: summable_iff_convergent)
  also have "(λn. i<n. f (Suc i) - f i) = (λn. f n - f 0)"
    by (subst sum_lessThan_telescope) auto
  also have "convergent   convergent f"
    by (rule convergent_diff_const_right_iff)
  finally show "convergent f" .
qed

lemma telescope_summable_iff':
  fixes f :: "nat  'a::{real_normed_vector}"
  shows "summable (λn. f n - f (Suc n))  convergent f"
  using telescope_summable_iff[of "λn. -f n"] by (simp flip: convergent_minus_iff)

lemma norm_summable_mult_bounded:
  assumes "summable (λn. norm (f n))"
  assumes "g  O(λ_. 1)"
  shows   "summable (λn. norm (f n * g n))"
proof -
  from assms(2) obtain C where C: "C > 0" "eventually (λn. norm (g n)  C) at_top"
    by (auto elim!: landau_o.bigE)
  show ?thesis
  proof (rule summable_comparison_test_ev)
    show "summable (λn. norm (f n) * C)"
      by (subst mult.commute) (intro summable_mult assms)
    show "eventually (λn. norm (norm (f n * g n))  norm (f n) * C) at_top"
      using C(2) by eventually_elim (use C(1) in auto intro!: mult_mono simp: norm_mult)
  qed
qed

lemma summable_powser_comparison_test_bigo:
  fixes f g :: "nat  'a :: {real_normed_field, banach}"
  assumes "summable f" "g  O(λn. f n * c ^ n)" "norm c < 1"
  shows   "summable (λn. norm (g n))"
proof (rule summable_comparison_test_bigo)
  have "summable (λn. norm (f n * c ^ n))"
    by (rule powser_insidea[of _ 1]) (use assms in auto)
  thus "summable (λn. norm (norm (f n * c ^ n)))"
    by simp
  show "(λn. norm (g n))  O(λn. norm (f n * c ^ n))"
    using assms(2) by simp
qed
  
lemma geometric_sums_gen:
  assumes "norm (x :: 'a :: real_normed_field) < 1"
  shows   "(λn. x ^ (n + k)) sums (x ^ k / (1 - x))"
proof -
  have "(λn. x ^ k * x ^ n) sums (x ^ k * (1 / (1 - x)))"
    by (intro sums_mult geometric_sums assms)
  thus ?thesis
    by (simp add: power_add mult_ac)
qed

lemma has_sum_geometric:
  fixes x :: "'a :: {real_normed_field, banach}"
  assumes "norm x < 1"
  shows   "((λn. x ^ n) has_sum (x ^ m / (1 - x))) {m..}"
proof -
  have "((λn. x ^ n) has_sum (1 / (1 - x))) UNIV"
    using assms
    by (intro norm_summable_imp_has_sum)
       (auto intro: geometric_sums summable_geometric simp: norm_power)
  hence "((λn. x ^ m * x ^ n) has_sum (x ^ m * (1 / (1 - x)))) UNIV"
    by (rule has_sum_cmult_right)
  also have "?this  ?thesis"
    by (rule has_sum_reindex_bij_witness[of _ "λn. n - m" "λn. n + m"]) (auto simp: power_add)
  finally show ?thesis .
qed

lemma n_powser_sums:
  fixes q :: "'a :: {real_normed_field,banach}"
  assumes q: "norm q < 1"
  shows   "(λn. of_nat n * q ^ n) sums (q / (1 - q) ^ 2)"
proof -
  have "(λn. q * (of_nat (Suc n) * q ^ n)) sums (q * (1 / (1 - q)2))"
    using q by (intro sums_mult geometric_deriv_sums)
  also have "(λn. q * (of_nat (Suc n) * q ^ n)) = (λn. of_nat (Suc n) * q ^ Suc n)"
    by (simp add: algebra_simps)
  finally have "(λn. of_nat n * q ^ n) sums (q * (1 / (1 - q)2) + of_nat 0 * q ^ 0)"
    by (rule sums_Suc)
  thus "(λn. of_nat n * q ^ n) sums (q / (1 - q) ^ 2)"
    by simp
qed


subsection ‹Convergence radius›

lemma tendsto_imp_conv_radius_eq:
  assumes "(λn. ereal (norm (f n) powr (1 / real n)))  c'" "c = inverse c'"
  shows   "conv_radius f = c"
proof -
  have "(λn. ereal (root n (norm (f n))))  c'"
  proof (rule Lim_transform_eventually)
    show "(λn. ereal (norm (f n) powr (1 / real n)))  c'"
      using assms by simp
    show "F x in sequentially. ereal (norm (f x) powr (1 / real x)) = 
                                ereal (root x (norm (f x)))"
      using eventually_gt_at_top[of 0] 
    proof eventually_elim
      case (elim n)
      show ?case using elim
        by (cases "f n = 0") (simp_all add: root_powr_inverse)
    qed
  qed
  thus ?thesis
    unfolding conv_radius_def using assms by (simp add: limsup_root_limit)
qed

lemma conv_radius_powr_real: "conv_radius (λn. real n powr a) = 1"
proof (rule tendsto_imp_conv_radius_eq)
  have "(λn. ereal ((real n powr a) powr (1 / real n)))  ereal 1"
    by (rule tendsto_ereal) real_asymp
  thus "(λn. ereal (norm (real n powr a) powr (1 / real n)))  ereal 1"
    by simp
qed (simp_all add: one_ereal_def)

lemma conv_radius_one_over: "conv_radius (λn. 1 / of_nat n :: 'a :: {real_normed_field, banach}) = 1"
proof (rule tendsto_imp_conv_radius_eq)
  have "(λn. ereal ((1 / n) powr (1 / real n)))  ereal 1"
    by (rule tendsto_ereal) real_asymp
  thus "(λn. ereal (norm (1 / of_nat n :: 'a) powr (1 / real n)))  ereal 1"
    by (simp add: norm_divide)
qed (simp_all add: one_ereal_def)

lemma conv_radius_mono:
  assumes "eventually (λn. norm (f n)  norm (g n)) sequentially"
  shows   "conv_radius f  conv_radius g"
  unfolding conv_radius_def
proof (rule ereal_inverse_antimono[OF _ Limsup_mono])
  have "limsup (λn. 0)  limsup (λn. ereal (root n (norm (g n))))"
    by (rule Limsup_mono) (auto intro!: eventually_mono[OF eventually_gt_at_top[of 0]])
  thus "limsup (λn. ereal (root n (norm (g n))))  0"
    by (simp add: Limsup_const)
next
  show "F x in sequentially. ereal (root x (norm (g x)))  ereal (root x (norm (f x)))"
    using assms eventually_gt_at_top[of 0] by eventually_elim auto
qed

lemma conv_radius_const [simp]:
  assumes "c  0"
  shows   "conv_radius (λ_. c) = 1"
proof (rule tendsto_imp_conv_radius_eq)
  show "(λn. ereal (norm c powr (1 / real n)))  ereal 1"
    by (rule tendsto_ereal) (use assms in real_asymp)
qed auto

lemma conv_radius_bigo_polynomial:
  assumes "f  O(λn. of_nat n ^ k)"
  shows   "conv_radius f  1"
proof -
  from assms obtain C where ev: "C > 0" "eventually (λn. norm (f n)  C * real n ^ k) at_top"
    by (elim landau_o.bigE) (auto simp: norm_power)
  have "(λx. (C * real x ^ k) powr (1 / real x))  1"
    using ev(1) by real_asymp
  hence "conv_radius (λn. C * real n ^ k) = inverse (ereal 1)" using ev(1)
    by (intro tendsto_imp_conv_radius_eq[OF _ refl] tendsto_ereal)
       (simp add: norm_mult norm_power abs_mult)
  moreover have "conv_radius (λn. C * real n ^ k)  conv_radius f"
    by (intro conv_radius_mono eventually_mono[OF ev(2)]) auto
  ultimately show ?thesis
    by (simp add: one_ereal_def)
qed


subsection ‹Limits›

lemma oscillation_imp_not_tendsto:
  assumes "eventually (λn. f (g n)  A) sequentially" "filterlim g F sequentially"
  assumes "eventually (λn. f (h n)  B) sequentially" "filterlim h F sequentially"
  assumes "closed A" "closed B" "A  B = {}"
  shows   "¬filterlim f (nhds c) F"
proof
  assume *: "filterlim f (nhds c) F"
  have "filterlim (λn. f (g n)) (nhds c) sequentially"
    using * assms(2) by (rule filterlim_compose)
  with assms(1,5) have "c  A"
    by (metis Lim_in_closed_set sequentially_bot)
  have "filterlim (λn. f (h n)) (nhds c) sequentially"
    using * assms(4) by (rule filterlim_compose)
  with assms(3,6) have "c  B"
    by (metis Lim_in_closed_set sequentially_bot)
  with c  A and A  B = {} show False
    by blast
qed

lemma oscillation_imp_not_convergent:
  assumes "frequently (λn. f n  A) sequentially"
  assumes "frequently (λn. f n  B) sequentially"
  assumes "closed A" "closed B" "A  B = {}"
  shows   "¬convergent f"
proof -
  obtain g :: "nat  nat" where g: "strict_mono g" "n. f (g n)  A"
    using assms(1) infinite_enumerate
    unfolding cofinite_eq_sequentially [symmetric] INFM_iff_infinite
    by blast
  obtain h :: "nat  nat" where h: "strict_mono h" "n. f (h n)  B"
    using assms(2) infinite_enumerate
    unfolding cofinite_eq_sequentially [symmetric] INFM_iff_infinite
    by blast
  have "¬f  L" for L
  proof (rule oscillation_imp_not_tendsto)
    show "F n in sequentially. f (g n)  A" "F n in sequentially. f (h n)  B"
      using g h by auto
  qed (use g h assms in auto intro: filterlim_subseq)
  thus ?thesis
    unfolding convergent_def by blast
qed

lemma seq_bigo_1_iff:
  "g  O(λ_::nat. 1)  bounded (range g)"
proof
  assume "g  O(λ_. 1)"
  then obtain C where"eventually (λn. norm (g n)  C) at_top"
    by (elim landau_o.bigE) auto
  then obtain N where N: "n. n  N  norm (g n)  C" 
    by (auto simp: eventually_at_top_linorder)
  hence "norm (g n)  Max (insert C (norm ` g ` {..<N}))" for n
    by (cases "n < N") (auto simp: Max_ge_iff)
  thus "bounded (range g)"
    by (auto simp: bounded_iff)
next
  assume "bounded (range g)"
  then obtain C where "norm (g n)  C" for n
    by (auto simp: bounded_iff)
  thus "g  O(λ_. 1)"
    by (intro bigoI[where c = C]) auto
qed

lemma incseq_convergent':
  assumes "incseq (g :: nat  real)" "g  O(λ_. 1)"
  shows   "convergent g"
proof -
  from assms(2) have "bounded (range g)"
    by (simp add: seq_bigo_1_iff)
  then obtain C where C: "¦g n¦  C" for n
    unfolding bounded_iff by auto
  show ?thesis
  proof (rule incseq_convergent)
    show "incseq g"
      by fact
  next
    have "g i  C" for i :: nat
      using C[of i] by auto
    thus "i. g i  C"
      by blast
  qed (auto simp: convergent_def)
qed

lemma decseq_convergent':
  assumes "decseq (g :: nat  real)" "g  O(λ_. 1)"
  shows   "convergent g"
  using incseq_convergent'[of "λn. -g n "] assms
  by (simp flip: convergent_minus_iff add: decseq_eq_incseq)

lemma filterlim_of_int_iff:
  fixes c :: "'a :: real_normed_algebra_1"
  assumes "F  bot"
  shows "filterlim (λx. of_int (f x)) (nhds c) F 
           (c'. c = of_int c'  eventually (λx. f x = c') F)"
proof
  assume "c'. c = of_int c'  eventually (λx. f x = c') F"
  then obtain c' where c': "c = of_int c'" "eventually (λx. f x = c') F"
    by blast
  from c'(2) have "eventually (λx. of_int (f x) = c) F"
    by eventually_elim (auto simp: c'(1))
  thus "filterlim (λx. of_int (f x)) (nhds c) F"
    by (rule tendsto_eventually)    
next
  assume *: "filterlim (λx. of_int (f x)) (nhds c) F"
  show "(c'. c = of_int c'  eventually (λx. f x = c') F)"
  proof (cases "c  ")
    case False
    hence "setdist {c}  > 0"
      by (subst setdist_gt_0_compact_closed) auto
    with * have "eventually (λx. dist (of_int (f x)) c < setdist {c} ) F"
      unfolding tendsto_iff by blast
    then obtain x where "dist (of_int (f x)) c < setdist {c} "
      using F  bot eventually_happens by blast
    moreover have "dist c (of_int (f x))  setdist {c} "
      by (rule setdist_le_dist) auto
    ultimately show ?thesis
      by (simp add: dist_commute)
  next
    case True
    then obtain c' where c: "c = of_int c'"
      by (elim Ints_cases)
    have "eventually (λx. dist (of_int (f x)) c < 1) F"
      using * unfolding tendsto_iff by auto
    hence "eventually (λx. f x = c') F"
      by eventually_elim (auto simp: c dist_of_int)
    with c show ?thesis
      by auto
  qed
qed

lemma filterlim_of_nat_iff:
  fixes c :: "'a :: real_normed_algebra_1"
  assumes "F  bot"
  shows "filterlim (λx. of_nat (f x)) (nhds c) F 
           (c'. c = of_nat c'  eventually (λx. f x = c') F)"
proof
  assume "c'. c = of_nat c'  eventually (λx. f x = c') F"
  then obtain c' where c': "c = of_nat c'" "eventually (λx. f x = c') F"
    by blast
  from c'(2) have "eventually (λx. of_nat (f x) = c) F"
    by eventually_elim (auto simp: c'(1))
  thus "filterlim (λx. of_nat (f x)) (nhds c) F"
    by (rule tendsto_eventually)    
next
  assume *: "filterlim (λx. of_nat (f x)) (nhds c) F"
  show "(c'. c = of_nat c'  eventually (λx. f x = c') F)"
  proof (cases "c  ")
    case False
    hence "setdist {c}  > 0"
      by (subst setdist_gt_0_compact_closed) auto
    with * have "eventually (λx. dist (of_nat (f x)) c < setdist {c} ) F"
      unfolding tendsto_iff by blast
    then obtain x where "dist (of_nat (f x)) c < setdist {c} "
      using F  bot eventually_happens by blast
    moreover have "dist c (of_nat (f x))  setdist {c} "
      by (rule setdist_le_dist) auto
    ultimately show ?thesis
      by (simp add: dist_commute)
  next
    case True
    then obtain c' where c: "c = of_nat c'"
      by (elim Nats_cases)
    have "eventually (λx. dist (of_nat (f x)) c < 1) F"
      using * unfolding tendsto_iff by auto
    hence "eventually (λx. f x = c') F"
      by eventually_elim (auto simp: c dist_of_nat)
    with c show ?thesis
      by auto
  qed
qed

lemma uniform_limit_compose:
  assumes "uniform_limit B (λx y. f x y) (λy. f' y) F" "y. y  A  g y  B"
  shows   "uniform_limit A (λx y. f x (g y)) (λy. f' (g y)) F"
proof -
  have "uniform_limit (g ` A) (λx y. f x y) (λy. f' y) F"
    using assms(1) by (rule uniform_limit_on_subset) (use assms(2) in blast)
  thus "uniform_limit A (λx y. f x (g y)) (λy. f' (g y)) F"
    unfolding uniform_limit_iff by auto
qed

lemma uniform_limit_const':
  assumes "filterlim f (nhds c) F"
  shows   "uniform_limit A (λx y. f x) (λy. c) F"
proof -
  have "F n in F. xA. dist (f n) c < ε" if ε: "ε > 0" for ε :: real
  proof -
    from assms and ε have "F n in F. dist (f n) c < ε"
      unfolding tendsto_iff by blast
    thus ?thesis
      by eventually_elim auto
  qed
  thus ?thesis
    unfolding uniform_limit_iff by blast
qed

lemma uniform_limit_singleton_iff [simp]:
  "uniform_limit {x} f g F  filterlim (λy. f y x) (nhds (g x)) F"
  by (simp add: uniform_limit_iff tendsto_iff)

end