Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 


Quelle  Infinite_Products.thy

  Sprache: Isabelle
 

(*File:      HOL/Analysis/Infinite_Product.thy
  Author: Manuel Eberl & LC Paulson
 
  Basic results about convergence and absolute convergence of infinite products
  and their connection to summability.
*)
section Infinite Products
theory Infinite_Products
  imports Topology_Euclidean_Space Complex_Transcendental
begin

subsection🍋tag unimportant Preliminaries

lemma sum_le_prod:
  fixes f :: "'a ==> 'b :: linordered_semidom"
  assumes "x. x A ==> f x 0"
  shows   "sum f A (xA. 1 + f x)"
  using assms
proof (induction A rule: infinite_finite_induct)
  case (insert x A)
  from insert.hyps have "sum f A + f x * (xA. 1) (xA. 1 + f x) + f x * (xA. 1 + f x)"
    by (intro add_mono insert mult_left_mono prod_mono) (auto intro: insert.prems)
  with insert.hyps show ?case by (simp add: algebra_simps)
qed simp_all

lemma prod_le_exp_sum:
  fixes f :: "'a ==> real"
  assumes "x. x A ==> f x 0"
  shows   "prod (λx. 1 + f x) A exp (sum f A)"
  using assms
proof (induction A rule: infinite_finite_induct)
  case (insert x A)
  have "(1 + f x) * (xA. 1 + f x) exp (f x) * exp (sum f A)"
    using insert.prems by (intro mult_mono insert prod_nonneg exp_ge_add_one_self) auto
  with insert.hyps show ?case by (simp add: algebra_simps exp_add)
qed simp_all

lemma lim_ln_1_plus_x_over_x_at_0: "(λx::real. ln (1 + x) / x) ←-0 1"
proof (rule lhopital)
  show "(λx::real. ln (1 + x)) ←-0 0"
    by (rule tendsto_eq_intros refl | simp)+
  have "eventually (λx::real. x {-1/2<..<1/2}) (nhds 0)"
    by (rule eventually_nhds_in_open) auto
  hence *: "eventually (λx::real. x {-1/2<..<1/2}) (at 0)"
    by (rule filter_leD [rotated]) (simp_all add: at_within_def)   
  show "eventually (λx::real. ((λx. ln (1 + x)) has_field_derivative inverse (1 + x)) (at x)) (at 0)"
    using * by eventually_elim (auto intro!: derivative_eq_intros simp: field_simps)
  show "eventually (λx::real. ((λx. x) has_field_derivative 1) (at x)) (at 0)"
    using * by eventually_elim (auto intro!: derivative_eq_intros simp: field_simps)
  show "🪙F x in at 0. x 0" by (auto simp: at_within_def eventually_inf_principal)
  show "(λx::real. inverse (1 + x) / 1) ←-0 1"
    by (rule tendsto_eq_intros refl | simp)+
qed auto

subsectionDefinitions and basic properties

definition🍋tag important raw_has_prod :: "[nat ==> 'a::{t2_space, comm_semiring_1}, nat, 'a] ==> bool" 
  where "raw_has_prod f M p (λn. in. f (i+M)) <---- p p 0"

textThe nonzero and zero cases, as in \emph{Complex Analysis} by Joseph Bak and Donald J.Newman, page 241
text🍋tag important %whitespace
definition🍋tag important
  has_prod :: "(nat ==> 'a::{t2_space, comm_semiring_1}) ==> 'a ==> bool" (infixr has'_prod 80)
  where "f has_prod p raw_has_prod f 0 p (i q. p = 0 f i = 0 raw_has_prod f (Suc i) q)"

definition🍋tag important convergent_prod :: "(nat ==> 'a :: {t2_space,comm_semiring_1}) ==> bool" where
  "convergent_prod f M p. raw_has_prod f M p"

definition🍋tag important prodinf :: "(nat ==> 'a::{t2_space, comm_semiring_1}) ==> 'a"
    (binder  10)
  where "prodinf f = (THE p. f has_prod p)"

lemmas prod_defs = raw_has_prod_def has_prod_def convergent_prod_def prodinf_def

lemma has_prod_subst[trans]: "f = g ==> g has_prod z ==> f has_prod z"
  by simp

lemma has_prod_cong: "(n. f n = g n) ==> f has_prod c g has_prod c"
  by presburger

lemma raw_has_prod_nonzero [simp]: "¬ raw_has_prod f M 0"
  by (simp add: raw_has_prod_def)

lemma raw_has_prod_eq_0:
  fixes f :: "nat ==> 'a::{semidom,t2_space}"
  assumes p: "raw_has_prod f m p" and i: "f i = 0" "i m"
  shows "p = 0"
proof -
  have eq0: "(kn. f (k+m)) = 0" if "i - m n" for n
  proof -
    have "kn. f (k + m) = 0"
      using i that by auto
    then show ?thesis
      by auto
  qed
  have "(λn. in. f (i + m)) <---- 0"
    by (rule LIMSEQ_offset [where k = "i-m"]) (simp add: eq0)
    with p show ?thesis
      unfolding raw_has_prod_def
    using LIMSEQ_unique by blast
qed

lemma raw_has_prod_Suc: 
  "raw_has_prod f (Suc M) a raw_has_prod (λn. f (Suc n)) M a"
  unfolding raw_has_prod_def by auto

lemma has_prod_0_iff: "f has_prod 0 (i. f i = 0 (p. raw_has_prod f (Suc i) p))"
  by (simp add: has_prod_def)
      
lemma has_prod_unique2: 
  fixes f :: "nat ==> 'a::{semidom,t2_space}"
  assumes "f has_prod a" "f has_prod b" shows "a = b"
  using assms
  by (auto simp: has_prod_def raw_has_prod_eq_0) (meson raw_has_prod_def sequentially_bot tendsto_unique)

lemma has_prod_unique:
  fixes f :: "nat ==> 'a :: {semidom,t2_space}"
  shows "f has_prod s ==> s = prodinf f"
  by (simp add: has_prod_unique2 prodinf_def the_equality)

lemma has_prod_eq_0_iff:
  fixes f :: "nat ==> 'a :: {semidom, comm_semiring_1, t2_space}"
  assumes "f has_prod P"
  shows   "P = 0 0 range f"
proof
  assume "0 range f"
  then obtain N where N: "f N = 0"
    by auto
  have "eventually (λn. n > N) at_top"
    by (rule eventually_gt_at_top)
  hence "eventually (λn. (k
    by eventually_elim (use N in auto)
  hence "(λn. k<---- 0"

    by (simp add: tendsto_eventually)
  moreover have "(λn. k<---- P"
    using assms by (metis N calculation prod_defs(2) raw_has_prod_eq_0 zero_le)
  ultimately show "P = 0"
    using tendsto_unique by force
qed (use assms in auto simp: has_prod_def)

lemma has_prod_0D:
  fixes f :: "nat ==> 'a :: {semidom, comm_semiring_1, t2_space}"
  shows "f has_prod 0 ==> 0 range f"
  using has_prod_eq_0_iff[of f 0] by auto

lemma has_prod_zeroI:
  fixes f :: "nat ==> 'a :: {semidom, comm_semiring_1, t2_space}"
  assumes "f has_prod P" "f n = 0"
  shows   "P = 0"
  using assms by (auto simp: has_prod_eq_0_iff)  

lemma raw_has_prod_in_Reals:
  assumes "raw_has_prod (complex_of_real z) M p"
  shows "p "
  using assms by (auto simp: raw_has_prod_def real_lim_sequentially)

lemma raw_has_prod_of_real_iff: "raw_has_prod (complex_of_real z) M (of_real p) raw_has_prod z M p"
  by (auto simp: raw_has_prod_def tendsto_of_real_iff simp flip: of_real_prod)

lemma convergent_prod_of_real_iff: "convergent_prod (complex_of_real z) convergent_prod z"
  by (smt (verit, best) Reals_cases convergent_prod_def raw_has_prod_in_Reals raw_has_prod_of_real_iff)

lemma convergent_prod_altdef:
  fixes f :: "nat ==> 'a :: {t2_space,comm_semiring_1}"
  shows "convergent_prod f (M L. (nM. f n 0) (λn. in. f (i+M)) <---- L L 0)"
proof
  assume "convergent_prod f"
  then obtain M L where *: "(λn. in. f (i+M)) <---- L" "L 0"
    by (auto simp: prod_defs)
  have "f i 0" if "i M" for i
  proof
    assume "f i = 0"
    have **: "eventually (λn. (in. f (i+M)) = 0) sequentially"
      using eventually_ge_at_top[of "i - M"]
    proof eventually_elim
      case (elim n)
      with f i = 0 and i M show ?case
        by (auto intro!: bexI[of _ "i - M"] prod_zero)
    qed
    have "(λn. (in. f (i+M))) <---- 0"
      unfolding filterlim_iff
      by (auto dest!: eventually_nhds_x_imp_x intro!: eventually_mono[OF **])
    from tendsto_unique[OF _ this *(1)] and *(2)
      show False by simp
  qed
  with * show "(M L. (nM. f n 0) (λn. in. f (i+M)) <---- L L 0)" 
    by blast
qed (auto simp: prod_defs)

lemma raw_has_prod_norm:
  fixes a :: "'a ::real_normed_field"
  assumes "raw_has_prod f M a"
  shows "raw_has_prod (λn. norm (f n)) M (norm a)"
  using assms by (auto simp: raw_has_prod_def prod_norm tendsto_norm)

lemma has_prod_norm:
  fixes a :: "'a ::real_normed_field"
  assumes f: "f has_prod a" 
  shows "(λn. norm (f n)) has_prod (norm a)"
  using f [unfolded has_prod_def]
proof (elim disjE exE conjE)
  assume f0: "raw_has_prod f 0 a"
  then show "(λn. norm (f n)) has_prod norm a"
    using has_prod_def raw_has_prod_norm by blast
next
  fix i p
  assume "a = 0" and "f i = 0" and p: "raw_has_prod f (Suc i) p"
  then have "Ex (raw_has_prod (λn. norm (f n)) (Suc i))"
    using raw_has_prod_norm by blast
  then show ?thesis
    by (metis a = 0 f i = 0 has_prod_0_iff norm_zero)
qed

lemma raw_has_prod_imp_nonzero:
  assumes "raw_has_prod f N P" "n N"
  shows   "f n 0"
proof
  assume "f n = 0"
  from assms(1) have lim: "(λm. (km. f (k + N))) <---- P" and "P 0"
    unfolding raw_has_prod_def by blast+
  have "eventually (λm. m n - N) at_top"
    by (rule eventually_ge_at_top)
  hence "eventually (λm. (km. f (k + N)) = 0) at_top"
  proof eventually_elim
    case (elim m)
    have "f ((n - N) + N) = 0" "n - N {..m}" "finite {..m}"
      using n N f n = 0 elim by auto
    thus "(km. f (k + N)) = 0"
      using prod_zero[of "{..m}" "λk. f (k + N)"by blast
  qed
  with lim have "P = 0"
    by (simp add: LIMSEQ_const_iff tendsto_cong)
  thus False
    using P 0 by contradiction
qed

lemma has_prod_imp_tendsto:
  fixes f :: "nat ==> 'a :: {semidom, t2_space}"
  assumes "f has_prod P"
  shows   "(λn. kn. f k) <---- P"
proof (cases "P = 0")
  case False
  with assms show ?thesis
    by (auto simp: has_prod_def raw_has_prod_def)
next
  case True
  with assms obtain N P' where "f N = 0" "raw_has_prod f (Suc N) P'"
    by (auto simp: has_prod_def)
  thus ?thesis
    using LIMSEQ_prod_0 True f N = 0 by blast
qed

lemma has_prod_imp_tendsto':
  fixes f :: "nat ==> 'a :: {semidom, t2_space}"
  assumes "f has_prod P"
  shows   "(λn. k<---- P"
  using has_prod_imp_tendsto[OF assms] LIMSEQ_lessThan_iff_atMost by blast

lemma has_prod_nonneg:
  assumes "f has_prod P" "n. f n (0::real)"
  shows   "P 0"
proof (rule tendsto_le)
  show "((λn. in. f i)) <---- P"
    using assms(1) by (rule has_prod_imp_tendsto)
  show "(λn. 0::real) <---- 0"
    by auto
qed (use assms in auto intro!: always_eventually prod_nonneg)

lemma has_prod_pos:
  assumes "f has_prod P" "n. f n > (0::real)"
  shows   "P > 0"
proof -
  have "P 0"
    by (rule has_prod_nonneg[OF assms(1)]) (auto intro!: less_imp_le assms(2))
  moreover have "f n 0" for n
    using assms(2)[of n] by auto
  hence "P 0"
    using has_prod_0_iff[of f] assms by auto
  ultimately show ?thesis
    by linarith
qed


subsectionAbsolutely convergent products

definition🍋tag important abs_convergent_prod :: "(nat ==> _) ==> bool" where
  "abs_convergent_prod f convergent_prod (λi. 1 + norm (f i - 1))"

lemma abs_convergent_prodI:
  assumes "convergent (λn. in. 1 + norm (f i - 1))"
  shows   "abs_convergent_prod f"
proof -
  from assms obtain L where L: "(λn. in. 1 + norm (f i - 1)) <---- L"
    by (auto simp: convergent_def)
  have "L 1"
  proof (rule tendsto_le)
    show "eventually (λn. (in. 1 + norm (f i - 1)) 1) sequentially"
    proof (intro always_eventually allI)
      fix n
      have "(in. 1 + norm (f i - 1)) (in. 1)"
        by (intro prod_mono) auto
      thus "(in. 1 + norm (f i - 1)) 1" by simp
    qed
  qed (use L in simp_all)
  hence "L 0" by auto
  with L show ?thesis unfolding abs_convergent_prod_def prod_defs
    by (intro exI[of _ "0::nat"] exI[of _ L]) auto
qed

lemma
  fixes f :: "nat ==> 'a :: {topological_semigroup_mult,t2_space,idom}"
  assumes "convergent_prod f"
  shows   convergent_prod_imp_convergent:     "convergent (λn. in. f i)"
    and   convergent_prod_to_zero_iff [simp]: "(λn. in. f i) <---- 0 (i. f i = 0)"
proof -
  from assms obtain M L 
    where M: "n. n M ==> f n 0" and "(λn. in. f (i + M)) <---- L" and "L 0"
    by (auto simp: convergent_prod_altdef)
  note this(2)
  also have "(λn. in. f (i + M)) = (λn. i=M..M+n. f i)"
    by (intro ext prod.reindex_bij_witness[of _ "λn. n - M" "λn. n + M"]) auto
  finally have "(λn. (ii=M..M+n. f i)) <---- (i
    by (intro tendsto_mult tendsto_const)
  also have "(λn. (ii=M..M+n. f i)) = (λn. (i{..∪{M..M+n}. f i))"
    by (subst prod.union_disjoint) auto
  also have "(λn. {.. {M..M+n}) = (λn. {..n+M})" by auto
  finally have lim: "(λn. prod f {..n}) <---- prod f {.. 
    by (rule LIMSEQ_offset)
  thus "convergent (λn. in. f i)"
    by (auto simp: convergent_def)

  show "(λn. in. f i) <---- 0 (i. f i = 0)"
  proof
    assume "i. f i = 0"
    then obtain i where "f i = 0" by auto
    moreover with M have "i < M" by (cases "i < M") auto
    ultimately have "(i by auto
    with lim show "(λn. in. f i) <---- 0" by simp
  next
    assume "(λn. in. f i) <---- 0"
    from tendsto_unique[OF _ this lim] and L 0
    show "i. f i = 0" by auto
  qed
qed

lemma convergent_prod_iff_nz_lim:
  fixes f :: "nat ==> 'a :: {topological_semigroup_mult,t2_space,idom}"
  assumes "i. f i 0"
  shows "convergent_prod f (L. (λn. in. f i) <---- L L 0)"
    (is "?lhs ?rhs")
proof
  assume ?lhs then show ?rhs
    using assms convergentD convergent_prod_imp_convergent convergent_prod_to_zero_iff by blast
next
  assume ?rhs then show ?lhs
    unfolding prod_defs
    by (rule_tac x=0 in exI) auto
qed

lemma🍋tag important convergent_prod_iff_convergent: 
  fixes f :: "nat ==> 'a :: {topological_semigroup_mult,t2_space,idom}"
  assumes "i. f i 0"
  shows "convergent_prod f convergent (λn. in. f i) lim (λn. in. f i) 0"
  by (force simp: convergent_prod_iff_nz_lim assms convergent_def limI)

lemma bounded_imp_convergent_prod:
  fixes a :: "nat ==> real"
  assumes 1: "n. a n 1" and bounded: "n. (in. a i) B"
  shows "convergent_prod a"
proof -
  have "bdd_above (range(λn. in. a i))"
    by (meson bdd_aboveI2 bounded)
  moreover have "incseq (λn. in. a i)"
    unfolding mono_def by (metis 1 prod_mono2 atMost_subset_iff dual_order.trans finite_atMost zero_le_one)
  ultimately obtain p where p: "(λn. in. a i) <---- p"
    using LIMSEQ_incseq_SUP by blast
  then have "p 0"
    by (metis "1" not_one_le_zero prod_ge_1 LIMSEQ_le_const)
  with 1 p show ?thesis
    by (metis convergent_prod_iff_nz_lim not_one_le_zero)
qed


lemma abs_convergent_prod_altdef:
  fixes f :: "nat ==> 'a :: {one,real_normed_vector}"
  shows  "abs_convergent_prod f convergent (λn. in. 1 + norm (f i - 1))"
proof
  assume "abs_convergent_prod f"
  thus "convergent (λn. in. 1 + norm (f i - 1))"
    by (auto simp: abs_convergent_prod_def intro!: convergent_prod_imp_convergent)
qed (auto intro: abs_convergent_prodI)

lemma Weierstrass_prod_ineq:
  fixes f :: "'a ==> real" 
  assumes "x. x A ==> f x {0..1}"
  shows   "1 - sum f A (xA. 1 - f x)"
  using assms
proof (induction A rule: infinite_finite_induct)
  case (insert x A)
  from insert.hyps and insert.prems 
    have "1 - sum f A + f x * (xA. 1 - f x) (xA. 1 - f x) + f x * (xA. 1)"
    by (intro insert.IH add_mono mult_left_mono prod_mono) auto
  with insert.hyps show ?case by (simp add: algebra_simps)
qed simp_all

lemma norm_prod_minus1_le_prod_minus1:
  fixes f :: "nat ==> 'a :: {real_normed_div_algebra,comm_ring_1}"  
  shows "norm (prod (λn. 1 + f n) A - 1) prod (λn. 1 + norm (f n)) A - 1"
proof (induction A rule: infinite_finite_induct)
  case (insert x A)
  from insert.hyps have 
    "norm ((ninsert x A. 1 + f n) - 1) =

       norm ((nA. 1 + f n) - 1 + f x * (nA. 1 + f n))"
    by (simp add: algebra_simps)
  also have " norm ((nA. 1 + f n) - 1) + norm (f x * (nA. 1 + f n))"
    by (rule norm_triangle_ineq)
  also have "norm (f x * (nA. 1 + f n)) = norm (f x) * (xA. norm (1 + f x))"
    by (simp add: prod_norm norm_mult)
  also have "(xA. norm (1 + f x)) (xA. norm (1::'a) + norm (f x))"
    by (intro prod_mono norm_triangle_ineq ballI conjI) auto
  also have "norm (1::'a) = 1" by simp
  also note insert.IH
  also have "(nA. 1 + norm (f n)) - 1 + norm (f x) * (xA. 1 + norm (f x)) =

             (ninsert x A. 1 + norm (f n)) - 1"
    using insert.hyps by (simp add: algebra_simps)
  finally show ?case by - (simp_all add: mult_left_mono)
qed simp_all

lemma convergent_prod_imp_ev_nonzero:
  fixes f :: "nat ==> 'a :: {t2_space,comm_semiring_1}"
  assumes "convergent_prod f"
  shows   "eventually (λn. f n 0) sequentially"
  using assms by (auto simp: eventually_at_top_linorder convergent_prod_altdef)

lemma convergent_prod_imp_LIMSEQ:
  fixes f :: "nat ==> 'a :: {real_normed_field}"
  assumes "convergent_prod f"
  shows   "f <---- 1"
proof -
  from assms obtain M L where L: "(λn. in. f (i+M)) <---- L" "n. n M ==> f n 0" "L 0"
    by (auto simp: convergent_prod_altdef)
  hence L': "(λn. iSuc n. f (i+M)) <---- L" by (subst filterlim_sequentially_Suc)
  have "(λn. (iSuc n. f (i+M)) / (in. f (i+M))) <---- L / L"
    using L L' by (intro tendsto_divide) simp_all
  also from L have "L / L = 1" by simp
  also have "(λn. (iSuc n. f (i+M)) / (in. f (i+M))) = (λn. f (n + Suc M))"
    using assms L by (auto simp: fun_eq_iff atMost_Suc)
  finally show ?thesis by (rule LIMSEQ_offset)
qed

lemma abs_convergent_prod_imp_summable:
  fixes f :: "nat ==> 'a :: real_normed_div_algebra"
  assumes "abs_convergent_prod f"
  shows "summable (λi. norm (f i - 1))"
proof -
  from assms have "convergent (λn. in. 1 + norm (f i - 1))" 
    unfolding abs_convergent_prod_def by (rule convergent_prod_imp_convergent)
  then obtain L where L: "(λn. in. 1 + norm (f i - 1)) <---- L"
    unfolding convergent_def by blast
  have "convergent (λn. in. norm (f i - 1))"
  proof (rule Bseq_monoseq_convergent)
    have "eventually (λn. (in. 1 + norm (f i - 1)) < L + 1) sequentially"
      using L(1) by (rule order_tendstoD) simp_all
    hence "🪙F x in sequentially. norm (ix. norm (f i - 1)) L + 1"
    proof eventually_elim
      case (elim n)
      have "norm (in. norm (f i - 1)) = (in. norm (f i - 1))"
        unfolding real_norm_def by (intro abs_of_nonneg sum_nonneg) simp_all
      also have " (in. 1 + norm (f i - 1))" by (rule sum_le_prod) auto
      also have " < L + 1" by (rule elim)
      finally show ?case by simp
    qed
    thus "Bseq (λn. in. norm (f i - 1))" by (rule BfunI)
  next
    show "monoseq (λn. in. norm (f i - 1))"
      by (rule mono_SucI1) auto
  qed
  thus "summable (λi. norm (f i - 1))" by (simp add: summable_iff_convergent')
qed

lemma summable_imp_abs_convergent_prod:
  fixes f :: "nat ==> 'a :: real_normed_div_algebra"
  assumes "summable (λi. norm (f i - 1))"
  shows   "abs_convergent_prod f"
proof (intro abs_convergent_prodI Bseq_monoseq_convergent)
  show "monoseq (λn. in. 1 + norm (f i - 1))"
    by (intro mono_SucI1) 
       (auto simp: atMost_Suc algebra_simps intro!: mult_nonneg_nonneg prod_nonneg)
next
  show "Bseq (λn. in. 1 + norm (f i - 1))"
  proof (rule Bseq_eventually_mono)
    show "eventually (λn. norm (in. 1 + norm (f i - 1))
            norm (exp (in. norm (f i - 1)))) sequentially"
      by (intro always_eventually allI) (auto simp: abs_prod exp_sum intro!: prod_mono)
  next
    from assms have "(λn. in. norm (f i - 1)) <---- (i. norm (f i - 1))"
      using sums_def_le by blast
    hence "(λn. exp (in. norm (f i - 1))) <---- exp (i. norm (f i - 1))"
      by (rule tendsto_exp)
    hence "convergent (λn. exp (in. norm (f i - 1)))"
      by (rule convergentI)
    thus "Bseq (λn. exp (in. norm (f i - 1)))"
      by (rule convergent_imp_Bseq)
  qed
qed

theorem abs_convergent_prod_conv_summable:
  fixes f :: "nat ==> 'a :: real_normed_div_algebra"
  shows "abs_convergent_prod f summable (λi. norm (f i - 1))"
  by (blast intro: abs_convergent_prod_imp_summable summable_imp_abs_convergent_prod)

lemma abs_convergent_prod_imp_LIMSEQ:
  fixes f :: "nat ==> 'a :: {comm_ring_1,real_normed_div_algebra}"
  assumes "abs_convergent_prod f"
  shows   "f <---- 1"
proof -
  from assms have "summable (λn. norm (f n - 1))"
    by (rule abs_convergent_prod_imp_summable)
  from summable_LIMSEQ_zero[OF this] have "(λn. f n - 1) <---- 0"
    by (simp add: tendsto_norm_zero_iff)
  from tendsto_add[OF this tendsto_const[of 1]] show ?thesis by simp
qed

lemma abs_convergent_prod_imp_ev_nonzero:
  fixes f :: "nat ==> 'a :: {comm_ring_1,real_normed_div_algebra}"
  assumes "abs_convergent_prod f"
  shows   "eventually (λn. f n 0) sequentially"
proof -
  from assms have "f <---- 1" 
    by (rule abs_convergent_prod_imp_LIMSEQ)
  hence "eventually (λn. dist (f n) 1 < 1) at_top"
    by (auto simp: tendsto_iff)
  thus ?thesis by eventually_elim auto
qed

subsection🍋tag unimportant Ignoring initial segments

lemma convergent_prod_offset:
  assumes "convergent_prod (λn. f (n + m))"  
  shows   "convergent_prod f"
proof -
  from assms obtain M L where "(λn. kn. f (k + (M + m))) <---- L" "L 0"
    by (auto simp: prod_defs add.assoc)
  thus "convergent_prod f" 
    unfolding prod_defs by blast
qed

lemma abs_convergent_prod_offset:
  assumes "abs_convergent_prod (λn. f (n + m))"  
  shows   "abs_convergent_prod f"
  using assms unfolding abs_convergent_prod_def by (rule convergent_prod_offset)


lemma raw_has_prod_ignore_initial_segment:
  fixes f :: "nat ==> 'a :: real_normed_field"
  assumes "raw_has_prod f M p" "N M"
  obtains q where  "raw_has_prod f N q"
proof -
  have p: "(λn. kn. f (k + M)) <---- p" and "p 0" 
    using assms by (auto simp: raw_has_prod_def)
  then have nz: "n. n M ==> f n 0"
    using assms by (auto simp: raw_has_prod_eq_0)
  define C where "C = (k
  from nz have [simp]: "C 0" 
    by (auto simp: C_def)

  from p have "(λi. ki + (N-M). f (k + M)) <---- p" 
    by (rule LIMSEQ_ignore_initial_segment)
  also have "(λi. ki + (N-M). f (k + M)) = (λn. C * (kn. f (k + N)))"
  proof (rule ext, goal_cases)
    case (1 n)
    have "{..n+(N-M)} = {..<(N-M)} {(N-M)..n+(N-M)}" by auto
    also have "(k. f (k + M)) = C * (k=(N-M)..n+(N-M). f (k + M))"
      unfolding C_def by (rule prod.union_disjoint) auto
    also have "(k=(N-M)..n+(N-M). f (k + M)) = (kn. f (k + (N-M) + M))"
      by (intro ext prod.reindex_bij_witness[of _ "λk. k + (N-M)" "λk. k - (N-M)"]) auto
    finally show ?case
      using N M by (simp add: add_ac)
  qed
  finally have "(λn. C * (kn. f (k + N)) / C) <---- p / C"
    by (intro tendsto_divide tendsto_const) auto
  hence "(λn. kn. f (k + N)) <---- p / C" by simp
  moreover from p 0 have "p / C 0" by simp
  ultimately show ?thesis
    using raw_has_prod_def that by blast 
qed

corollary🍋tag unimportant convergent_prod_ignore_initial_segment:
  fixes f :: "nat ==> 'a :: real_normed_field"
  assumes "convergent_prod f"
  shows   "convergent_prod (λn. f (n + m))"
  using assms
  unfolding convergent_prod_def 
  apply clarify
  apply (erule_tac N="M+m" in raw_has_prod_ignore_initial_segment)
  apply (auto simp add: raw_has_prod_def add_ac)
  done

corollary🍋tag unimportant convergent_prod_ignore_nonzero_segment:
  fixes f :: "nat ==> 'a :: real_normed_field"
  assumes f: "convergent_prod f" and nz: "i. i M ==> f i 0"
  shows "p. raw_has_prod f M p"
  using convergent_prod_ignore_initial_segment [OF f]
  by (metis convergent_LIMSEQ_iff convergent_prod_iff_convergent le_add_same_cancel2 nz prod_defs(1) zero_order(1))

corollary🍋tag unimportant abs_convergent_prod_ignore_initial_segment:
  assumes "abs_convergent_prod f"
  shows   "abs_convergent_prod (λn. f (n + m))"
  using assms unfolding abs_convergent_prod_def 
  by (rule convergent_prod_ignore_initial_segment)

subsectionMore elementary properties

theorem abs_convergent_prod_imp_convergent_prod:
  fixes f :: "nat ==> 'a :: {real_normed_div_algebra,complete_space,comm_ring_1}"
  assumes "abs_convergent_prod f"
  shows   "convergent_prod f"
proof -
  from assms have "eventually (λn. f n 0) sequentially"
    by (rule abs_convergent_prod_imp_ev_nonzero)
  then obtain N where N: "f n 0" if "n N" for n 
    by (auto simp: eventually_at_top_linorder)
  let ?P = "λn. in. f (i + N)" and ?Q = "λn. in. 1 + norm (f (i + N) - 1)"

  have "Cauchy ?P"
  proof (rule CauchyI', goal_cases)
    case (1 ε)
    from assms have "abs_convergent_prod (λn. f (n + N))"
      by (rule abs_convergent_prod_ignore_initial_segment)
    hence "Cauchy ?Q"
      unfolding abs_convergent_prod_def
      by (intro convergent_Cauchy convergent_prod_imp_convergent)
    from CauchyD[OF this 1] obtain M where M: "norm (?Q m - ?Q n) < ε" if "m M" "n M" for m n
      by blast
    show ?case
    proof (rule exI[of _ M], safe, goal_cases)
      case (1 m n)
      have "dist (?P m) (?P n) = norm (?P n - ?P m)"
        by (simp add: dist_norm norm_minus_commute)
      also from 1 have "{..n} = {..m} {m<..n}" by auto
      hence "norm (?P n - ?P m) = norm (?P m * (k{m<..n}. f (k + N)) - ?P m)"
        by (subst prod.union_disjoint [symmetric]) (auto simp: algebra_simps)
      also have " = norm (?P m * ((k{m<..n}. f (k + N)) - 1))"
        by (simp add: algebra_simps)
      also have " = (km. norm (f (k + N))) * norm ((k{m<..n}. f (k + N)) - 1)"
        by (simp add: norm_mult prod_norm)
      also have " ?Q m * ((k{m<..n}. 1 + norm (f (k + N) - 1)) - 1)"
        using norm_prod_minus1_le_prod_minus1[of "λk. f (k + N) - 1" "{m<..n}"]
              norm_triangle_ineq[of 1 "f k - 1" for k]
        by (intro mult_mono prod_mono ballI conjI norm_prod_minus1_le_prod_minus1 prod_nonneg) auto
      also have " = ?Q m * (k{m<..n}. 1 + norm (f (k + N) - 1)) - ?Q m"
        by (simp add: algebra_simps)
      also have "?Q m * (k{m<..n}. 1 + norm (f (k + N) - 1)) =

                   (k{..m}{m<..n}. 1 + norm (f (k + N) - 1))"
        by (rule prod.union_disjoint [symmetric]) auto
      also from 1 have "{..m}{m<..n} = {..n}" by auto
      also have "?Q n - ?Q m norm (?Q n - ?Q m)" by simp
      also from 1 have " < ε" by (intro M) auto
      finally show ?case .
    qed
  qed
  hence conv: "convergent ?P" by (rule Cauchy_convergent)
  then obtain L where L: "?P <---- L"
    by (auto simp: convergent_def)

  have "L 0"
  proof
    assume [simp]: "L = 0"
    from tendsto_norm[OF L] have limit: "(λn. kn. norm (f (k + N))) <---- 0" 
      by (simp add: prod_norm)

    from assms have "(λn. f (n + N)) <---- 1"
      by (intro abs_convergent_prod_imp_LIMSEQ abs_convergent_prod_ignore_initial_segment)
    hence "eventually (λn. norm (f (n + N) - 1) < 1) sequentially"
      by (auto simp: tendsto_iff dist_norm)
    then obtain M0 where M0: "norm (f (n + N) - 1) < 1" if "n M0" for n
      by (auto simp: eventually_at_top_linorder)

    {
      fix M assume M: "M M0"
      with M0 have M: "norm (f (n + N) - 1) < 1" if "n M" for n using that by simp

      have "(λn. kn. 1 - norm (f (k+M+N) - 1)) <---- 0"
      proof (rule tendsto_sandwich)
        show "eventually (λn. (kn. 1 - norm (f (k+M+N) - 1)) 0) sequentially"
          using M by (intro always_eventually prod_nonneg allI ballI) (auto intro: less_imp_le)
        have "norm (1::'a) - norm (f (i + M + N) - 1) norm (f (i + M + N))" for i
          using norm_triangle_ineq3[of "f (i + M + N)" 1] by simp
        thus "eventually (λn. (kn. 1 - norm (f (k+M+N) - 1)) (kn. norm (f (k+M+N)))) at_top"
          using M by (intro always_eventually allI prod_mono ballI conjI) (auto intro: less_imp_le)
        
        define C where "C = (k
        from N have [simp]: "C 0" by (auto simp: C_def)
        from L have "(λn. norm (kn+M. f (k + N))) <---- 0"
          by (intro LIMSEQ_ignore_initial_segment) (simp add: tendsto_norm_zero_iff)
        also have "(λn. norm (kn+M. f (k + N))) = (λn. C * (kn. norm (f (k + M + N))))"
        proof (rule ext, goal_cases)
          case (1 n)
          have "{..n+M} = {.. {M..n+M}"
 by auto
          also have "norm (k. f (k + N)) = C * norm (k=M..n+M. f (k + N))"
            unfolding C_def by (subst prod.union_disjoint) (auto simp: norm_mult prod_norm)
          also have "(k=M..n+M. f (k + N)) = (kn. f (k + N + M))"
            by (intro prod.reindex_bij_witness[of _ "λi. i + M" "λi. i - M"]) auto
          finally show ?case by (simp add: add_ac prod_norm)
        qed
        finally have "(λn. C * (kn. norm (f (k + M + N))) / C) <---- 0 / C"
          by (intro tendsto_divide tendsto_const) auto
        thus "(λn. kn. norm (f (k + M + N))) <---- 0" by simp
      qed simp_all

      have "1 - (i. norm (f (i + M + N) - 1)) 0"
      proof (rule tendsto_le)
        show "eventually (λn. 1 - (kn. norm (f (k+M+N) - 1))
                                (kn. 1 - norm (f (k+M+N) - 1))) at_top"
          using M by (intro always_eventually allI Weierstrass_prod_ineq) (auto intro: less_imp_le)
        show "(λn. kn. 1 - norm (f (k+M+N) - 1)) <---- 0" by fact
        show "(λn. 1 - (kn. norm (f (k + M + N) - 1)))
                  <---- 1 - (i. norm (f (i + M + N) - 1))"
          by (intro tendsto_intros summable_LIMSEQ' summable_ignore_initial_segment 
                abs_convergent_prod_imp_summable assms)
      qed simp_all
      hence "(i. norm (f (i + M + N) - 1)) 1" by simp
      also have " + (ii. norm (f (i + N) - 1))"
        by (intro suminf_split_initial_segment [symmetric] summable_ignore_initial_segment
              abs_convergent_prod_imp_summable assms)
      finally have "1 + (i (i. norm (f (i + N) - 1))" by simp
    } note * = this

    have "1 + (i. norm (f (i + N) - 1)) (i. norm (f (i + N) - 1))"
    proof (rule tendsto_le)
      show "(λM. 1 + (i<---- 1 + (i. norm (f (i + N) - 1))"
        by (intro tendsto_intros summable_LIMSEQ summable_ignore_initial_segment 
                abs_convergent_prod_imp_summable assms)
      show "eventually (λM. 1 + (i (i. norm (f (i + N) - 1))) at_top"
        using eventually_ge_at_top[of M0] by eventually_elim (use * in auto)
    qed simp_all
    thus False by simp
  qed
  with L show ?thesis by (auto simp: prod_defs)
qed

lemma raw_has_prod_cases:
  fixes f :: "nat ==> 'a :: {idom,topological_semigroup_mult,t2_space}"
  assumes "raw_has_prod f M p"
  obtains i where "i "f i = 0" | p where "raw_has_prod f 0 p"
proof -
  have "(λn. in. f (i + M)) <---- p" "p 0"
    using assms unfolding raw_has_prod_def by blast+
  then have "(λn. prod f {..in. f (i + M))) <---- prod f {..
    by (metis tendsto_mult_left)
  moreover have "prod f {..in. f (i + M)) = prod f {..n+M}"
 for n
  proof -
    have "{..n+M} = {.. {M..n+M}"
      by auto
    then have "prod f {..n+M} = prod f {..
      by simp (subst prod.union_disjoint; force)
    also have " = prod f {..in. f (i + M))"

      by (metis (mono_tags, lifting) add.left_neutral atMost_atLeast0 prod.shift_bounds_cl_nat_ivl)
    finally show ?thesis by metis
  qed
  ultimately have "(λn. prod f {..n}) <---- prod f {..
    by (auto intro: LIMSEQ_offset [where k=M])
  then have "raw_has_prod f 0 (prod f {.. if "i 0"
    using p 0 assms that by (auto simp: raw_has_prod_def)
  then show thesis
    using that by blast
qed

corollary convergent_prod_offset_0:
  fixes f :: "nat ==> 'a :: {idom,topological_semigroup_mult,t2_space}"
  assumes "convergent_prod f" "i. f i 0"
  shows "p. raw_has_prod f 0 p"
  using assms convergent_prod_def raw_has_prod_cases by blast

lemma prodinf_eq_lim:
  fixes f :: "nat ==> 'a :: {idom,topological_semigroup_mult,t2_space}"
  assumes "convergent_prod f" "i. f i 0"
  shows "prodinf f = lim (λn. in. f i)"
  using assms convergent_prod_offset_0 [OF assms]
  by (simp add: prod_defs lim_def) (metis (no_types) assms(1) convergent_prod_to_zero_iff)

lemma prodinf_eq_lim':
  fixes f :: "nat ==> 'a :: {idom,topological_semigroup_mult,t2_space}"
  assumes "convergent_prod f" "i. f i 0"
  shows "prodinf f = lim (λn. i
  by (metis assms prodinf_eq_lim LIMSEQ_lessThan_iff_atMost convergent_prod_iff_nz_lim limI)

lemma prodinf_eq_prod_lim:
  fixes a:: "'a :: {topological_semigroup_mult,t2_space,idom}"
  assumes "(λn. kn. f k) <---- a" "a 0"
  shows"(k. f k) = a"
  by (metis LIMSEQ_prod_0 LIMSEQ_unique assms convergent_prod_iff_nz_lim limI prodinf_eq_lim)

lemma prodinf_eq_prod_lim':
  fixes a:: "'a :: {topological_semigroup_mult,t2_space,idom}"
  assumes "(λn. k<---- a"
 "a 0"
  shows"(k. f k) = a"
  using LIMSEQ_lessThan_iff_atMost assms prodinf_eq_prod_lim by blast

lemma has_prod_one[simp, intro]: "(λn. 1) has_prod 1"
  unfolding prod_defs by auto

lemma convergent_prod_one[simp, intro]: "convergent_prod (λn. 1)"
  unfolding prod_defs by auto

lemma prodinf_cong: "(n. f n = g n) ==> prodinf f = prodinf g"
  by presburger

lemma convergent_prod_cong:
  fixes f g :: "nat ==> 'a::{field,topological_semigroup_mult,t2_space}"
  assumes ev: "eventually (λx. f x = g x) sequentially" and f: "i. f i 0" and g: "i. g i 0"
  shows "convergent_prod f = convergent_prod g"
proof -
  from assms obtain N where N: "nN. f n = g n"
    by (auto simp: eventually_at_top_linorder)
  define C where "C = (k
  with g have "C 0"
    by (simp add: f)
  have *: "eventually (λn. prod f {..n} = C * prod g {..n}) sequentially"
    using eventually_ge_at_top[of N]
  proof eventually_elim
    case (elim n)
    then have "{..n} = {.. {N..n}"

      by auto
    also have "prod f = prod f {..
      by (intro prod.union_disjoint) auto
    also from N have "prod f {N..n} = prod g {N..n}"
      by (intro prod.cong) simp_all
    also have "prod f {..
      unfolding C_def by (simp add: g prod_dividef)
    also have "prod g {.. {N..n})"

      by (intro prod.union_disjoint [symmetric]) auto
    also from elim have "{.. {N..n} = {..n}"

      by auto                                                                    
    finally show "prod f {..n} = C * prod g {..n}" .
  qed
  then have cong: "convergent (λn. prod f {..n}) = convergent (λn. C * prod g {..n})"
    by (rule convergent_cong)
  show ?thesis
  proof
    assume cf: "convergent_prod f"
    with f have "¬ (λn. prod f {..n}) <---- 0"
      by simp
    then have "¬ (λn. prod g {..n}) <---- 0"
      using * C 0 filterlim_cong by fastforce
    then show "convergent_prod g"
      by (metis convergent_mult_const_iff C 0 cong cf convergent_LIMSEQ_iff convergent_prod_iff_convergent convergent_prod_imp_convergent g)
  next
    assume cg: "convergent_prod g"
    have **: "eventually (λn. prod g {..n} = prod f {..n} / C) sequentially"
      using * by eventually_elim (use C 0 in auto)
    from cg and g have "¬ (λn. prod g {..n}) <---- 0"
      by simp
    then have "¬ (λn. prod f {..n}) <---- 0"
      using ** C 0 filterlim_cong by fastforce
    then show "convergent_prod f"
      by (metis C 0 cg convergent_LIMSEQ_iff
          convergent_mult_const_iff convergent_prod_iff_convergent
          convergent_prod_imp_convergent f local.cong)
  qed
qed

lemma has_prod_finite:
  fixes f :: "nat ==> 'a::{semidom,t2_space}"
  assumes [simp]: "finite N"
    and f: "n. n N ==> f n = 1"
  shows "f has_prod (nN. f n)"
proof -
  have eq: "prod f {..n + Suc (Max N)} = prod f N" for n
  proof (rule prod.mono_neutral_right)
    show "N {..n + Suc (Max N)}"
      by (auto simp: le_Suc_eq trans_le_add2)
    show "i{..n + Suc (Max N)} - N. f i = 1"
      using f by blast
  qed auto
  show ?thesis
  proof (cases "nN. f n 0")
    case True
    then have "prod f N 0"
      by simp
    moreover have "(λn. prod f {..n}) <---- prod f N"
      by (rule LIMSEQ_offset[of _ "Suc (Max N)"]) (simp add: eq atLeast0LessThan del: add_Suc_right)
    ultimately show ?thesis
      by (simp add: raw_has_prod_def has_prod_def)
  next
    case False
    then obtain k where "k N" "f k = 0"
      by auto
    let ?Z = "{n N. f n = 0}"
    have maxge: "Max ?Z n" if "f n = 0" for n
      using Max_ge [of ?Z] finite N f n = 0
      by (metis (mono_tags) Collect_mem_eq f finite_Collect_conjI mem_Collect_eq zero_neq_one)
    let ?q = "prod f {Suc (Max ?Z)..Max N}"
    have [simp]: "?q 0"
      using maxge Suc_n_not_le_n le_trans by force
    have eq: "(in + Max N. f (Suc (i + Max ?Z))) = ?q" for n
    proof -
      have "(in + Max N. f (Suc (i + Max ?Z))) = prod f {Suc (Max ?Z)..n + Max N + Suc (Max ?Z)}" 
      proof (rule prod.reindex_cong [where l = "λi. i + Suc (Max ?Z)"THEN sym])
        show "{Suc (Max ?Z)..n + Max N + Suc (Max ?Z)} = (λi. i + Suc (Max ?Z)) ` {..n + Max N}"
          using le_Suc_ex by fastforce
      qed (auto simp: inj_on_def)
      also have " = ?q"
        by (rule prod.mono_neutral_right)
           (use Max.coboundedI [OF finite N] f in force+)
      finally show ?thesis .
    qed
    have q: "raw_has_prod f (Suc (Max ?Z)) ?q"
    proof (simp add: raw_has_prod_def)
      show "(λn. in. f (Suc (i + Max ?Z))) <---- ?q"
        by (rule LIMSEQ_offset[of _ "(Max N)"]) (simp add: eq)
    qed
    show ?thesis
      unfolding has_prod_def
    proof (intro disjI2 exI conjI)      
      show "prod f N = 0"
        using f k = 0 k N finite N prod_zero by blast
      show "f (Max ?Z) = 0"
        using Max_in [of ?Z] finite N f k = 0 k N by auto
    qed (use q in auto)
  qed
qed

corollary🍋tag unimportant has_prod_0:
  fixes f :: "nat ==> 'a::{semidom,t2_space}"
  assumes "n. f n = 1"
  shows "f has_prod 1"
  by (simp add: assms has_prod_cong)

lemma prodinf_zero[simp]: "prodinf (λn. 1::'a::real_normed_field) = 1"
  using has_prod_unique by force

lemma convergent_prod_finite:
  fixes f :: "nat ==> 'a::{idom,t2_space}"
  assumes "finite N" "n. n N ==> f n = 1"
  shows "convergent_prod f"
proof -
  have "n p. raw_has_prod f n p"
    using assms has_prod_def has_prod_finite by blast
  then show ?thesis
    by (simp add: convergent_prod_def)
qed

lemma has_prod_If_finite_set:
  fixes f :: "nat ==> 'a::{idom,t2_space}"
  shows "finite A ==> (λr. if r A then f r else 1) has_prod (rA. f r)"
  using has_prod_finite[of A "(λr. if r A then f r else 1)"]
  by simp

lemma has_prod_If_finite:
  fixes f :: "nat ==> 'a::{idom,t2_space}"
  shows "finite {r. P r} ==> (λr. if P r then f r else 1) has_prod (r | P r. f r)"
  using has_prod_If_finite_set[of "{r. P r}"by simp

lemma convergent_prod_If_finite_set[simp, intro]:
  fixes f :: "nat ==> 'a::{idom,t2_space}"
  shows "finite A ==> convergent_prod (λr. if r A then f r else 1)"
  by (simp add: convergent_prod_finite)

lemma convergent_prod_If_finite[simp, intro]:
  fixes f :: "nat ==> 'a::{idom,t2_space}"
  assumes "finite {r. P r}"
  shows   "convergent_prod (λr. if P r then f r else 1)"
proof -
  have "(λr. if P r then f r else 1) has_prod (r | P r. f r)"
    by (rule has_prod_If_finite) fact
  thus ?thesis
    by (meson convergent_prod_def has_prod_def)
qed

lemma has_prod_single:
  fixes f :: "nat ==> 'a::{idom,t2_space}"
  shows "(λr. if r = i then f r else 1) has_prod f i"
  using has_prod_If_finite[of "λr. r = i"by simp

text The ge1 assumption can probably be weakened, at the expense of extra work
lemma uniform_limit_prodinf:
  fixes f:: "nat ==> real ==> real"
  assumes "uniformly_convergent_on X (λn x. k 
    and ge1: "x k . x X ==> f k x 1"
  shows "uniform_limit X (λn x. kk. f k x) sequentially"

proof -
  have ul: "uniform_limit X (λn x. kk
    using assms uniformly_convergent_uniform_limit_iff by blast
  moreover have "(k. f k x) = lim (λn. k if "x X" for x
  proof (intro prodinf_eq_lim')
    have tends: "(λn. k<---- lim (λn. k
      using tendsto_uniform_limitI [OF ul] that by metis
    moreover have "(k 1"
 for n
      using ge1 by (simp add: prod_ge_1 that)
    ultimately have "lim (λn. k 1"

      by (meson LIMSEQ_le_const)
    then have "raw_has_prod (λk. f k x) 0 (lim (λn. k
      using LIMSEQ_lessThan_iff_atMost tends by (auto simp: raw_has_prod_def)
    then show "convergent_prod (λk. f k x)"
      unfolding convergent_prod_def by blast
    show "k. f k x 0"
      by (smt (verit) ge1 that)
  qed
  ultimately show ?thesis
    by (metis (mono_tags, lifting) uniform_limit_cong')
qed

context
  fixes f :: "nat ==> 'a :: real_normed_field"
begin

lemma convergent_prod_imp_has_prod: 
  assumes "convergent_prod f"
  shows "p. f has_prod p"
proof -
  obtain M p where p: "raw_has_prod f M p"
    using assms convergent_prod_def by blast
  then have "p 0"
    using raw_has_prod_nonzero by blast
  with p have fnz: "f i 0" if "i M" for i
    using raw_has_prod_eq_0 that by blast
  define C where "C = (n
  show ?thesis
  proof (cases "nM. f n 0")
    case True
    then have "C 0"
      by (simp add: C_def)
    then show ?thesis
      by (meson True assms convergent_prod_offset_0 fnz has_prod_def nat_le_linear)
  next
    case False
    let ?N = "GREATEST n. f n = 0"
    have 0: "f ?N = 0"
      using fnz False
      by (metis (mono_tags, lifting) GreatestI_ex_nat nat_le_linear)
    have "f i 0" if "i > ?N" for i
      by (metis (mono_tags, lifting) Greatest_le_nat fnz leD linear that)
    then have "p. raw_has_prod f (Suc ?N) p"
      using assms by (auto simp: intro!: convergent_prod_ignore_nonzero_segment)
    then show ?thesis
      unfolding has_prod_def using 0 by blast
  qed
qed

lemma convergent_prod_has_prod [intro]:
  shows "convergent_prod f ==> f has_prod (prodinf f)"
  unfolding prodinf_def
  by (metis convergent_prod_imp_has_prod has_prod_unique theI')

lemma convergent_prod_LIMSEQ:
  shows "convergent_prod f ==> (λn. in. f i) <---- prodinf f"
  by (metis convergent_LIMSEQ_iff convergent_prod_has_prod convergent_prod_imp_convergent 
      convergent_prod_to_zero_iff raw_has_prod_eq_0 has_prod_def prodinf_eq_lim zero_le)

theorem has_prod_iff: "f has_prod x convergent_prod f prodinf f = x"
proof
  assume "f has_prod x"
  then show "convergent_prod f prodinf f = x"
    apply safe
    using convergent_prod_def has_prod_def apply blast
    using has_prod_unique by blast
qed auto

lemma convergent_prod_has_prod_iff: "convergent_prod f f has_prod prodinf f"
  by (auto simp: has_prod_iff convergent_prod_has_prod)

lemma prodinf_finite:
  assumes N: "finite N"
    and f: "n. n N ==> f n = 1"
  shows "prodinf f = (nN. f n)"
  using has_prod_finite[OF assms, THEN has_prod_unique] by simp

lemma convergent_prod_tendsto_imp_has_prod:
  assumes "convergent_prod f" "(λn. (in. f i)) <---- P"
  shows   "f has_prod P"
  using assms by (metis convergent_prod_imp_has_prod has_prod_imp_tendsto limI)
    
end

subsection🍋tag unimportant Infinite products on ordered topological monoids

context
  fixes f :: "nat ==> 'a::{linordered_semidom,linorder_topology}"
begin

lemma has_prod_nonzero:
  assumes "f has_prod a" "a 0"
  shows "f k 0"
  using assms by (auto simp: has_prod_def raw_has_prod_def LIMSEQ_prod_0 LIMSEQ_unique)

lemma has_prod_le:
  assumes f: "f has_prod a" and g: "g has_prod b" and le: "n. 0 f n f n g n"
  shows "a b"
proof (cases "a=0 b=0")
  case True
  then show ?thesis
  proof
    assume [simp]: "a=0"
    have "b 0"
    proof (rule LIMSEQ_prod_nonneg)
      show "(λn. prod g {..n}) <---- b"
        using g by (auto simp: has_prod_def raw_has_prod_def LIMSEQ_prod_0)
    qed (use le order_trans in auto)
    then show ?thesis
      by auto
  next
    assume [simp]: "b=0"
    then obtain i where "g i = 0"    
      using g by (auto simp: prod_defs)
    then have "f i = 0"
      using antisym le by force
    then have "a=0"
      using f by (auto simp: prod_defs LIMSEQ_prod_0 LIMSEQ_unique)
    then show ?thesis
      by auto
  qed
next
  case False
  then show ?thesis
    using assms
    unfolding has_prod_def raw_has_prod_def
    by (force simp: LIMSEQ_prod_0 intro!: LIMSEQ_le prod_mono)
qed

lemma prodinf_le: 
  assumes f: "f has_prod a" and g: "g has_prod b" and le: "n. 0 f n f n g n"
  shows "prodinf f prodinf g"
  using has_prod_le [OF assms] has_prod_unique f g  by blast

end


lemma prod_le_prodinf: 
  fixes f :: "nat ==> 'a::{linordered_idom,linorder_topology}"
  assumes "f has_prod a" "i. 0 f i" "i. in ==> 1 f i"
  shows "prod f {.. prodinf f"

  by(rule has_prod_le[OF has_prod_If_finite_set]) (use assms has_prod_unique in auto)

lemma prodinf_nonneg:
  fixes f :: "nat ==> 'a::{linordered_idom,linorder_topology}"
  assumes "f has_prod a" "i. 1 f i" 
  shows "1 prodinf f"
  using prod_le_prodinf[of f a 0] assms
  by (metis order_trans prod_ge_1 zero_le_one)

lemma prodinf_le_const:
  fixes f :: "nat ==> real"
  assumes "convergent_prod f" "n. n N ==> prod f {.. x"
 
  shows "prodinf f x"
  by (metis lessThan_Suc_atMost assms convergent_prod_LIMSEQ LIMSEQ_le_const2 atMost_iff lessThan_iff less_le)

lemma prodinf_eq_one_iff [simp]: 
  fixes f :: "nat ==> real"
  assumes f: "convergent_prod f" and ge1: "n. 1 f n"
  shows "prodinf f = 1 (n. f n = 1)"
proof
  assume "prodinf f = 1" 
  then have "(λn. i<---- 1"
    using convergent_prod_LIMSEQ[of f] assms by (simp add: LIMSEQ_lessThan_iff_atMost)
  then have "i. (n{i}. f n) 1"
  proof (rule LIMSEQ_le_const)
    have "1 prod f n" for n
      by (simp add: ge1 prod_ge_1)
    have "prod f {.. for n
      by (metis n. 1 prod f n prodinf f = 1 antisym f convergent_prod_has_prod ge1 order_trans prod_le_prodinf zero_le_one)
    then have "(n{i}. f n) prod f {.. if "n Suc i" for i n
      by (metis mult.left_neutral order_refl prod.cong prod.neutral_const prod.lessThan_Suc)
    then show "N. nN. (n{i}. f n) prod f {.. for i
      by blast      
  qed
  with ge1 show "n. f n = 1"
    by (auto intro!: antisym)
qed (metis prodinf_zero fun_eq_iff)

lemma prodinf_pos_iff:
  fixes f :: "nat ==> real"
  assumes "convergent_prod f" "n. 1 f n"
  shows "1 < prodinf f (i. 1 < f i)"
  using prod_le_prodinf[of f 1] prodinf_eq_one_iff
  by (metis convergent_prod_has_prod assms less_le prodinf_nonneg)

lemma less_1_prodinf2:
  fixes f :: "nat ==> real"
  assumes "convergent_prod f" "n. 1 f n" "1 < f i"
  shows "1 < prodinf f"
proof -
  have "1 < (n
    using assms  by (intro less_1_prod2[where i=i]) auto
  also have " prodinf f"
    by (intro prod_le_prodinf) (use assms order_trans zero_le_one in blast+)
  finally show ?thesis .
qed

lemma less_1_prodinf:
  fixes f :: "nat ==> real"
  shows "[convergent_prod f; n. 1 < f n] ==> 1 < prodinf f"
  by (intro less_1_prodinf2[where i=1]) (auto intro: less_imp_le)

lemma prodinf_nonzero:
  fixes f :: "nat ==> 'a :: {idom,topological_semigroup_mult,t2_space}"
  assumes "convergent_prod f" "i. f i 0"
  shows "prodinf f 0"
  by (metis assms convergent_prod_offset_0 has_prod_unique raw_has_prod_def has_prod_def)

lemma less_0_prodinf:
  fixes f :: "nat ==> real"
  assumes f: "convergent_prod f" and 0: "i. f i > 0"
  shows "0 < prodinf f"
proof -
  have "prodinf f 0"
    by (metis assms less_irrefl prodinf_nonzero)
  moreover have "0 < (n for i
    by (simp add: 0 prod_pos)
  then have "prodinf f 0"
    using convergent_prod_LIMSEQ [OF f] LIMSEQ_prod_nonneg 0 less_le by blast
  ultimately show ?thesis
    by auto
qed

lemma prod_less_prodinf2:
  fixes f :: "nat ==> real"
  assumes f: "convergent_prod f" and 1: "m. mn ==> 1 f m" and 0: "m. 0 < f m" and i: "n i" "1 < f i"
  shows "prod f {..
proof -
  have "prod f {.. prod f {..
    by (rule prod_mono2) (use assms less_le in auto)
  then have "prod f {..
    using mult_less_le_imp_less[of 1 "f i" "prod f {.. "prod f {..] assms
    by (simp add: prod_pos)
  moreover have "prod f {.. prodinf f"

    using prod_le_prodinf[of f _ "Suc i"]
    by (meson "0" "1" Suc_leD convergent_prod_has_prod f n i le_trans less_eq_real_def)
  ultimately show ?thesis
    by (metis le_less_trans mult.commute not_le prod.lessThan_Suc)
qed

lemma prod_less_prodinf:
  fixes f :: "nat ==> real"
  assumes f: "convergent_prod f" and 1: "m. mn ==> 1 < f m" and 0: "m. 0 < f m" 
  shows "prod f {..
  by (meson "0" "1" f le_less prod_less_prodinf2)

lemma raw_has_prodI_bounded:
  fixes f :: "nat ==> real"
  assumes pos: "n. 1 f n"
    and le: "n. (i x"

  shows "p. raw_has_prod f 0 p"
  unfolding raw_has_prod_def add_0_right
proof (rule exI LIMSEQ_incseq_SUP conjI)+
  show "bdd_above (range (λn. prod f {..n}))"
    by (metis bdd_aboveI2 le lessThan_Suc_atMost)
  then have "(SUP i. prod f {..i}) > 0"
    by (metis UNIV_I cSUP_upper less_le_trans pos prod_pos zero_less_one)
  then show "(SUP i. prod f {..i}) 0"
    by auto
  show "incseq (λn. prod f {..n})"
    using pos order_trans [OF zero_le_one] by (auto simp: mono_def intro!: prod_mono2)
qed

lemma convergent_prodI_nonneg_bounded:
  fixes f :: "nat ==> real"
  assumes "n. 1 f n" "n. (i x"

  shows "convergent_prod f"
  using convergent_prod_def raw_has_prodI_bounded [OF assms] by blast


subsection🍋tag unimportant Infinite products on topological spaces

context
  fixes f g :: "nat ==> 'a::{t2_space,topological_semigroup_mult,idom}"
begin

lemma raw_has_prod_mult: "[raw_has_prod f M a; raw_has_prod g M b] ==> raw_has_prod (λn. f n * g n) M (a * b)"
  by (force simp add: prod.distrib tendsto_mult raw_has_prod_def)

lemma has_prod_mult_nz: "[f has_prod a; g has_prod b; a 0; b 0] ==> (λn. f n * g n) has_prod (a * b)"
  by (simp add: raw_has_prod_mult has_prod_def)

end


context
  fixes f g :: "nat ==> 'a::real_normed_field"
begin

lemma has_prod_mult:
  assumes f: "f has_prod a" and g: "g has_prod b"
  shows "(λn. f n * g n) has_prod (a * b)"
  using f [unfolded has_prod_def]
proof (elim disjE exE conjE)
  assume f0: "raw_has_prod f 0 a"
  show ?thesis
    using g [unfolded has_prod_def]
  proof (elim disjE exE conjE)
    assume g0: "raw_has_prod g 0 b"
    with f0 show ?thesis
      by (force simp add: has_prod_def prod.distrib tendsto_mult raw_has_prod_def)
  next
    fix j q
    assume "b = 0" and "g j = 0" and q: "raw_has_prod g (Suc j) q"
    obtain p where p: "raw_has_prod f (Suc j) p"
      using f0 raw_has_prod_ignore_initial_segment by blast
    then have "Ex (raw_has_prod (λn. f n * g n) (Suc j))"
      using q raw_has_prod_mult by blast
    then show ?thesis
      using b = 0 g j = 0 has_prod_0_iff by fastforce
  qed
next
  fix i p
  assume "a = 0" and "f i = 0" and p: "raw_has_prod f (Suc i) p"
  show ?thesis
    using g [unfolded has_prod_def]
  proof (elim disjE exE conjE)
    assume g0: "raw_has_prod g 0 b"
    obtain q where q: "raw_has_prod g (Suc i) q"
      using g0 raw_has_prod_ignore_initial_segment by blast
    then have "Ex (raw_has_prod (λn. f n * g n) (Suc i))"
      using raw_has_prod_mult p by blast
    then show ?thesis
      using a = 0 f i = 0 has_prod_0_iff by fastforce
  next
    fix j q
    assume "b = 0" and "g j = 0" and q: "raw_has_prod g (Suc j) q"
    obtain p' where p': "raw_has_prod f (Suc (max i j)) p'"
      by (metis raw_has_prod_ignore_initial_segment max_Suc_Suc max_def p)
    moreover
    obtain q' where q': "raw_has_prod g (Suc (max i j)) q'"
      by (metis raw_has_prod_ignore_initial_segment max.cobounded2 max_Suc_Suc q)
    ultimately show ?thesis
      using b = 0 by (simp add: has_prod_def) (metis f i = 0 g j = 0 raw_has_prod_mult max_def)
  qed
qed

lemma convergent_prod_mult:
  assumes f: "convergent_prod f" and g: "convergent_prod g"
  shows "convergent_prod (λn. f n * g n)"
  unfolding convergent_prod_def
proof -
  obtain M p N q where p: "raw_has_prod f M p" and q: "raw_has_prod g N q"
    using convergent_prod_def f g by blast+
  then obtain p' q' where p': "raw_has_prod f (max M N) p'" and q': "raw_has_prod g (max M N) q'"
    by (meson raw_has_prod_ignore_initial_segment max.cobounded1 max.cobounded2)
  then show "M p. raw_has_prod (λn. f n * g n) M p"
    using raw_has_prod_mult by blast
qed

lemma prodinf_mult: "convergent_prod f ==> convergent_prod g ==> prodinf f * prodinf g = (n. f n * g n)"
  by (intro has_prod_unique has_prod_mult convergent_prod_has_prod)

end

context
  fixes f :: "'i ==> nat ==> 'a::real_normed_field"
    and I :: "'i set"
begin

lemma has_prod_prod: "(i. i I ==> (f i) has_prod (x i)) ==> (λn. iI. f i n) has_prod (iI. x i)"
  by (induct I rule: infinite_finite_induct) (auto intro!: has_prod_mult)

lemma prodinf_prod: "(i. i I ==> convergent_prod (f i)) ==> (n. iI. f i n) = (iI. n. f i n)"
  using has_prod_unique[OF has_prod_prod, OF convergent_prod_has_prod] by simp

lemma convergent_prod_prod: "(i. i I ==> convergent_prod (f i)) ==> convergent_prod (λn. iI. f i n)"
  using convergent_prod_has_prod_iff has_prod_prod prodinf_prod by force

end

subsection🍋tag unimportant Infinite summability on real normed fields

context
  fixes f :: "nat ==> 'a::real_normed_field"
begin

lemma raw_has_prod_Suc_iff: "raw_has_prod f M (a * f M) raw_has_prod (λn. f (Suc n)) M a f M 0"
proof -
  have "raw_has_prod f M (a * f M) (λi. jSuc i. f (j+M)) <---- a * f M a * f M 0"
    by (subst filterlim_sequentially_Suc) (simp add: raw_has_prod_def)
  also have " (λi. (ji. f (Suc j + M)) * f M) <---- a * f M a * f M 0"
    by (simp add: ac_simps atMost_Suc_eq_insert_0 image_Suc_atMost prod.atLeast1_atMost_eq lessThan_Suc_atMost
                  del: prod.cl_ivl_Suc)
  also have " raw_has_prod (λn. f (Suc n)) M a f M 0"
  proof safe
    assume tends: "(λi. (ji. f (Suc j + M)) * f M) <---- a * f M" and 0: "a * f M 0"
    with tendsto_divide[OF tends tendsto_const, of "f M"]    
    show "raw_has_prod (λn. f (Suc n)) M a"
      by (simp add: raw_has_prod_def)
  qed (auto intro: tendsto_mult_right simp:  raw_has_prod_def)
  finally show ?thesis .
qed

lemma has_prod_Suc_iff:
  assumes "f 0 0" shows "(λn. f (Suc n)) has_prod a f has_prod (a * f 0)"
proof (cases "a = 0")
  case True
  then show ?thesis
  proof (simp add: has_prod_def, safe)
    fix i x
    assume "f (Suc i) = 0" and "raw_has_prod (λn. f (Suc n)) (Suc i) x"
    then obtain y where "raw_has_prod f (Suc (Suc i)) y"
      by (metis (no_types) raw_has_prod_eq_0 Suc_n_not_le_n raw_has_prod_Suc_iff raw_has_prod_ignore_initial_segment raw_has_prod_nonzero linear)
    then show "i. f i = 0 Ex (raw_has_prod f (Suc i))"
      using f (Suc i) = 0 by blast
  next
    fix i x
    assume "f i = 0" and x: "raw_has_prod f (Suc i) x"
    then obtain j where j: "i = Suc j"
      by (metis assms not0_implies_Suc)
    moreover have " y. raw_has_prod (λn. f (Suc n)) i y"
      using x by (auto simp: raw_has_prod_def)
    then show "i. f (Suc i) = 0 Ex (raw_has_prod (λn. f (Suc n)) (Suc i))"
      using f i = 0by blast
  qed
next
  case False
  then show ?thesis
    by (auto simp: has_prod_def raw_has_prod_Suc_iff assms)
qed

lemma convergent_prod_Suc_iff [simp]:
  shows "convergent_prod (λn. f (Suc n)) = convergent_prod f"
proof
  assume "convergent_prod f"
  then obtain M L where M_nz:"nM. f n 0" and 
        M_L:"(λn. in. f (i + M)) <---- L" and "L 0" 
    unfolding convergent_prod_altdef by auto
  have "(λn. in. f (Suc (i + M))) <---- L / f M"
  proof -
    have "(λn. i{0..Suc n}. f (i + M)) <---- L"
      using M_L 
      apply (subst (asm) filterlim_sequentially_Suc[symmetric]) 
      using atLeast0AtMost by auto
    then have "(λn. f M * (i{0..n}. f (Suc (i + M)))) <---- L"
      apply (subst (asm) prod.atLeast0_atMost_Suc_shift)
      by simp
    then have "(λn. (i{0..n}. f (Suc (i + M)))) <---- L/f M"
      apply (drule_tac tendsto_divide)
      using M_nz[rule_format,of M,simplified] by auto
    then show ?thesis unfolding atLeast0AtMost .
  qed
  then show "convergent_prod (λn. f (Suc n))" unfolding convergent_prod_altdef
    apply (rule_tac exI[where x=M])
    apply (rule_tac exI[where x="L/f M"])
    using M_nz L0 by auto
next
  assume "convergent_prod (λn. f (Suc n))"
  then obtain M where "L. (nM. f (Suc n) 0) (λn. in. f (Suc (i + M))) <---- L L 0"
    unfolding convergent_prod_altdef by auto
  then show "convergent_prod f" unfolding convergent_prod_altdef
    apply (rule_tac exI[where x="Suc M"])
    using Suc_le_D by auto
qed

lemma raw_has_prod_inverse: 
  assumes "raw_has_prod f M a" shows "raw_has_prod (λn. inverse (f n)) M (inverse a)"
  using assms unfolding raw_has_prod_def by (auto dest: tendsto_inverse simp: prod_inversef [symmetric])

lemma has_prod_inverse: 
  assumes "f has_prod a" shows "(λn. inverse (f n)) has_prod (inverse a)"
using assms raw_has_prod_inverse unfolding has_prod_def by auto 

lemma convergent_prod_inverse:
  assumes "convergent_prod f" 
  shows "convergent_prod (λn. inverse (f n))"
  using assms unfolding convergent_prod_def  by (blast intro: raw_has_prod_inverse elim: )

end

context 
  fixes f :: "nat ==> 'a::real_normed_field"
begin

lemma raw_has_prod_Suc_iff': "raw_has_prod f M a raw_has_prod (λn. f (Suc n)) M (a / f M) f M 0"
  by (metis raw_has_prod_eq_0 add.commute add.left_neutral raw_has_prod_Suc_iff raw_has_prod_nonzero le_add1 nonzero_mult_div_cancel_right times_divide_eq_left)

lemma has_prod_divide: "f has_prod a ==> g has_prod b ==> (λn. f n / g n) has_prod (a / b)"
  unfolding divide_inverse by (intro has_prod_inverse has_prod_mult)

lemma convergent_prod_divide:
  assumes f: "convergent_prod f" and g: "convergent_prod g"
  shows "convergent_prod (λn. f n / g n)"
  using f g has_prod_divide has_prod_iff by blast

lemma prodinf_divide: "convergent_prod f ==> convergent_prod g ==> prodinf f / prodinf g = (n. f n / g n)"
  by (intro has_prod_unique has_prod_divide convergent_prod_has_prod)

lemma prodinf_inverse: "convergent_prod f ==> (n. inverse (f n)) = inverse (n. f n)"
  by (intro has_prod_unique [symmetric] has_prod_inverse convergent_prod_has_prod)

lemma has_prod_Suc_imp: 
  assumes "(λn. f (Suc n)) has_prod a"
  shows "f has_prod (a * f 0)"
proof -
  have "f has_prod (a * f 0)" when "raw_has_prod (λn. f (Suc n)) 0 a" 
    apply (cases "f 0=0")
    using that unfolding has_prod_def raw_has_prod_Suc 
    by (auto simp add: raw_has_prod_Suc_iff)
  moreover have "f has_prod (a * f 0)" when 
    "(i q. a = 0 f (Suc i) = 0 raw_has_prod (λn. f (Suc n)) (Suc i) q)" 
  proof -
    from that 
    obtain i q where "a = 0" "f (Suc i) = 0" "raw_has_prod (λn. f (Suc n)) (Suc i) q"
      by auto
    then show ?thesis unfolding has_prod_def 
      by (auto intro!:exI[where x="Suc i"] simp:raw_has_prod_Suc)
  qed
  ultimately show "f has_prod (a * f 0)" using assms unfolding has_prod_def by auto
qed

lemma has_prod_iff_shift: 
  assumes "i. i < n ==> f i 0"
  shows "(λi. f (i + n)) has_prod a f has_prod (a * (i
  using assms
proof (induct n arbitrary: a)
  case 0
  then show ?case by simp
next
  case (Suc n)
  then have "(λi. f (Suc i + n)) has_prod a (λi. f (i + n)) has_prod (a * f n)"
    by (subst has_prod_Suc_iff) auto
  with Suc show ?case
    by (simp add: ac_simps)
qed

corollary🍋tag unimportant has_prod_iff_shift':
  assumes "i. i < n ==> f i 0"
  shows "(λi. f (i + n)) has_prod (a / (i f has_prod a"

  by (simp add: assms has_prod_iff_shift)

lemma has_prod_one_iff_shift:
  assumes "i. i < n ==> f i = 1"
  shows "(λi. f (i+n)) has_prod a (λi. f i) has_prod a"
  by (simp add: assms has_prod_iff_shift)

lemma convergent_prod_iff_shift [simp]:
  shows "convergent_prod (λi. f (i + n)) convergent_prod f"
  apply safe
  using convergent_prod_offset apply blast
  using convergent_prod_ignore_initial_segment convergent_prod_def by blast

lemma has_prod_split_initial_segment:
  assumes "f has_prod a" "i. i < n ==> f i 0"
  shows "(λi. f (i + n)) has_prod (a / (i
  using assms has_prod_iff_shift' by blast

lemma prodinf_divide_initial_segment:
  assumes "convergent_prod f" "i. i < n ==> f i 0"
  shows "(i. f (i + n)) = (i. f i) / (i
  by (rule has_prod_unique[symmetric]) (auto simp: assms has_prod_iff_shift)

lemma prodinf_split_initial_segment:
  assumes "convergent_prod f" "i. i < n ==> f i 0"
  shows "prodinf f = (i. f (i + n)) * (i
  by (auto simp add: assms prodinf_divide_initial_segment)

lemma prodinf_split_head:
  assumes "convergent_prod f" "f 0 0"
  shows "(n. f (Suc n)) = prodinf f / f 0"
  using prodinf_split_initial_segment[of 1] assms by simp

lemma has_prod_ignore_initial_segment':
  assumes "convergent_prod f"
  shows   "f has_prod ((kk. f (k + n)))"

proof (cases "k)
  case True
  hence [simp]: "(k
    by (meson finite_lessThan lessThan_iff prod_zero)
  thus ?thesis using True assms
    by (metis convergent_prod_has_prod_iff has_prod_zeroI mult_not_zero)
next
  case False
  hence "(λi. f (i + n)) has_prod (prodinf f / prod f {..
    using assms by (intro has_prod_split_initial_segment) (auto simp: convergent_prod_has_prod_iff)
  hence "prodinf f = prod f {..k. f (k + n))"

    using False by (simp add: has_prod_iff divide_simps mult_ac)
  thus ?thesis
    using assms by (simp add: convergent_prod_has_prod_iff)
qed

end

context 
  fixes f :: "nat ==> 'a::real_normed_field"
begin

lemma convergent_prod_inverse_iff [simp]: "convergent_prod (λn. inverse (f n)) convergent_prod f"
  by (auto dest: convergent_prod_inverse)

lemma convergent_prod_const_iff [simp]:
  fixes c :: "'a :: {real_normed_field}"
  shows "convergent_prod (λ_. c) c = 1"
proof
  assume "convergent_prod (λ_. c)"
  then show "c = 1"
    using convergent_prod_imp_LIMSEQ LIMSEQ_unique by blast 
next
  assume "c = 1"
  then show "convergent_prod (λ_. c)"
    by auto
qed

lemma has_prod_power: "f has_prod a ==> (λi. f i ^ n) has_prod (a ^ n)"
  by (induction n) (auto simp: has_prod_mult)

lemma convergent_prod_power: "convergent_prod f ==> convergent_prod (λi. f i ^ n)"
  by (induction n) (auto simp: convergent_prod_mult)

lemma prodinf_power: "convergent_prod f ==> prodinf (λi. f i ^ n) = prodinf f ^ n"
  by (metis has_prod_unique convergent_prod_imp_has_prod has_prod_power)

end

lemma prod_ge_prodinf: 
  fixes f :: "nat ==> 'a::{linordered_idom,linorder_topology}"
  assumes "f has_prod a" "i. 0 f i" "i. i n ==> f i 1"
  shows "prod f {.. prodinf f"

proof (rule has_prod_le; (intro conjI)?)
  show "f has_prod prodinf f"
    using assms(1) has_prod_unique by blast
  show "(λr. if r {..
    by (rule has_prod_If_finite_set) auto
next
  fix i 
  show "f i 0"
    by (rule assms)
  show "f i (if i {..
    using assms(3)[of i] by auto
qed

lemma has_prod_less:
  fixes F G :: real
  assumes less: "f m < g m"
  assumes f: "f has_prod F" and g: "g has_prod G"
  assumes pos: "n. 0 < f n" and le: "n. f n g n"
  shows   "F < G"
proof -
  define F' G' where "F' = (n and "G' = (n
  have [simp]: "f n 0" "g n 0" for n
    using pos[of n] le[of n] by auto
  have [simp]: "F' 0" "G' 0"
    by (auto simp: F'_def G'_def)
  have f': "(λn. f (n + Suc m)) has_prod (F / F')"
    unfolding F'_def using f
    by (intro has_prod_split_initial_segment) auto
  have g': "(λn. g (n + Suc m)) has_prod (G / G')"
    unfolding G'_def using g
    by (intro has_prod_split_initial_segment) auto
  have "F' * (F / F') < G' * (F / F')"
  proof (rule mult_strict_right_mono)
    show "F' < G'"
      unfolding F'_def G'_def
      by (rule prod_mono_strict[of m])
         (auto intro: le less_imp_le[OF pos] less_le_trans[OF pos le] less)
    show "F / F' > 0"
      using f' by (rule has_prod_pos) (use pos in auto)
  qed
  also have " G' * (G / G')"
  proof (rule mult_left_mono)
    show "F / F' G / G'"
      using f' g' by (rule has_prod_le) (auto intro: less_imp_le[OF pos] le)
    show "G' 0"
      unfolding G'_def by (intro prod_nonneg order.trans[OF less_imp_le[OF pos] le])
  qed
  finally show ?thesis
    by simp
qed


subsectionExponentials and logarithms

context 
  fixes f :: "nat ==> 'a::{real_normed_field,banach}"
begin

lemma sums_imp_has_prod_exp: 
  assumes "f sums s"
  shows "raw_has_prod (λi. exp (f i)) 0 (exp s)"
  using assms continuous_on_exp [of UNIV "λx::'a. x"]
  using continuous_on_tendsto_compose [of UNIV exp "(λn. sum f {..n})" s]
  by (simp add: prod_defs sums_def_le exp_sum)

lemma convergent_prod_exp: 
  assumes "summable f"
  shows "convergent_prod (λi. exp (f i))"
  using sums_imp_has_prod_exp assms unfolding summable_def convergent_prod_def  by blast

lemma prodinf_exp: 
  assumes "summable f"
  shows "prodinf (λi. exp (f i)) = exp (suminf f)"
proof -
  have "f sums suminf f"
    using assms by blast
  then have "(λi. exp (f i)) has_prod exp (suminf f)"
    by (simp add: has_prod_def sums_imp_has_prod_exp)
  then show ?thesis
    by (rule has_prod_unique [symmetric])
qed

end

theorem convergent_prod_iff_summable_real:
  fixes a :: "nat ==> real"
  assumes "n. a n > 0"
  shows "convergent_prod (λk. 1 + a k) summable a" (is "?lhs = ?rhs")
proof
  assume ?lhs
  then obtain p where "raw_has_prod (λk. 1 + a k) 0 p"
    by (metis assms add_less_same_cancel2 convergent_prod_offset_0 not_one_less_zero)
  then have to_p: "(λn. kn. 1 + a k) <---- p"
    by (auto simp: raw_has_prod_def)
  moreover have le: "(kn. a k) (kn. 1 + a k)" for n
    by (rule sum_le_prod) (use assms less_le in force)
  have "(kn. 1 + a k) p" for n
  proof (rule incseq_le [OF _ to_p])
    show "incseq (λn. kn. 1 + a k)"
      using assms by (auto simp: mono_def order.strict_implies_order intro!: prod_mono2)
  qed
  with le have "(kn. a k) p" for n
    by (metis order_trans)
  with assms bounded_imp_summable show ?rhs
    by (metis not_less order.asym)
next
  assume R: ?rhs
  have "(kn. 1 + a k) exp (suminf a)" for n
  proof -
    have "(kn. 1 + a k) exp (kn. a k)" for n
      by (rule prod_le_exp_sum) (use assms less_le in force)
    moreover have "exp (kn. a k) exp (suminf a)" for n
      unfolding exp_le_cancel_iff
      by (meson sum_le_suminf R assms finite_atMost less_eq_real_def)
    ultimately show ?thesis
      by (meson order_trans)
  qed
  then obtain L where L: "(λn. kn. 1 + a k) <---- L"
    by (metis assms bounded_imp_convergent_prod convergent_prod_iff_nz_lim le_add_same_cancel1 le_add_same_cancel2 less_le not_le zero_le_one)
  moreover have "L 0"
  proof
    assume "L = 0"
    with L have "(λn. kn. 1 + a k) <---- 0"
      by simp
    moreover have "(kn. 1 + a k) > 1" for n
      by (simp add: assms less_1_prod)
    ultimately show False
      by (meson Lim_bounded2 not_one_le_zero less_imp_le)
  qed
  ultimately show ?lhs
    using assms convergent_prod_iff_nz_lim
    by (metis add_less_same_cancel1 less_le not_le zero_less_one)
qed

lemma exp_suminf_prodinf_real:
  fixes f :: "nat ==> real"
  assumes ge0:"n. f n 0" and ac: "abs_convergent_prod (λn. exp (f n))"
  shows "prodinf (λi. exp (f i)) = exp (suminf f)"
proof -
  have "summable f"
    using ac unfolding abs_convergent_prod_conv_summable
  proof (elim summable_comparison_test')
    fix n
    have "f n = f n"
      by (simp add: ge0)
    also have " exp (f n) - 1"
      by (metis diff_diff_add exp_ge_add_one_self ge_iff_diff_ge_0)
    finally show "norm (f n) norm (exp (f n) - 1)"
      by simp
  qed
  then show ?thesis
    by (simp add: prodinf_exp)
qed

lemma has_prod_imp_sums_ln_real: 
  fixes f :: "nat ==> real"
  assumes "raw_has_prod f 0 p" and 0: "x. f x > 0"
  shows "(λi. ln (f i)) sums (ln p)"
proof -
  have "p > 0"
    using assms unfolding prod_defs by (metis LIMSEQ_prod_nonneg less_eq_real_def)
  moreover have "x. f x 0"
    by (smt (verit, best) "0")
  ultimately show ?thesis
    using assms continuous_on_ln [of "{0<..}" "λx. x"]
    using continuous_on_tendsto_compose [of "{0<..}" ln "(λn. prod f {..n})" p]
    by (auto simp: prod_defs sums_def_le ln_prod order_tendstoD)
qed

lemma has_prod_imp_sums_ln_real':
  fixes P :: real
  assumes "f has_prod P" "n. f n > 0"
  shows   "(λn. ln (f n)) sums (ln P)"
proof -
  have nz: "f n 0" for n
    using assms(2)[of n] by simp
  have "P 0"
    using has_prod_eq_0_iff[OF assms(1)] by (auto simp: nz)

  have "(λn. k<---- P"

    using has_prod_imp_tendsto'[OF assms(1)] by simp
  hence "(λn. ln (k<---- ln P"

    by (intro tendsto_intros P 0)
  also have "(λn. ln (kk
    by (subst ln_prod) (auto simp: nz)
  finally show ?thesis
    by (simp add: sums_def)
qed

lemma summable_ln_real: 
  fixes f :: "nat ==> real"
  assumes f: "convergent_prod f" and 0: "x. f x > 0"
  shows "summable (λi. ln (f i))"
proof -
  obtain M p where "raw_has_prod f M p"
    using f convergent_prod_def by blast
  then consider i where "i "f i = 0" | p where "raw_has_prod f 0 p"
    using raw_has_prod_cases by blast
  then show ?thesis
  proof cases
    case 1
    with 0 show ?thesis
      by (metis less_irrefl)
  next
    case 2
    then show ?thesis
      using "0" has_prod_imp_sums_ln_real summable_def by blast
  qed
qed

lemma suminf_ln_real: 
  fixes f :: "nat ==> real"
  assumes f: "convergent_prod f" and 0: "x. f x > 0"
  shows "suminf (λi. ln (f i)) = ln (prodinf f)"
proof -
  have "f has_prod prodinf f"
    by (simp add: f has_prod_iff)
  then have "raw_has_prod f 0 (prodinf f)"
    by (metis "0" has_prod_def less_irrefl)
  then have "(λi. ln (f i)) sums ln (prodinf f)"
    using "0" has_prod_imp_sums_ln_real by blast
  then show ?thesis
    by (rule sums_unique [symmetric])
qed

lemma prodinf_exp_real: 
  fixes f :: "nat ==> real"
  assumes f: "convergent_prod f" and 0: "x. f x > 0"
  shows "prodinf f = exp (suminf (λi. ln (f i)))"
  by (simp add: "0" f less_0_prodinf suminf_ln_real)


theorem Ln_prodinf_complex:
  fixes z :: "nat ==> complex"
  assumes z: "j. z j 0" and ξ:  0"
  shows "((λn. jn. z j) <---- ξ) (k. (λn. (jn. Ln (z j))) <---- Ln ξ + of_int k * (of_real(2*pi) * i))" (is "?lhs = ?rhs")
proof
  assume L: ?lhs
  have pnz: "(jn. z j) 0" for n
    using z by auto
  define Θ where  Arg ξ + 2*pi"
  then have "Θ > pi"
    using Arg_def mpi_less_Im_Ln by fastforce
  have ξ_eq: "ξ = cmod ξ * exp (i * Θ)"
    using Arg_def Arg_eq ξ unfolding Θ_def by (simp add: algebra_simps exp_add)
  define θ where  λn. THE t. is_Arg (jn. z j) t t {Θ-pi<..Θ+pi}"
  have uniq: "!s. is_Arg (jn. z j) s s {Θ-pi<..Θ+pi}" for n
    using Argument_exists_unique [OF pnz] by metis
  have θ: "is_Arg (jn. z j) (θ n)" and θ_interval: "θ n {Θ-pi<..Θ+pi}" for n
    unfolding θ_def
    using theI' [OF uniq] by metis+
  have θ_pos: "j. θ j > 0"
    using θ_interval Θ > pi by simp (meson diff_gt_0_iff_gt less_trans)
  have "(jn. z j) = cmod (jn. z j) * exp (i * θ n)" for n
    using θ by (auto simp: is_Arg_def)
  then have eq: "(λn. jn. z j) = (λn. cmod (jn. z j) * exp (i * θ n))"
    by simp
  then have "(λn. (cmod (jn. z j)) * exp (i * (θ n))) <---- ξ"
    using L by force
  then obtain k where k: "(λj. θ j - of_int (k j) * (2 * pi)) <---- Θ"
    using L by (subst (asm) ξ_eq) (auto simp add: eq z ξ polar_convergence)
  moreover have "🪙F n in sequentially. k n = 0"
  proof -
    have *: "kj = 0" if "dist (vj - real_of_int kj * 2) V < 1" "vj {V - 1<..V + 1}" for kj vj V
      using that  by (auto simp: dist_norm)
    have "🪙F j in sequentially. dist (θ j - of_int (k j) * (2 * pi)) Θ < pi"
      using tendstoD [OF k] pi_gt_zero by blast
    then show ?thesis
    proof (rule eventually_mono)
      fix j
      assume d: "dist (θ j - real_of_int (k j) * (2 * pi)) Θ < pi"
      show "k j = 0"
        by (rule * [of "θ j/pi" _ "Θ/pi"])
           (use θ_interval [of j] d in simp_all add: divide_simps dist_norm)
    qed
  qed
  ultimately have θtoΘ: <---- Θ"
    apply (simp only: tendsto_def)
    apply (erule all_forward imp_forward asm_rl)+
    apply (drule (1) eventually_conj)
    apply (auto elim: eventually_mono)
    done
  then have to0: "(λn. θ (Suc n) - θ n) <---- 0"
    by (metis (full_types) diff_self filterlim_sequentially_Suc tendsto_diff tendsto_rabs_zero)
  have "k. Im (jn. Ln (z j)) - of_int k * (2*pi) = θ n" for n
  proof (rule is_Arg_exp_diff_2pi)
    show "is_Arg (exp (jn. Ln (z j))) (θ n)"
      using pnz θ by (simp add: is_Arg_def exp_sum prod_norm)
  qed
  then have "k. (jn. Im (Ln (z j))) = θ n + of_int k * (2*pi)" for n
    by (simp add: algebra_simps)
  then obtain k where k: "n. (jn. Im (Ln (z j))) = θ n + of_int (k n) * (2*pi)"
    by metis
  obtain K where "🪙F n in sequentially. k n = K"
  proof -
    have k_le: "(2*pi) * k (Suc n) - k n θ (Suc n) - θ n + Im (Ln (z (Suc n)))" for n
    proof -
      have "(jSuc n. Im (Ln (z j))) - (jn. Im (Ln (z j))) = Im (Ln (z (Suc n)))"
        by simp
      then show ?thesis
        using k [of "Suc n"] k [of n] by (auto simp: abs_if algebra_simps)
    qed
    have "z <---- 1"
      using L ξ convergent_prod_iff_nz_lim z by (blast intro: convergent_prod_imp_LIMSEQ)
    with z have "(λn. Ln (z n)) <---- Ln 1"
      using isCont_tendsto_compose [OF continuous_at_Ln] nonpos_Reals_one_I by blast
    then have "(λn. Ln (z n)) <---- 0"
      by simp
    then have "(λn. Im (Ln (z (Suc n)))) <---- 0"
      by (metis LIMSEQ_unique z <---- 1 continuous_at_Ln filterlim_sequentially_Suc isCont_tendsto_compose nonpos_Reals_one_I tendsto_Im tendsto_rabs_zero_iff zero_complex.simps(2))
    then have "🪙F n in sequentially. Im (Ln (z (Suc n))) < 1"
      by (simp add: order_tendsto_iff)
    moreover have "🪙F n in sequentially. θ (Suc n) - θ n < 1"
      using to0 by (simp add: order_tendsto_iff)
    ultimately have "🪙F n in sequentially. (2*pi) * k (Suc n) - k n < 1 + 1" 
    proof (rule eventually_elim2) 
      fix n 
      assume "Im (Ln (z (Suc n))) < 1" and "θ (Suc n) - θ n < 1"
      with k_le [of n] show "2 * pi * real_of_int k (Suc n) - k n < 1 + 1"
        by linarith
    qed
    then have "🪙F n in sequentially. real_of_intk (Suc n) - k n < 1" 
    proof (rule eventually_mono)
      fix n :: "nat"
      assume "2 * pi * k (Suc n) - k n < 1 + 1"
      then have "k (Suc n) - k n < 2 / (2*pi)"
        by (simp add: field_simps)
      also have "... < 1"
        using pi_ge_two by auto
      finally show "real_of_int k (Suc n) - k n < 1" .
    qed
  then obtain N where N: "n. nN ==> k (Suc n) - k n = 0"
    using eventually_sequentially less_irrefl of_int_abs by fastforce
  have "k (N+i) = k N" for i
  proof (induction i)
    case (Suc i)
    with N [of "N+i"show ?case
      by auto
  qed simp
  then have "n. nN ==> k n = k N"
    using le_Suc_ex by auto
  then show ?thesis
    by (force simp add: eventually_sequentially intro: that)
  qed
  with θtoΘ have "(λn. (jn. Im (Ln (z j)))) <---- Θ + of_int K * (2*pi)"
    by (simp add: k tendsto_add tendsto_mult tendsto_eventually)
  moreover have "(λn. (kn. Re (Ln (z k)))) <---- Re (Ln ξ)"
    using assms continuous_imp_tendsto [OF isCont_ln tendsto_norm [OF L]]
    by (simp add: o_def flip: prod_norm ln_prod)
  ultimately show ?rhs
    by (rule_tac x="K+1" in exI) (auto simp: tendsto_complex_iff Θ_def Arg_def assms algebra_simps)
next
  assume ?rhs
  then obtain r where r: "(λn. (kn. Ln (z k))) <---- Ln ξ + of_int r * (of_real(2*pi) * i)" ..
  have "(λn. exp (kn. Ln (z k))) <---- ξ"
    using assms continuous_imp_tendsto [OF isCont_exp r] exp_integer_2pi [of r]
    by (simp add: o_def exp_add algebra_simps)
  moreover have "exp (kn. Ln (z k)) = (kn. z k)" for n
    by (simp add: exp_sum add_eq_0_iff assms)
  ultimately show ?lhs
    by auto
qed

textProp 17.2 of Bak and Newman, Complex Analysis, p.242
proposition convergent_prod_iff_summable_complex:
  fixes z :: "nat ==> complex"
  assumes "k. z k 0"
  shows "convergent_prod (λk. z k) summable (λk. Ln (z k))" (is "?lhs = ?rhs")
proof
  assume ?lhs
  then obtain p where p: "(λn. kn. z k) <---- p" and "p 0"
    using convergent_prod_LIMSEQ prodinf_nonzero add_eq_0_iff assms by fastforce
  then show ?rhs
    using Ln_prodinf_complex assms
    by (auto simp: prodinf_nonzero summable_def sums_def_le)
next
  assume R: ?rhs
  have "(kn. z k) = exp (kn. Ln (z k))" for n
    by (simp add: exp_sum add_eq_0_iff assms)
  then have "(λn. kn. z k) <---- exp (suminf (λk. Ln (z k)))"
    using continuous_imp_tendsto [OF isCont_exp summable_LIMSEQ' [OF R]] by (simp add: o_def)
  then show ?lhs
    by (subst convergent_prod_iff_convergent) (auto simp: convergent_def tendsto_Lim assms add_eq_0_iff)
qed

textProp 17.3 of Bak and Newman, Complex Analysis
proposition summable_imp_convergent_prod_complex:
  fixes z :: "nat ==> complex"
  assumes z: "summable (λk. norm (z k))" and non0: "k. z k -1"
  shows "convergent_prod (λk. 1 + z k)" 
proof -
  obtain N where "k. kN ==> norm (z k) < 1/2"
    using summable_LIMSEQ_zero [OF z]
    by (metis diff_zero dist_norm half_gt_zero_iff less_numeral_extra(1) lim_sequentially tendsto_norm_zero_iff)
  then have "summable (λk. Ln (1 + z k))"
    by (metis norm_Ln_le summable_comparison_test summable_mult z)
  with non0 show ?thesis
    by (simp add: add_eq_0_iff convergent_prod_iff_summable_complex)
qed

corollary summable_imp_convergent_prod_real:
  fixes z :: "nat ==> real"
  assumes z: "summable (λk. z k)" and non0: "k. z k -1"
  shows "convergent_prod (λk. 1 + z k)" 
proof -
  have "k. (complex_of_real z) k - 1"
    by (metis non0 o_apply of_real_1 of_real_eq_iff of_real_minus)
  with z 
  have "convergent_prod (λk. 1 + (complex_of_real z) k)"
    by (auto intro: summable_imp_convergent_prod_complex)
  then show ?thesis 
    using convergent_prod_of_real_iff [of "λk. 1 + z k"by (simp add: o_def)
qed

lemma summable_Ln_complex:
  fixes z :: "nat ==> complex"
  assumes "convergent_prod z" "k. z k 0"
  shows "summable (λk. Ln (z k))"
  using convergent_prod_def assms convergent_prod_iff_summable_complex by blast


subsection🍋tag unimportant Embeddings from the reals into some complete real normed field

lemma tendsto_eq_of_real_lim:
  assumes "(λn. of_real (f n) :: 'a::{complete_space,real_normed_field}) <---- q"
  shows "q = of_real (lim f)"
proof -
  have "convergent (λn. of_real (f n) :: 'a)"
    using assms convergent_def by blast 
  then have "convergent f"
    unfolding convergent_def
    by (simp add: convergent_eq_Cauchy Cauchy_def)
  then show ?thesis
    by (metis LIMSEQ_unique assms convergentD sequentially_bot tendsto_Lim tendsto_of_real)
qed

lemma tendsto_eq_of_real:
  assumes "(λn. of_real (f n) :: 'a::{complete_space,real_normed_field}) <---- q"
  obtains r where "q = of_real r"
  using tendsto_eq_of_real_lim assms by blast

lemma has_prod_of_real_iff [simp]:
  "(λn. of_real (f n) :: 'a::{complete_space,real_normed_field}) has_prod of_real c f has_prod c"
  (is "?lhs = ?rhs")
proof
  assume ?lhs
  then show ?rhs
    apply (auto simp: prod_defs LIMSEQ_prod_0 tendsto_of_real_iff simp flip: of_real_prod)
    using tendsto_eq_of_real
    by (metis of_real_0 tendsto_of_real_iff)
next
  assume ?rhs
  with tendsto_of_real_iff show ?lhs
    by (fastforce simp: prod_defs simp flip: of_real_prod)
qed

subsection Convergence criteria: especially uniform convergence of infinite products

text 

  Cauchy's criterion for the convergence of infinite products, adapted to proving

  uniform convergence: let $f_k(x)$ be a sequence of functions such that

 

  🪙 $f_k(x)$ has uniformly bounded partial products, i.e.there exists a constant C

  such that $\prod_{k=0}^m f_k(x) \leq C$ for all $m$ and $x\in A$.

 

  🪙 For any $\varepsilon > 0$ there exists a number $M \in \mathbb{N}$ such that, for any

  $m, n \geq M$ and all $x\in A$ we have $|(\prod_{k=m}^n f_k(x)) - 1| 🚫varepsilon$

 

  Then $\prod_{k=0}^n f_k(x)$ converges to $\prod_{k=0}^\infty f_k(x)$ uniformly for all

  $x \in A$.

 
lemma uniformly_convergent_prod_Cauchy:
  fixes f :: "nat ==> 'a :: topological_space ==> 'b :: {real_normed_div_algebra, comm_ring_1, banach}"
  assumes C: "x m. x A ==> norm (k C"
  assumes "e. e > 0 ==> M. xA. mM. nm. dist (k=m..n. f k x) 1 < e"
  shows   "uniformly_convergent_on A (λN x. n
proof (rule Cauchy_uniformly_convergent, rule uniformly_Cauchy_onI')
  fix ε :: real assume ε: "ε > 0"
  define C' where "C' = max C 1"
  have C': "C' > 0"
    by (auto simp: C'_def)
  define δ where "δ = Min {2 / 3 * ε / C', 1 / 2}"
  from ε have "δ > 0"
    using C' > 0 by (auto simp: δ_def)
  obtain M where M: "x m n. x A ==> m M ==> n m ==> dist (k=m..n. f k x) 1 < δ"
    using δ > 0 assms by fast

  show "M. xA. mM. n>m. dist (kk
  proof (rule exI, intro ballI allI impI)
    fix x m n
    assume x: "x A" and mn: "M + 1 m" "m < n"
    show "dist (kk
    proof (cases "k)
      case True
      hence "(k and "(k
        using mn x by (auto intro!: prod_zero)
      thus ?thesis
        using ε by simp
    next
      case False
      have *: "{.. {m..n-1}"

        using mn by auto
      have "dist (kk
k
k=m..n-1. f k x) - 1))"

        unfolding * by (subst prod.union_disjoint)
                       (use mn in auto simp: dist_norm algebra_simps norm_minus_commute)
      also have " = (kk=m..n-1. f k x) 1"
        by (simp add: norm_mult dist_norm prod_norm)
      also have " < (k
      proof (rule mult_strict_left_mono)
        show "dist (k = m..n - 1. f k x) 1 < 2 / 3 * ε / C'"
          using M[of x m "n-1"] x mn unfolding δ_def by fastforce
      qed (use False in auto intro!: prod_pos)
      also have "(kk
k=M..
      proof -
        have *: "{.. {M..
          using mn by auto
        show ?thesis
          unfolding * using mn by (subst prod.union_disjoint) (auto simp: prod_norm)
      qed
      also have "norm (k=M.. 3 / 2"
      proof -
        have "dist (k=M..m-1. f k x) 1 < δ"
          using M[of x M "m-1"] x mn δ > 0 by auto
        also have " 1 / 2"
          by (simp add: δ_def)
        also have "{M..m-1} = {M..
          using mn by auto
        finally have "norm (k=M.. norm (1 :: 'b) + 1 / 2"

          by norm
        thus ?thesis
          by simp
      qed
      hence "(kk = M..
             (k
        using ε C' by (intro mult_left_mono mult_right_mono prod_nonneg) auto
      also have " C' * (3 / 2) * (2 / 3 * ε / C')"
      proof (intro mult_right_mono)
        have "(k C"

          using C[of x M] x by (simp add: prod_norm)
        also have " C'"
          by (simp add: C'_def)
        finally show "(k C'" .
      qed (use ε C' in auto)
      finally show "dist (kk
        using C' > 0 by (simp add: field_simps)
    qed
  qed
qed

text 
  By instantiating the set $A$ in this result with a singleton set, we obtain the ``normal''
  Cauchy criterion for infinite products:
 
lemma convergent_prod_Cauchy_sufficient:
  fixes f :: "nat ==> 'b :: {real_normed_div_algebra, comm_ring_1, banach}"
  assumes "e. e > 0 ==> M. m n. M m m n dist (k=m..n. f k) 1 < e"
  shows   "convergent_prod f"
proof -
  obtain M where M: "m n. m M ==> n m ==> dist (prod f {m..n}) 1 < 1 / 2"
    using assms(1)[of "1 / 2"by auto
  have nz: "f m 0" if "m M" for m
    using M[of m m] that by auto

  have M': "dist (prod (λk. f (k + M)) {m.. for m n
  proof (cases "m < n")
    case True
    have "dist (prod f {m+M..n-1+M}) 1 < 1 / 2"
      by (rule M) (use True in auto)
    also have "prod f {m+M..n-1+M} = prod (λk. f (k + M)) {m..
      by (rule prod.reindex_bij_witness[of _ "λk. k + M" "λk. k - M"]) (use True in auto)
    finally show ?thesis .
  qed auto 

  have "uniformly_convergent_on {0::'b} (λN x. n
  proof (rule uniformly_convergent_prod_Cauchy)
    fix m :: nat
    have "norm (k=0..
      using M'[of 0 m] by norm
    thus "norm (k 3 / 2"

      by (simp add: atLeast0LessThan)
  next
    fix e :: real assume e: "e > 0"
    obtain M' where M': "m n. M' m m n dist (k=m..n. f k) 1 < e"
      using assms e by blast
    show "M'. x{0}. mM'. nm. dist (k=m..n. f (k + M)) 1 < e"
    proof (rule exI[of _ M'], intro ballI impI allI)
      fix m n :: nat assume "M' m" "m n"
      thus "dist (k=m..n. f (k + M)) 1 < e"
        using M' by (metis add.commute add_left_mono prod.shift_bounds_cl_nat_ivl trans_le_add1)
    qed
  qed
  hence "convergent (λN. n
    by (rule uniformly_convergent_imp_convergent[of _ _ 0]) auto
  then obtain L where L: "(λN. n<---- L"

    unfolding convergent_def by blast

  show ?thesis
    unfolding convergent_prod_altdef
  proof (rule exI[of _ M], rule exI[of _ L], intro conjI)
    show "nM. f n 0"
      using nz by auto
  next
    show "(λn. in. f (i + M)) <---- L"
      using LIMSEQ_Suc[OF L] by (subst (asm) lessThan_Suc_atMost)
  next
    have "norm L 1 / 2"
    proof (rule tendsto_lowerbound)
      show "(λn. norm (i<---- norm L"

        by (intro tendsto_intros L)
      show "🪙F n in sequentially. 1 / 2 norm (i
      proof (intro always_eventually allI)
        fix m :: nat
        have "norm (k=0.. norm (1 :: 'b) - 1 / 2"

          using M'[of 0 m] by norm
        thus "norm (k 1 / 2"

          by (simp add: atLeast0LessThan)
      qed
    qed auto
    thus "L 0"
      by auto
  qed
qed


text 

  We now prove that the Cauchy criterion for pointwise convergence is both necessary
  and sufficient.
 
lemma convergent_prod_Cauchy_necessary:
  fixes f :: "nat ==> 'b :: {real_normed_field, banach}"
  assumes "convergent_prod f" "e > 0"
  shows   "M. m n. M m m n dist (k=m..n. f k) 1 < e"
proof -
  have *: "M. m n. M m m n dist (k=m..n. f k) 1 < e"
    if f: "convergent_prod f" "0 range f" and e: "e > 0"
    for f :: "nat ==> 'b" and e :: real
  proof -
    have *: "(λn. norm (k<---- norm (k. f k)"
      using has_prod_imp_tendsto' f(1) by (intro tendsto_norm) blast
    from f(1,2) have [simp]: "(k. f k) 0"
      using prodinf_nonzero by fastforce
    obtain M' where M': "norm (k norm (k. f k) / 2" if "m M'" for m
      using order_tendstoD(1)[OF *, of "norm (k. f k) / 2"]
      by (auto simp: eventually_at_top_linorder)
    define M where "M = Min (insert (norm (k. f k) / 2) ((λm. norm (k
    have "M > 0"
      unfolding M_def using f(2) by (subst Min_gr_iff) auto
    have norm_ge: "norm (k M"
 for m
    proof (cases "m M'")
      case True
      have "M norm (k. f k) / 2"
        unfolding M_def by (intro Min.coboundedI) auto
      also from True have "norm (k norm (k. f k) / 2"
        by (intro M')
      finally show ?thesis by linarith
    next
      case False
      thus ?thesis
        unfolding M_def
        by (intro Min.coboundedI) auto
    qed

    have "convergent (λn. k
      using f(1) convergent_def has_prod_imp_tendsto' by blast
    hence "Cauchy (λn. k
      by (rule convergent_Cauchy)
    moreover have "e * M > 0"
      using e M > 0 by auto
    ultimately obtain N where N: "dist (kk if "m N" "n N" for m n
      unfolding Cauchy_def by fast

    show "M. m n. M m m n dist (prod f {m..n}) 1 < e"
    proof (rule exI[of _ N], intro allI impI, goal_cases)
      case (1 m n)
      have "dist (kk
        by (rule N) (use 1 in auto)
      also have "dist (kk
k
k
        by (simp add: dist_norm norm_minus_commute)
      also have "(kk{..∪{m..n}. f k)"
        using 1 by (intro prod.cong) auto
      also have " = (k{..k{m..n}. f k)"
        by (subst prod.union_disjoint) auto
      also have " - (kk∏k{m..n}. f k) - 1)"
        by (simp add: algebra_simps)
      finally have "norm (prod f {m..n} - 1) < e * M / norm (prod f {..
        using f(2) by (auto simp add: norm_mult divide_simps mult_ac)
      also have " e * M / M"
        using e M > 0 f(2) by (intro divide_left_mono norm_ge mult_pos_pos) auto
      also have " = e"
        using M > 0 by simp
      finally show ?case
        by (simp add: dist_norm)
    qed
  qed

  obtain M where M: "f m 0" if "m M" for m
    using convergent_prod_imp_ev_nonzero[OF assms(1)]
    by (auto simp: eventually_at_top_linorder)

  have "M'. m n. M' m m n dist (k=m..n. f (k + M)) 1 < e"
    by (rule *) (use assms M in auto)
  then obtain M' where M': "dist (k=m..n. f (k + M)) 1 < e" if "M' m" "m n" for m n
    by blast

  show "M. m n. M m m n dist (prod f {m..n}) 1 < e"
  proof (rule exI[of _ "M + M'"], safe, goal_cases)
    case (1 m n)
    have "dist (k=m-M..n-M. f (k + M)) 1 < e"
      by (rule M') (use 1 in auto)
    also have "(k=m-M..n-M. f (k + M)) = (k=m..n. f k)"
      using 1 by (intro prod.reindex_bij_witness[of _ "λk. k - M" "λk. k + M"]) auto
    finally show ?case .
  qed
qed

lemma convergent_prod_Cauchy_iff:
  fixes f :: "nat ==> 'b :: {real_normed_field, banach}"
  shows "convergent_prod f (e>0. M. m n. M m m n dist (k=m..n. f k) 1 < e)"
  using convergent_prod_Cauchy_necessary[of f] convergent_prod_Cauchy_sufficient[of f]
  by blast

lemma uniformly_convergent_on_prod:
  fixes f :: "nat ==> 'a :: topological_space ==> 'b :: {real_normed_div_algebra, comm_ring_1, banach}"
  assumes cont: "n. continuous_on A (f n)"
  assumes A: "compact A"
  assumes conv_sum: "uniformly_convergent_on A (λN x. n
  shows   "uniformly_convergent_on A (λN x. n
proof -
  have lim: "uniform_limit A (λn x. kk. norm (f k x)) sequentially"

    by (rule uniform_limit_suminf) fact
  have cont': "🪙F n in sequentially. continuous_on A (λx. k
    using cont by (auto intro!: continuous_intros always_eventually cont)
  have "continuous_on A (λx. k. norm (f k x))"
    by (rule uniform_limit_theorem[OF cont' lim]) auto
  hence "compact ((λx. k. norm (f k x)) ` A)"
    by (intro compact_continuous_image A)
  hence "bounded ((λx. k. norm (f k x)) ` A)"
    by (rule compact_imp_bounded)
  then obtain C where C: "norm (k. norm (f k x)) C" if "x A" for x
    unfolding bounded_iff by blast
  show ?thesis
  proof (rule uniformly_convergent_prod_Cauchy)
    fix x :: 'a and m :: nat
    assume x: "x A"
    have "norm (kk
      by (simp add: prod_norm)
    also have " (k
      by (intro prod_mono) norm
    also have " = (k
      by simp
    also have " exp (k
      by (rule prod_le_exp_sum) auto
    also have "(k (k. norm (f k x))"

    proof (rule sum_le_suminf)
      have "(λn. k<---- (k. norm (f k x))"

        by (rule tendsto_uniform_limitI[OF lim]) fact
      thus "summable (λk. norm (f k x))"
        using sums_def sums_iff by blast
    qed auto
    also have "exp (k. norm (f k x)) exp (norm (k. norm (f k x)))"
      by simp
    also have "norm (k. norm (f k x)) C"
      by (rule C) fact
    finally show "norm (k exp C"

      by - simp_all
  next
    fix ε :: real assume ε: "ε > 0"
    have "uniformly_Cauchy_on A (λN x. n
      by (rule uniformly_convergent_Cauchy) fact
    moreover have "ln (1 + ε) > 0"
      using ε by simp
    ultimately obtain M where M: "m n x. x A ==> M m ==> M n ==>

        dist (kk
      using ε unfolding uniformly_Cauchy_on_def by metis
  
    show "M. xA. mM. nm. dist (k = m..n. 1 + f k x) 1 < ε"
    proof (rule exI, intro ballI allI impI)
      fix x m n
      assume x: "x A" and mn: "M m" "m n"
      have "dist (kk
        by (rule M) (use x mn in auto)
      also have "dist (kk

                 k{.."

        using mn by (subst sum_diff) (auto simp: dist_norm)
      also have "{..
        using mn by auto
      also have "k=m..n. norm (f k x) = (k=m..n. norm (f k x))"
        by (intro abs_of_nonneg sum_nonneg) auto
      finally have *: "(k=m..n. norm (f k x)) < ln (1 + ε)" .
  
      have "dist (k=m..n. 1 + f k x) 1 = norm ((k=m..n. 1 + f k x) - 1)"
        by (simp add: dist_norm)
      also have "norm ((k=m..n. 1 + f k x) - 1) (n=m..n. 1 + norm (f n x)) - 1"
        by (rule norm_prod_minus1_le_prod_minus1)
      also have "(n=m..n. 1 + norm (f n x)) exp (k=m..n. norm (f k x))"
        by (rule prod_le_exp_sum) auto
      also note *
      finally show "dist (k = m..n. 1 + f k x) 1 < ε"
        using ε by - simp_all
    qed
  qed
qed

lemma uniformly_convergent_on_prod':
  fixes f :: "nat ==> 'a :: topological_space ==> 'b :: {real_normed_div_algebra, comm_ring_1, banach}"
  assumes cont: "n. continuous_on A (f n)"
  assumes A: "compact A"
  assumes conv_sum: "uniformly_convergent_on A (λN x. n
  shows "uniformly_convergent_on A (λN x. n
proof -
  have "uniformly_convergent_on A (λN x. n
    by (rule uniformly_convergent_on_prod) (use assms in auto intro!: continuous_intros)
  thus ?thesis
    by simp
qed

end

Messung V0.5 in Prozent
C=96 H=92 G=93

¤ Diese beiden folgenden Angebotsgruppen bietet das Unternehmen0.71Angebot  (Wie Sie bei der Firma Beratungs- und Dienstleistungen beauftragen können 2026-05-03) ¤

*Eine klare Vorstellung vom Zielzustand






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.






                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Software

     Produkte
     Quellcodebibliothek

Aktivitäten

     Artikel über Sicherheit
     Anleitung zur Aktivierung von SSL

Muße

     Gedichte
     Musik
     Bilder

Jenseits des Üblichen ....
    

Besucherstatistik

Besucherstatistik

Monitoring

Montastic status badge