infinite product material
authorpaulson <lp15@cam.ac.uk>
Sun, 03 Jun 2018 15:22:30 +0100
changeset 68361 20375f232f3b
parent 68360 0f19c98fa7be
child 68363 23b2fad1729a
child 68371 17c3b22a9575
infinite product material
src/HOL/Analysis/Brouwer_Fixpoint.thy
src/HOL/Analysis/Henstock_Kurzweil_Integration.thy
src/HOL/Analysis/Infinite_Products.thy
src/HOL/Groups_Big.thy
src/HOL/Set_Interval.thy
src/HOL/Topological_Spaces.thy
--- a/src/HOL/Analysis/Brouwer_Fixpoint.thy	Sat Jun 02 22:57:44 2018 +0100
+++ b/src/HOL/Analysis/Brouwer_Fixpoint.thy	Sun Jun 03 15:22:30 2018 +0100
@@ -40,9 +40,7 @@
 
 lemmas swap_apply1 = swap_apply(1)
 lemmas swap_apply2 = swap_apply(2)
-lemmas lessThan_empty_iff = Iio_eq_empty_iff_nat
 lemmas Zero_notin_Suc = zero_notin_Suc_image
-lemmas atMost_Suc_eq_insert_0 = Iic_Suc_eq_insert_0
 
 lemma pointwise_minimal_pointwise_maximal:
   fixes s :: "(nat \<Rightarrow> nat) set"
--- a/src/HOL/Analysis/Henstock_Kurzweil_Integration.thy	Sat Jun 02 22:57:44 2018 +0100
+++ b/src/HOL/Analysis/Henstock_Kurzweil_Integration.thy	Sun Jun 03 15:22:30 2018 +0100
@@ -3925,55 +3925,42 @@
 subsection \<open>Stronger form with finite number of exceptional points\<close>
 
 lemma fundamental_theorem_of_calculus_interior_strong:
-  fixes f :: "real \<Rightarrow> 'a::banach"
-  assumes "finite s"
-    and "a \<le> b"
-    and "continuous_on {a..b} f"
-    and "\<forall>x\<in>{a <..< b} - s. (f has_vector_derivative f'(x)) (at x)"
-  shows "(f' has_integral (f b - f a)) {a..b}"
+ fixes f :: "real \<Rightarrow> 'a::banach"
+ assumes "finite S"
+   and "a \<le> b" "\<And>x. x \<in> {a <..< b} - S \<Longrightarrow> (f has_vector_derivative f'(x)) (at x)"
+   and "continuous_on {a .. b} f"
+ shows "(f' has_integral (f b - f a)) {a .. b}"
   using assms
-proof (induct "card s" arbitrary: s a b)
-  case 0
+proof (induction arbitrary: a b)
+case empty
   then show ?case
-    by (force simp add: intro: fundamental_theorem_of_calculus_interior)
+    using fundamental_theorem_of_calculus_interior by force
 next
-  case (Suc n)
-  then obtain c s' where cs: "s = insert c s'" and n: "n = card s'"
-    by (metis card_eq_SucD)
-  then have "finite s'"
-    using \<open>finite s\<close> by force
+case (insert x S)
   show ?case
-  proof (cases "c \<in> box a b")
-    case False
-    with \<open>finite s'\<close> show ?thesis
-      using cs n Suc
-      by (metis Diff_iff box_real(1) insert_iff)
+  proof (cases "x \<in> {a<..<b}")
+    case False then show ?thesis
+      using insert by blast
   next
-    let ?P = "\<lambda>i j. \<forall>x\<in>{i <..< j} - s'. (f has_vector_derivative f' x) (at x)"
-    case True
-    then have "a \<le> c" "c \<le> b"
-      by (auto simp: mem_box)
-    moreover have "?P a c" "?P c b"
-      using Suc.prems(4) True \<open>a \<le> c\<close> cs(1) by auto
-    moreover have "continuous_on {a..c} f" "continuous_on {c..b} f"
-      using \<open>continuous_on {a..b} f\<close> \<open>a \<le> c\<close> \<open>c \<le> b\<close> continuous_on_subset by fastforce+
-    ultimately have "(f' has_integral f c - f a + (f b - f c)) {a..b}"
-      using Suc.hyps(1) \<open>finite s'\<close> \<open>n = card s'\<close> by (blast intro: has_integral_combine)
-      then show ?thesis
-        by auto
+    case True then have "a < x" "x < b"
+      by auto
+    have "(f' has_integral f x - f a) {a..x}" "(f' has_integral f b - f x) {x..b}"
+      using \<open>continuous_on {a..b} f\<close> \<open>a < x\<close> \<open>x < b\<close> continuous_on_subset by (force simp: intro!: insert)+
+    then have "(f' has_integral f x - f a + (f b - f x)) {a..b}"
+      using \<open>a < x\<close> \<open>x < b\<close> has_integral_combine less_imp_le by blast
+    then show ?thesis
+      by simp
   qed
 qed
 
 corollary fundamental_theorem_of_calculus_strong:
   fixes f :: "real \<Rightarrow> 'a::banach"
-  assumes "finite s"
+  assumes "finite S"
     and "a \<le> b"
+    and vec: "\<And>x. x \<in> {a..b} - S \<Longrightarrow> (f has_vector_derivative f'(x)) (at x)"
     and "continuous_on {a..b} f"
-    and vec: "\<forall>x\<in>{a..b} - s. (f has_vector_derivative f'(x)) (at x)"
   shows "(f' has_integral (f b - f a)) {a..b}"
-  apply (rule fundamental_theorem_of_calculus_interior_strong[OF assms(1-3), of f'])
-  using vec apply (auto simp: mem_box)
-  done
+  by (rule fundamental_theorem_of_calculus_interior_strong [OF \<open>finite S\<close>]) (force simp: assms)+
 
 proposition indefinite_integral_continuous_left:
   fixes f:: "real \<Rightarrow> 'a::banach"
@@ -7242,7 +7229,6 @@
   define f where "f = (\<lambda>k x. if x \<in> {inverse (of_nat (Suc k))..c} then x powr a else 0)"
   define F where "F = (\<lambda>k. if inverse (of_nat (Suc k)) \<le> c then
                              c powr (a+1)/(a+1) - inverse (real (Suc k)) powr (a+1)/(a+1) else 0)"
-
   {
     fix k :: nat
     have "(f k has_integral F k) {0..c}"
@@ -7448,8 +7434,8 @@
 
 lemma integrable_on_subinterval:
   fixes f :: "'n::ordered_euclidean_space \<Rightarrow> 'a::banach"
-  assumes "f integrable_on s" "{a..b} \<subseteq> s"
+  assumes "f integrable_on S" "{a..b} \<subseteq> S"
   shows "f integrable_on {a..b}"
-  using integrable_on_subcbox[of f s a b] assms by (simp add: cbox_interval)
+  using integrable_on_subcbox[of f S a b] assms by (simp add: cbox_interval)
 
 end
--- a/src/HOL/Analysis/Infinite_Products.thy	Sat Jun 02 22:57:44 2018 +0100
+++ b/src/HOL/Analysis/Infinite_Products.thy	Sun Jun 03 15:22:30 2018 +0100
@@ -50,21 +50,21 @@
     by (rule tendsto_eq_intros refl | simp)+
 qed auto
 
-definition gen_has_prod :: "[nat \<Rightarrow> 'a::{t2_space, comm_semiring_1}, nat, 'a] \<Rightarrow> bool" 
-  where "gen_has_prod f M p \<equiv> (\<lambda>n. \<Prod>i\<le>n. f (i+M)) \<longlonglongrightarrow> p \<and> p \<noteq> 0"
+definition raw_has_prod :: "[nat \<Rightarrow> 'a::{t2_space, comm_semiring_1}, nat, 'a] \<Rightarrow> bool" 
+  where "raw_has_prod f M p \<equiv> (\<lambda>n. \<Prod>i\<le>n. f (i+M)) \<longlonglongrightarrow> p \<and> p \<noteq> 0"
 
 text\<open>The nonzero and zero cases, as in \emph{Complex Analysis} by Joseph Bak and Donald J.Newman, page 241\<close>
 definition has_prod :: "(nat \<Rightarrow> 'a::{t2_space, comm_semiring_1}) \<Rightarrow> 'a \<Rightarrow> bool" (infixr "has'_prod" 80)
-  where "f has_prod p \<equiv> gen_has_prod f 0 p \<or> (\<exists>i q. p = 0 \<and> f i = 0 \<and> gen_has_prod f (Suc i) q)"
+  where "f has_prod p \<equiv> raw_has_prod f 0 p \<or> (\<exists>i q. p = 0 \<and> f i = 0 \<and> raw_has_prod f (Suc i) q)"
 
 definition convergent_prod :: "(nat \<Rightarrow> 'a :: {t2_space,comm_semiring_1}) \<Rightarrow> bool" where
-  "convergent_prod f \<equiv> \<exists>M p. gen_has_prod f M p"
+  "convergent_prod f \<equiv> \<exists>M p. raw_has_prod f M p"
 
 definition prodinf :: "(nat \<Rightarrow> 'a::{t2_space, comm_semiring_1}) \<Rightarrow> 'a"
     (binder "\<Prod>" 10)
   where "prodinf f = (THE p. f has_prod p)"
 
-lemmas prod_defs = gen_has_prod_def has_prod_def convergent_prod_def prodinf_def
+lemmas prod_defs = raw_has_prod_def has_prod_def convergent_prod_def prodinf_def
 
 lemma has_prod_subst[trans]: "f = g \<Longrightarrow> g has_prod z \<Longrightarrow> f has_prod z"
   by simp
@@ -72,34 +72,39 @@
 lemma has_prod_cong: "(\<And>n. f n = g n) \<Longrightarrow> f has_prod c \<longleftrightarrow> g has_prod c"
   by presburger
 
-lemma gen_has_prod_nonzero [simp]: "\<not> gen_has_prod f M 0"
-  by (simp add: gen_has_prod_def)
+lemma raw_has_prod_nonzero [simp]: "\<not> raw_has_prod f M 0"
+  by (simp add: raw_has_prod_def)
 
-lemma gen_has_prod_eq_0:
-  fixes f :: "nat \<Rightarrow> 'a::{idom,t2_space}"
-  assumes p: "gen_has_prod f m p" and i: "f i = 0" "i \<ge> m"
+lemma raw_has_prod_eq_0:
+  fixes f :: "nat \<Rightarrow> 'a::{semidom,t2_space}"
+  assumes p: "raw_has_prod f m p" and i: "f i = 0" "i \<ge> m"
   shows "p = 0"
 proof -
   have eq0: "(\<Prod>k\<le>n. f (k+m)) = 0" if "i - m \<le> n" for n
-    by (metis i that atMost_atLeast0 atMost_iff diff_add finite_atLeastAtMost prod_zero_iff)
+  proof -
+    have "\<exists>k\<le>n. f (k + m) = 0"
+      using i that by auto
+    then show ?thesis
+      by auto
+  qed
   have "(\<lambda>n. \<Prod>i\<le>n. f (i + m)) \<longlonglongrightarrow> 0"
     by (rule LIMSEQ_offset [where k = "i-m"]) (simp add: eq0)
     with p show ?thesis
-      unfolding gen_has_prod_def
+      unfolding raw_has_prod_def
     using LIMSEQ_unique by blast
 qed
 
-lemma has_prod_0_iff: "f has_prod 0 \<longleftrightarrow> (\<exists>i. f i = 0 \<and> (\<exists>p. gen_has_prod f (Suc i) p))"
+lemma has_prod_0_iff: "f has_prod 0 \<longleftrightarrow> (\<exists>i. f i = 0 \<and> (\<exists>p. raw_has_prod f (Suc i) p))"
   by (simp add: has_prod_def)
       
 lemma has_prod_unique2: 
-  fixes f :: "nat \<Rightarrow> 'a::{idom,t2_space}"
+  fixes f :: "nat \<Rightarrow> 'a::{semidom,t2_space}"
   assumes "f has_prod a" "f has_prod b" shows "a = b"
   using assms
-  by (auto simp: has_prod_def gen_has_prod_eq_0) (meson gen_has_prod_def sequentially_bot tendsto_unique)
+  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 \<Rightarrow> 'a :: {idom,t2_space}"
+  fixes f :: "nat \<Rightarrow> 'a :: {semidom,t2_space}"
   shows "f has_prod s \<Longrightarrow> s = prodinf f"
   by (simp add: has_prod_unique2 prodinf_def the_equality)
 
@@ -378,42 +383,55 @@
   shows   "abs_convergent_prod f"
   using assms unfolding abs_convergent_prod_def by (rule convergent_prod_offset)
 
-lemma convergent_prod_ignore_initial_segment:
-  fixes f :: "nat \<Rightarrow> 'a :: {real_normed_field}"
-  assumes "convergent_prod f"
-  shows   "convergent_prod (\<lambda>n. f (n + m))"
+lemma raw_has_prod_ignore_initial_segment:
+  fixes f :: "nat \<Rightarrow> 'a :: real_normed_field"
+  assumes "raw_has_prod f M p" "N \<ge> M"
+  obtains q where  "raw_has_prod f N q"
 proof -
-  from assms obtain M L 
-    where L: "(\<lambda>n. \<Prod>k\<le>n. f (k + M)) \<longlonglongrightarrow> L" "L \<noteq> 0" and nz: "\<And>n. n \<ge> M \<Longrightarrow> f n \<noteq> 0"
-    by (auto simp: convergent_prod_altdef)
-  define C where "C = (\<Prod>k<m. f (k + M))"
+  have p: "(\<lambda>n. \<Prod>k\<le>n. f (k + M)) \<longlonglongrightarrow> p" and "p \<noteq> 0" 
+    using assms by (auto simp: raw_has_prod_def)
+  then have nz: "\<And>n. n \<ge> M \<Longrightarrow> f n \<noteq> 0"
+    using assms by (auto simp: raw_has_prod_eq_0)
+  define C where "C = (\<Prod>k<N-M. f (k + M))"
   from nz have [simp]: "C \<noteq> 0" 
     by (auto simp: C_def)
 
-  from L(1) have "(\<lambda>n. \<Prod>k\<le>n+m. f (k + M)) \<longlonglongrightarrow> L" 
+  from p have "(\<lambda>i. \<Prod>k\<le>i + (N-M). f (k + M)) \<longlonglongrightarrow> p" 
     by (rule LIMSEQ_ignore_initial_segment)
-  also have "(\<lambda>n. \<Prod>k\<le>n+m. f (k + M)) = (\<lambda>n. C * (\<Prod>k\<le>n. f (k + M + m)))"
+  also have "(\<lambda>i. \<Prod>k\<le>i + (N-M). f (k + M)) = (\<lambda>n. C * (\<Prod>k\<le>n. f (k + N)))"
   proof (rule ext, goal_cases)
     case (1 n)
-    have "{..n+m} = {..<m} \<union> {m..n+m}" by auto
-    also have "(\<Prod>k\<in>\<dots>. f (k + M)) = C * (\<Prod>k=m..n+m. f (k + M))"
+    have "{..n+(N-M)} = {..<(N-M)} \<union> {(N-M)..n+(N-M)}" by auto
+    also have "(\<Prod>k\<in>\<dots>. f (k + M)) = C * (\<Prod>k=(N-M)..n+(N-M). f (k + M))"
       unfolding C_def by (rule prod.union_disjoint) auto
-    also have "(\<Prod>k=m..n+m. f (k + M)) = (\<Prod>k\<le>n. f (k + m + M))"
-      by (intro ext prod.reindex_bij_witness[of _ "\<lambda>k. k + m" "\<lambda>k. k - m"]) auto
-    finally show ?case by (simp add: add_ac)
+    also have "(\<Prod>k=(N-M)..n+(N-M). f (k + M)) = (\<Prod>k\<le>n. f (k + (N-M) + M))"
+      by (intro ext prod.reindex_bij_witness[of _ "\<lambda>k. k + (N-M)" "\<lambda>k. k - (N-M)"]) auto
+    finally show ?case
+      using \<open>N \<ge> M\<close> by (simp add: add_ac)
   qed
-  finally have "(\<lambda>n. C * (\<Prod>k\<le>n. f (k + M + m)) / C) \<longlonglongrightarrow> L / C"
+  finally have "(\<lambda>n. C * (\<Prod>k\<le>n. f (k + N)) / C) \<longlonglongrightarrow> p / C"
     by (intro tendsto_divide tendsto_const) auto
-  hence "(\<lambda>n. \<Prod>k\<le>n. f (k + M + m)) \<longlonglongrightarrow> L / C" by simp
-  moreover from \<open>L \<noteq> 0\<close> have "L / C \<noteq> 0" by simp
-  ultimately show ?thesis 
-    unfolding prod_defs by blast
+  hence "(\<lambda>n. \<Prod>k\<le>n. f (k + N)) \<longlonglongrightarrow> p / C" by simp
+  moreover from \<open>p \<noteq> 0\<close> have "p / C \<noteq> 0" by simp
+  ultimately show ?thesis
+    using raw_has_prod_def that by blast 
 qed
 
+corollary convergent_prod_ignore_initial_segment:
+  fixes f :: "nat \<Rightarrow> 'a :: real_normed_field"
+  assumes "convergent_prod f"
+  shows   "convergent_prod (\<lambda>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 convergent_prod_ignore_nonzero_segment:
   fixes f :: "nat \<Rightarrow> 'a :: real_normed_field"
   assumes f: "convergent_prod f" and nz: "\<And>i. i \<ge> M \<Longrightarrow> f i \<noteq> 0"
-  shows "\<exists>p. gen_has_prod f M p"
+  shows "\<exists>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))
 
@@ -551,13 +569,13 @@
   with L show ?thesis by (auto simp: prod_defs)
 qed
 
-lemma gen_has_prod_cases:
+lemma raw_has_prod_cases:
   fixes f :: "nat \<Rightarrow> 'a :: {idom,topological_semigroup_mult,t2_space}"
-  assumes "gen_has_prod f M p"
-  obtains i where "i<M" "f i = 0" | p where "gen_has_prod f 0 p"
+  assumes "raw_has_prod f M p"
+  obtains i where "i<M" "f i = 0" | p where "raw_has_prod f 0 p"
 proof -
   have "(\<lambda>n. \<Prod>i\<le>n. f (i + M)) \<longlonglongrightarrow> p" "p \<noteq> 0"
-    using assms unfolding gen_has_prod_def by blast+
+    using assms unfolding raw_has_prod_def by blast+
   then have "(\<lambda>n. prod f {..<M} * (\<Prod>i\<le>n. f (i + M))) \<longlonglongrightarrow> prod f {..<M} * p"
     by (metis tendsto_mult_left)
   moreover have "prod f {..<M} * (\<Prod>i\<le>n. f (i + M)) = prod f {..n+M}" for n
@@ -572,8 +590,8 @@
   qed
   ultimately have "(\<lambda>n. prod f {..n}) \<longlonglongrightarrow> prod f {..<M} * p"
     by (auto intro: LIMSEQ_offset [where k=M])
-  then have "gen_has_prod f 0 (prod f {..<M} * p)" if "\<forall>i<M. f i \<noteq> 0"
-    using \<open>p \<noteq> 0\<close> assms that by (auto simp: gen_has_prod_def)
+  then have "raw_has_prod f 0 (prod f {..<M} * p)" if "\<forall>i<M. f i \<noteq> 0"
+    using \<open>p \<noteq> 0\<close> assms that by (auto simp: raw_has_prod_def)
   then show thesis
     using that by blast
 qed
@@ -581,8 +599,8 @@
 corollary convergent_prod_offset_0:
   fixes f :: "nat \<Rightarrow> 'a :: {idom,topological_semigroup_mult,t2_space}"
   assumes "convergent_prod f" "\<And>i. f i \<noteq> 0"
-  shows "\<exists>p. gen_has_prod f 0 p"
-  using assms convergent_prod_def gen_has_prod_cases by blast
+  shows "\<exists>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 \<Rightarrow> 'a :: {idom,topological_semigroup_mult,t2_space}"
@@ -648,7 +666,7 @@
 qed
 
 lemma has_prod_finite:
-  fixes f :: "nat \<Rightarrow> 'a::{idom,t2_space}"
+  fixes f :: "nat \<Rightarrow> 'a::{semidom,t2_space}"
   assumes [simp]: "finite N"
     and f: "\<And>n. n \<notin> N \<Longrightarrow> f n = 1"
   shows "f has_prod (\<Prod>n\<in>N. f n)"
@@ -668,7 +686,7 @@
     moreover have "(\<lambda>n. prod f {..n}) \<longlonglongrightarrow> 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: gen_has_prod_def has_prod_def)
+      by (simp add: raw_has_prod_def has_prod_def)
   next
     case False
     then obtain k where "k \<in> N" "f k = 0"
@@ -692,8 +710,8 @@
            (use Max.coboundedI [OF \<open>finite N\<close>] f in \<open>force+\<close>)
       finally show ?thesis .
     qed
-    have q: "gen_has_prod f (Suc (Max ?Z)) ?q"
-    proof (simp add: gen_has_prod_def)
+    have q: "raw_has_prod f (Suc (Max ?Z)) ?q"
+    proof (simp add: raw_has_prod_def)
       show "(\<lambda>n. \<Prod>i\<le>n. f (Suc (i + Max ?Z))) \<longlonglongrightarrow> ?q"
         by (rule LIMSEQ_offset[of _ "(Max N)"]) (simp add: eq)
     qed
@@ -709,17 +727,20 @@
 qed
 
 corollary has_prod_0:
-  fixes f :: "nat \<Rightarrow> 'a::{idom,t2_space}"
+  fixes f :: "nat \<Rightarrow> 'a::{semidom,t2_space}"
   assumes "\<And>n. f n = 1"
   shows "f has_prod 1"
   by (simp add: assms has_prod_cong)
 
+lemma prodinf_zero[simp]: "prodinf (\<lambda>n. 1::'a::real_normed_field) = 1"
+  using has_prod_unique by force
+
 lemma convergent_prod_finite:
   fixes f :: "nat \<Rightarrow> 'a::{idom,t2_space}"
   assumes "finite N" "\<And>n. n \<notin> N \<Longrightarrow> f n = 1"
   shows "convergent_prod f"
 proof -
-  have "\<exists>n p. gen_has_prod f n p"
+  have "\<exists>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)
@@ -759,12 +780,12 @@
   assumes "convergent_prod f"
   shows "\<exists>p. f has_prod p"
 proof -
-  obtain M p where p: "gen_has_prod f M p"
+  obtain M p where p: "raw_has_prod f M p"
     using assms convergent_prod_def by blast
   then have "p \<noteq> 0"
-    using gen_has_prod_nonzero by blast
+    using raw_has_prod_nonzero by blast
   with p have fnz: "f i \<noteq> 0" if "i \<ge> M" for i
-    using gen_has_prod_eq_0 that by blast
+    using raw_has_prod_eq_0 that by blast
   define C where "C = (\<Prod>n<M. f n)"
   show ?thesis
   proof (cases "\<forall>n\<le>M. f n \<noteq> 0")
@@ -781,7 +802,7 @@
       by (metis (mono_tags, lifting) GreatestI_ex_nat nat_le_linear)
     have "f i \<noteq> 0" if "i > ?N" for i
       by (metis (mono_tags, lifting) Greatest_le_nat fnz leD linear that)
-    then have "\<exists>p. gen_has_prod f (Suc ?N) p"
+    then have "\<exists>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
@@ -796,7 +817,7 @@
 lemma convergent_prod_LIMSEQ:
   shows "convergent_prod f \<Longrightarrow> (\<lambda>n. \<Prod>i\<le>n. f i) \<longlonglongrightarrow> prodinf f"
   by (metis convergent_LIMSEQ_iff convergent_prod_has_prod convergent_prod_imp_convergent 
-      convergent_prod_to_zero_iff gen_has_prod_eq_0 has_prod_def prodinf_eq_lim zero_le)
+      convergent_prod_to_zero_iff raw_has_prod_eq_0 has_prod_def prodinf_eq_lim zero_le)
 
 lemma has_prod_iff: "f has_prod x \<longleftrightarrow> convergent_prod f \<and> prodinf f = x"
 proof
@@ -818,4 +839,494 @@
 
 end
 
+subsection \<open>Infinite products on ordered, topological monoids\<close>
+
+lemma LIMSEQ_prod_0: 
+  fixes f :: "nat \<Rightarrow> 'a::{semidom,topological_space}"
+  assumes "f i = 0"
+  shows "(\<lambda>n. prod f {..n}) \<longlonglongrightarrow> 0"
+proof (subst tendsto_cong)
+  show "\<forall>\<^sub>F n in sequentially. prod f {..n} = 0"
+  proof
+    show "prod f {..n} = 0" if "n \<ge> i" for n
+      using that assms by auto
+  qed
+qed auto
+
+lemma LIMSEQ_prod_nonneg: 
+  fixes f :: "nat \<Rightarrow> 'a::{linordered_semidom,linorder_topology}"
+  assumes 0: "\<And>n. 0 \<le> f n" and a: "(\<lambda>n. prod f {..n}) \<longlonglongrightarrow> a"
+  shows "a \<ge> 0"
+  by (simp add: "0" prod_nonneg LIMSEQ_le_const [OF a])
+
+
+context
+  fixes f :: "nat \<Rightarrow> 'a::{linordered_semidom,linorder_topology}"
+begin
+
+lemma has_prod_le:
+  assumes f: "f has_prod a" and g: "g has_prod b" and le: "\<And>n. 0 \<le> f n \<and> f n \<le> g n"
+  shows "a \<le> b"
+proof (cases "a=0 \<or> b=0")
+  case True
+  then show ?thesis
+  proof
+    assume [simp]: "a=0"
+    have "b \<ge> 0"
+    proof (rule LIMSEQ_prod_nonneg)
+      show "(\<lambda>n. prod g {..n}) \<longlonglongrightarrow> 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: "\<And>n. 0 \<le> f n \<and> f n \<le> g n"
+  shows "prodinf f \<le> prodinf g"
+  using has_prod_le [OF assms] has_prod_unique f g  by blast
+
 end
+
+
+lemma prod_le_prodinf: 
+  fixes f :: "nat \<Rightarrow> 'a::{linordered_idom,linorder_topology}"
+  assumes "f has_prod a" "\<And>i. 0 \<le> f i" "\<And>i. i\<ge>n \<Longrightarrow> 1 \<le> f i"
+  shows "prod f {..<n} \<le> 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 \<Rightarrow> 'a::{linordered_idom,linorder_topology}"
+  assumes "f has_prod a" "\<And>i. 1 \<le> f i" 
+  shows "1 \<le> 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 \<Rightarrow> real"
+  assumes "convergent_prod f" "\<And>n. prod f {..<n} \<le> x" 
+  shows "prodinf f \<le> x"
+  by (metis lessThan_Suc_atMost assms convergent_prod_LIMSEQ LIMSEQ_le_const2)
+
+lemma prodinf_eq_one_iff: 
+  fixes f :: "nat \<Rightarrow> real"
+  assumes f: "convergent_prod f" and ge1: "\<And>n. 1 \<le> f n"
+  shows "prodinf f = 1 \<longleftrightarrow> (\<forall>n. f n = 1)"
+proof
+  assume "prodinf f = 1" 
+  then have "(\<lambda>n. \<Prod>i<n. f i) \<longlonglongrightarrow> 1"
+    using convergent_prod_LIMSEQ[of f] assms by (simp add: LIMSEQ_lessThan_iff_atMost)
+  then have "\<And>i. (\<Prod>n\<in>{i}. f n) \<le> 1"
+  proof (rule LIMSEQ_le_const)
+    have "1 \<le> prod f n" for n
+      by (simp add: ge1 prod_ge_1)
+    have "prod f {..<n} = 1" for n
+      by (metis \<open>\<And>n. 1 \<le> prod f n\<close> \<open>prodinf f = 1\<close> antisym f convergent_prod_has_prod ge1 order_trans prod_le_prodinf zero_le_one)
+    then have "(\<Prod>n\<in>{i}. f n) \<le> prod f {..<n}" if "n \<ge> Suc i" for i n
+      by (metis mult.left_neutral order_refl prod.cong prod.neutral_const prod_lessThan_Suc)
+    then show "\<exists>N. \<forall>n\<ge>N. (\<Prod>n\<in>{i}. f n) \<le> prod f {..<n}" for i
+      by blast      
+  qed
+  with ge1 show "\<forall>n. f n = 1"
+    by (auto intro!: antisym)
+qed (metis prodinf_zero fun_eq_iff)
+
+lemma prodinf_pos_iff:
+  fixes f :: "nat \<Rightarrow> real"
+  assumes "convergent_prod f" "\<And>n. 1 \<le> f n"
+  shows "1 < prodinf f \<longleftrightarrow> (\<exists>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 \<Rightarrow> real"
+  assumes "convergent_prod f" "\<And>n. 1 \<le> f n" "1 < f i"
+  shows "1 < prodinf f"
+proof -
+  have "1 < (\<Prod>n<Suc i. f n)"
+    using assms  by (intro less_1_prod2[where i=i]) auto
+  also have "\<dots> \<le> prodinf f"
+    by (intro prod_le_prodinf) (use assms order_trans zero_le_one in \<open>blast+\<close>)
+  finally show ?thesis .
+qed
+
+lemma less_1_prodinf:
+  fixes f :: "nat \<Rightarrow> real"
+  shows "\<lbrakk>convergent_prod f; \<And>n. 1 < f n\<rbrakk> \<Longrightarrow> 1 < prodinf f"
+  by (intro less_1_prodinf2[where i=1]) (auto intro: less_imp_le)
+
+lemma prodinf_nonzero:
+  fixes f :: "nat \<Rightarrow> 'a :: {idom,topological_semigroup_mult,t2_space}"
+  assumes "convergent_prod f" "\<And>i. f i \<noteq> 0"
+  shows "prodinf f \<noteq> 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 \<Rightarrow> real"
+  assumes f: "convergent_prod f" and 0: "\<And>i. f i > 0"
+  shows "0 < prodinf f"
+proof -
+  have "prodinf f \<noteq> 0"
+    by (metis assms less_irrefl prodinf_nonzero)
+  moreover have "0 < (\<Prod>n<i. f n)" for i
+    by (simp add: 0 prod_pos)
+  then have "prodinf f \<ge> 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 \<Rightarrow> real"
+  assumes f: "convergent_prod f" and 1: "\<And>m. m\<ge>n \<Longrightarrow> 1 \<le> f m" and 0: "\<And>m. 0 < f m" and i: "n \<le> i" "1 < f i"
+  shows "prod f {..<n} < prodinf f"
+proof -
+  have "prod f {..<n} \<le> prod f {..<i}"
+    by (rule prod_mono2) (use assms less_le in auto)
+  then have "prod f {..<n} < f i * prod f {..<i}"
+    using mult_less_le_imp_less[of 1 "f i" "prod f {..<n}" "prod f {..<i}"] assms
+    by (simp add: prod_pos)
+  moreover have "prod f {..<Suc i} \<le> prodinf f"
+    using prod_le_prodinf[of f _ "Suc i"]
+    by (meson "0" "1" Suc_leD convergent_prod_has_prod f \<open>n \<le> i\<close> 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 \<Rightarrow> real"
+  assumes f: "convergent_prod f" and 1: "\<And>m. m\<ge>n \<Longrightarrow> 1 < f m" and 0: "\<And>m. 0 < f m" 
+  shows "prod f {..<n} < prodinf f"
+  by (meson "0" "1" f le_less prod_less_prodinf2)
+
+lemma raw_has_prodI_bounded:
+  fixes f :: "nat \<Rightarrow> real"
+  assumes pos: "\<And>n. 1 \<le> f n"
+    and le: "\<And>n. (\<Prod>i<n. f i) \<le> x"
+  shows "\<exists>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 (\<lambda>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}) \<noteq> 0"
+    by auto
+  show "incseq (\<lambda>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 \<Rightarrow> real"
+  assumes "\<And>n. 1 \<le> f n" "\<And>n. (\<Prod>i<n. f i) \<le> x"
+  shows "convergent_prod f"
+  using convergent_prod_def raw_has_prodI_bounded [OF assms] by blast
+
+
+subsection \<open>Infinite products on topological monoids\<close>
+
+context
+  fixes f g :: "nat \<Rightarrow> 'a::{t2_space,topological_semigroup_mult,idom}"
+begin
+
+lemma raw_has_prod_mult: "\<lbrakk>raw_has_prod f M a; raw_has_prod g M b\<rbrakk> \<Longrightarrow> raw_has_prod (\<lambda>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: "\<lbrakk>f has_prod a; g has_prod b; a \<noteq> 0; b \<noteq> 0\<rbrakk> \<Longrightarrow> (\<lambda>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 \<Rightarrow> 'a::real_normed_field"
+begin
+
+lemma has_prod_mult:
+  assumes f: "f has_prod a" and g: "g has_prod b"
+  shows "(\<lambda>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 (\<lambda>n. f n * g n) (Suc j))"
+      using q raw_has_prod_mult by blast
+    then show ?thesis
+      using \<open>b = 0\<close> \<open>g j = 0\<close> 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 (\<lambda>n. f n * g n) (Suc i))"
+      using raw_has_prod_mult p by blast
+    then show ?thesis
+      using \<open>a = 0\<close> \<open>f i = 0\<close> 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 \<open>b = 0\<close> by (simp add: has_prod_def) (metis \<open>f i = 0\<close> \<open>g j = 0\<close> 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 (\<lambda>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 "\<exists>M p. raw_has_prod (\<lambda>n. f n * g n) M p"
+    using raw_has_prod_mult by blast
+qed
+
+lemma prodinf_mult: "convergent_prod f \<Longrightarrow> convergent_prod g \<Longrightarrow> prodinf f * prodinf g = (\<Prod>n. f n * g n)"
+  by (intro has_prod_unique has_prod_mult convergent_prod_has_prod)
+
+end
+
+context
+  fixes f :: "'i \<Rightarrow> nat \<Rightarrow> 'a::real_normed_field"
+    and I :: "'i set"
+begin
+
+lemma has_prod_prod: "(\<And>i. i \<in> I \<Longrightarrow> (f i) has_prod (x i)) \<Longrightarrow> (\<lambda>n. \<Prod>i\<in>I. f i n) has_prod (\<Prod>i\<in>I. x i)"
+  by (induct I rule: infinite_finite_induct) (auto intro!: has_prod_mult)
+
+lemma prodinf_prod: "(\<And>i. i \<in> I \<Longrightarrow> convergent_prod (f i)) \<Longrightarrow> (\<Prod>n. \<Prod>i\<in>I. f i n) = (\<Prod>i\<in>I. \<Prod>n. f i n)"
+  using has_prod_unique[OF has_prod_prod, OF convergent_prod_has_prod] by simp
+
+lemma convergent_prod_prod: "(\<And>i. i \<in> I \<Longrightarrow> convergent_prod (f i)) \<Longrightarrow> convergent_prod (\<lambda>n. \<Prod>i\<in>I. f i n)"
+  using convergent_prod_has_prod_iff has_prod_prod prodinf_prod by force
+
+end
+
+subsection \<open>Infinite summability on real normed vector spaces\<close>
+
+context
+  fixes f :: "nat \<Rightarrow> 'a::real_normed_field"
+begin
+
+lemma raw_has_prod_Suc_iff: "raw_has_prod f M (a * f M) \<longleftrightarrow> raw_has_prod (\<lambda>n. f (Suc n)) M a \<and> f M \<noteq> 0"
+proof -
+  have "raw_has_prod f M (a * f M) \<longleftrightarrow> (\<lambda>i. \<Prod>j\<le>Suc i. f (j+M)) \<longlonglongrightarrow> a * f M \<and> a * f M \<noteq> 0"
+    by (subst LIMSEQ_Suc_iff) (simp add: raw_has_prod_def)
+  also have "\<dots> \<longleftrightarrow> (\<lambda>i. (\<Prod>j\<le>i. f (Suc j + M)) * f M) \<longlonglongrightarrow> a * f M \<and> a * f M \<noteq> 0"
+    by (simp add: ac_simps atMost_Suc_eq_insert_0 image_Suc_atMost prod_atLeast1_atMost_eq lessThan_Suc_atMost)
+  also have "\<dots> \<longleftrightarrow> raw_has_prod (\<lambda>n. f (Suc n)) M a \<and> f M \<noteq> 0"
+  proof safe
+    assume tends: "(\<lambda>i. (\<Prod>j\<le>i. f (Suc j + M)) * f M) \<longlonglongrightarrow> a * f M" and 0: "a * f M \<noteq> 0"
+    with tendsto_divide[OF tends tendsto_const, of "f M"]    
+    show "raw_has_prod (\<lambda>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 \<noteq> 0" shows "(\<lambda>n. f (Suc n)) has_prod a \<longleftrightarrow> 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 (\<lambda>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 "\<exists>i. f i = 0 \<and> Ex (raw_has_prod f (Suc i))"
+      using \<open>f (Suc i) = 0\<close> 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 "\<exists> y. raw_has_prod (\<lambda>n. f (Suc n)) i y"
+      using x by (auto simp: raw_has_prod_def)
+    then show "\<exists>i. f (Suc i) = 0 \<and> Ex (raw_has_prod (\<lambda>n. f (Suc n)) (Suc i))"
+      using \<open>f i = 0\<close> j by 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:
+  assumes "\<And>k. f k \<noteq> 0" shows "convergent_prod (\<lambda>n. f (Suc n)) = convergent_prod f"
+proof
+  assume "convergent_prod f"
+  then have "f has_prod prodinf f"
+    by (rule convergent_prod_has_prod)
+  moreover have "prodinf f \<noteq> 0"
+    by (simp add: \<open>convergent_prod f\<close> assms prodinf_nonzero)
+  ultimately have "(\<lambda>n. f (Suc n)) has_prod (prodinf f * inverse (f 0))"
+    by (simp add: has_prod_Suc_iff inverse_eq_divide assms)
+  then show "convergent_prod (\<lambda>n. f (Suc n))"
+    using has_prod_iff by blast
+next
+  assume "convergent_prod (\<lambda>n. f (Suc n))"
+  then show "convergent_prod f"
+    using assms convergent_prod_def raw_has_prod_Suc_iff by blast
+qed
+
+lemma raw_has_prod_inverse: 
+  assumes "raw_has_prod f M a" shows "raw_has_prod (\<lambda>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 "(\<lambda>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 (\<lambda>n. inverse (f n))"
+  using assms unfolding convergent_prod_def  by (blast intro: raw_has_prod_inverse elim: )
+
+end
+
+context (* Separate contexts are necessary to allow general use of the results above, here. *)
+  fixes f :: "nat \<Rightarrow> 'a::real_normed_field"
+begin
+
+lemma raw_has_prod_Suc_iff': "raw_has_prod f M a \<longleftrightarrow> raw_has_prod (\<lambda>n. f (Suc n)) M (a / f M) \<and> f M \<noteq> 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 \<Longrightarrow> g has_prod b \<Longrightarrow> (\<lambda>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 (\<lambda>n. f n / g n)"
+  using f g has_prod_divide has_prod_iff by blast
+
+lemma prodinf_divide: "convergent_prod f \<Longrightarrow> convergent_prod g \<Longrightarrow> prodinf f / prodinf g = (\<Prod>n. f n / g n)"
+  by (intro has_prod_unique has_prod_divide convergent_prod_has_prod)
+
+lemma prodinf_inverse: "convergent_prod f \<Longrightarrow> (\<Prod>n. inverse (f n)) = inverse (\<Prod>n. f n)"
+  by (intro has_prod_unique [symmetric] has_prod_inverse convergent_prod_has_prod)
+
+lemma has_prod_iff_shift: 
+  assumes "\<And>i. i < n \<Longrightarrow> f i \<noteq> 0"
+  shows "(\<lambda>i. f (i + n)) has_prod a \<longleftrightarrow> f has_prod (a * (\<Prod>i<n. f i))"
+  using assms
+proof (induct n arbitrary: a)
+  case 0
+  then show ?case by simp
+next
+  case (Suc n)
+  then have "(\<lambda>i. f (Suc i + n)) has_prod a \<longleftrightarrow> (\<lambda>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 has_prod_iff_shift':
+  assumes "\<And>i. i < n \<Longrightarrow> f i \<noteq> 0"
+  shows "(\<lambda>i. f (i + n)) has_prod (a / (\<Prod>i<n. f i)) \<longleftrightarrow> f has_prod a"
+  by (simp add: assms has_prod_iff_shift)
+
+lemma has_prod_one_iff_shift:
+  assumes "\<And>i. i < n \<Longrightarrow> f i = 1"
+  shows "(\<lambda>i. f (i+n)) has_prod a \<longleftrightarrow> (\<lambda>i. f i) has_prod a"
+  by (simp add: assms has_prod_iff_shift)
+
+lemma convergent_prod_iff_shift:
+  shows "convergent_prod (\<lambda>i. f (i + n)) \<longleftrightarrow> 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" "\<And>i. i < n \<Longrightarrow> f i \<noteq> 0"
+  shows "(\<lambda>i. f (i + n)) has_prod (a / (\<Prod>i<n. f i))"
+  using assms has_prod_iff_shift' by blast
+
+lemma prodinf_divide_initial_segment:
+  assumes "convergent_prod f" "\<And>i. i < n \<Longrightarrow> f i \<noteq> 0"
+  shows "(\<Prod>i. f (i + n)) = (\<Prod>i. f i) / (\<Prod>i<n. f i)"
+  by (rule has_prod_unique[symmetric]) (auto simp: assms has_prod_iff_shift)
+
+lemma prodinf_split_initial_segment:
+  assumes "convergent_prod f" "\<And>i. i < n \<Longrightarrow> f i \<noteq> 0"
+  shows "prodinf f = (\<Prod>i. f (i + n)) * (\<Prod>i<n. f i)"
+  by (auto simp add: assms prodinf_divide_initial_segment)
+
+lemma prodinf_split_head:
+  assumes "convergent_prod f" "f 0 \<noteq> 0"
+  shows "(\<Prod>n. f (Suc n)) = prodinf f / f 0"
+  using prodinf_split_initial_segment[of 1] assms by simp
+
+end
+
+context (* Separate contexts are necessary to allow general use of the results above, here. *)
+  fixes f :: "nat \<Rightarrow> 'a::real_normed_field"
+begin
+
+lemma convergent_prod_inverse_iff: "convergent_prod (\<lambda>n. inverse (f n)) \<longleftrightarrow> convergent_prod f"
+  by (auto dest: convergent_prod_inverse)
+
+lemma convergent_prod_const_iff:
+  fixes c :: "'a :: {real_normed_field}"
+  shows "convergent_prod (\<lambda>_. c) \<longleftrightarrow> c = 1"
+proof
+  assume "convergent_prod (\<lambda>_. c)"
+  then show "c = 1"
+    using convergent_prod_imp_LIMSEQ LIMSEQ_unique by blast 
+next
+  assume "c = 1"
+  then show "convergent_prod (\<lambda>_. c)"
+    by auto
+qed
+
+lemma has_prod_power: "f has_prod a \<Longrightarrow> (\<lambda>i. f i ^ n) has_prod (a ^ n)"
+  by (induction n) (auto simp: has_prod_mult)
+
+lemma convergent_prod_power: "convergent_prod f \<Longrightarrow> convergent_prod (\<lambda>i. f i ^ n)"
+  by (induction n) (auto simp: convergent_prod_mult)
+
+lemma prodinf_power: "convergent_prod f \<Longrightarrow> prodinf (\<lambda>i. f i ^ n) = prodinf f ^ n"
+  by (metis has_prod_unique convergent_prod_imp_has_prod has_prod_power)
+
+end
+
+end
--- a/src/HOL/Groups_Big.thy	Sat Jun 02 22:57:44 2018 +0100
+++ b/src/HOL/Groups_Big.thy	Sun Jun 03 15:22:30 2018 +0100
@@ -1302,17 +1302,20 @@
     by simp
 qed
 
-lemma (in linordered_semidom) prod_nonneg: "(\<forall>a\<in>A. 0 \<le> f a) \<Longrightarrow> 0 \<le> prod f A"
+context linordered_semidom
+begin
+
+lemma prod_nonneg: "(\<forall>a\<in>A. 0 \<le> f a) \<Longrightarrow> 0 \<le> prod f A"
   by (induct A rule: infinite_finite_induct) simp_all
 
-lemma (in linordered_semidom) prod_pos: "(\<forall>a\<in>A. 0 < f a) \<Longrightarrow> 0 < prod f A"
+lemma prod_pos: "(\<forall>a\<in>A. 0 < f a) \<Longrightarrow> 0 < prod f A"
   by (induct A rule: infinite_finite_induct) simp_all
 
-lemma (in linordered_semidom) prod_mono:
+lemma prod_mono:
   "(\<And>i. i \<in> A \<Longrightarrow> 0 \<le> f i \<and> f i \<le> g i) \<Longrightarrow> prod f A \<le> prod g A"
   by (induct A rule: infinite_finite_induct) (force intro!: prod_nonneg mult_mono)+
 
-lemma (in linordered_semidom) prod_mono_strict:
+lemma prod_mono_strict:
   assumes "finite A" "\<And>i. i \<in> A \<Longrightarrow> 0 \<le> f i \<and> f i < g i" "A \<noteq> {}"
   shows "prod f A < prod g A"
   using assms
@@ -1324,6 +1327,42 @@
   then show ?case by (force intro: mult_strict_mono' prod_nonneg)
 qed
 
+end
+
+lemma prod_mono2:
+  fixes f :: "'a \<Rightarrow> 'b :: linordered_idom"
+  assumes fin: "finite B"
+    and sub: "A \<subseteq> B"
+    and nn: "\<And>b. b \<in> B-A \<Longrightarrow> 1 \<le> f b"
+    and A: "\<And>a. a \<in> A \<Longrightarrow> 0 \<le> f a"
+  shows "prod f A \<le> prod f B"
+proof -
+  have "prod f A \<le> prod f A * prod f (B-A)"
+    by (metis prod_ge_1 A mult_le_cancel_left1 nn not_less prod_nonneg)
+  also from fin finite_subset[OF sub fin] have "\<dots> = prod f (A \<union> (B-A))"
+    by (simp add: prod.union_disjoint del: Un_Diff_cancel)
+  also from sub have "A \<union> (B-A) = B" by blast
+  finally show ?thesis .
+qed
+
+lemma less_1_prod:
+  fixes f :: "'a \<Rightarrow> 'b::linordered_idom"
+  shows "finite I \<Longrightarrow> I \<noteq> {} \<Longrightarrow> (\<And>i. i \<in> I \<Longrightarrow> 1 < f i) \<Longrightarrow> 1 < prod f I"
+  by (induct I rule: finite_ne_induct) (auto intro: less_1_mult)
+
+lemma less_1_prod2:
+  fixes f :: "'a \<Rightarrow> 'b::linordered_idom"
+  assumes I: "finite I" "i \<in> I" "1 < f i" "\<And>i. i \<in> I \<Longrightarrow> 1 \<le> f i"
+  shows "1 < prod f I"
+proof -
+  have "1 < f i * prod f (I - {i})"
+    using assms
+    by (meson DiffD1 leI less_1_mult less_le_trans mult_le_cancel_left1 prod_ge_1)
+  also have "\<dots> = prod f I"
+    using assms by (simp add: prod.remove)
+  finally show ?thesis .
+qed
+
 lemma (in linordered_field) abs_prod: "\<bar>prod f A\<bar> = (\<Prod>x\<in>A. \<bar>f x\<bar>)"
   by (induct A rule: infinite_finite_induct) (simp_all add: abs_mult)
 
--- a/src/HOL/Set_Interval.thy	Sat Jun 02 22:57:44 2018 +0100
+++ b/src/HOL/Set_Interval.thy	Sun Jun 03 15:22:30 2018 +0100
@@ -507,7 +507,7 @@
 lemma Iio_eq_empty_iff: "{..< n::'a::{linorder, order_bot}} = {} \<longleftrightarrow> n = bot"
   by (auto simp: set_eq_iff not_less le_bot)
 
-lemma Iio_eq_empty_iff_nat: "{..< n::nat} = {} \<longleftrightarrow> n = 0"
+lemma lessThan_empty_iff: "{..< n::nat} = {} \<longleftrightarrow> n = 0"
   by (simp add: Iio_eq_empty_iff bot_nat_def)
 
 lemma mono_image_least:
@@ -709,7 +709,7 @@
 lemma lessThan_Suc_atMost: "lessThan (Suc k) = atMost k"
 by (simp add: lessThan_def atMost_def less_Suc_eq_le)
 
-lemma Iic_Suc_eq_insert_0: "{.. Suc n} = insert 0 (Suc ` {.. n})"
+lemma atMost_Suc_eq_insert_0: "{.. Suc n} = insert 0 (Suc ` {.. n})"
   unfolding lessThan_Suc_atMost[symmetric] lessThan_Suc_eq_insert_0[of "Suc n"] ..
 
 lemma UN_lessThan_UNIV: "(UN m::nat. lessThan m) = UNIV"
@@ -803,7 +803,7 @@
 
 lemma atLeast0_atMost_Suc_eq_insert_0:
   "{0..Suc n} = insert 0 (Suc ` {0..n})"
-  by (simp add: atLeast0AtMost Iic_Suc_eq_insert_0)
+  by (simp add: atLeast0AtMost atMost_Suc_eq_insert_0)
 
 
 subsubsection \<open>Intervals of nats with @{term Suc}\<close>
@@ -2408,6 +2408,16 @@
   "\<Prod>i\<le>n. t" \<rightleftharpoons> "CONST prod (\<lambda>i. t) {..n}"
   "\<Prod>i<n. t" \<rightleftharpoons> "CONST prod (\<lambda>i. t) {..<n}"
 
+lemma prod_atLeast1_atMost_eq:
+  "prod f {Suc 0..n} = (\<Prod>k<n. f (Suc k))"
+proof -
+  have "prod f {Suc 0..n} = prod f (Suc ` {..<n})"
+    by (simp add: image_Suc_lessThan)
+  also have "\<dots> = (\<Prod>k<n. f (Suc k))"
+    by (simp add: prod.reindex)
+  finally show ?thesis .
+qed
+
 lemma prod_int_plus_eq: "prod int {i..i+j} =  \<Prod>{int i..int (i+j)}"
   by (induct j) (auto simp add: atLeastAtMostSuc_conv atLeastAtMostPlus1_int_conv)
 
@@ -2441,7 +2451,7 @@
   "prod f {Suc m..<Suc n} = prod (%i. f(Suc i)){m..<n}"
 by (simp add:prod_shift_bounds_nat_ivl[where k="Suc 0", simplified])
 
-lemma prod_lessThan_Suc: "prod f {..<Suc n} = prod f {..<n} * f n"
+lemma prod_lessThan_Suc [simp]: "prod f {..<Suc n} = prod f {..<n} * f n"
   by (simp add: lessThan_Suc mult.commute)
 
 lemma prod_lessThan_Suc_shift:"(\<Prod>i<Suc n. f i) = f 0 * (\<Prod>i<n. f (Suc i))"
--- a/src/HOL/Topological_Spaces.thy	Sat Jun 02 22:57:44 2018 +0100
+++ b/src/HOL/Topological_Spaces.thy	Sun Jun 03 15:22:30 2018 +0100
@@ -1353,6 +1353,12 @@
 lemma LIMSEQ_Suc_iff: "(\<lambda>n. f (Suc n)) \<longlonglongrightarrow> l = f \<longlonglongrightarrow> l"
   by (blast intro: LIMSEQ_imp_Suc LIMSEQ_Suc)
 
+lemma LIMSEQ_lessThan_iff_atMost:
+  shows "(\<lambda>n. f {..<n}) \<longlonglongrightarrow> x \<longleftrightarrow> (\<lambda>n. f {..n}) \<longlonglongrightarrow> x"
+  apply (subst LIMSEQ_Suc_iff [symmetric])
+  apply (simp only: lessThan_Suc_atMost)
+  done
+
 lemma LIMSEQ_unique: "X \<longlonglongrightarrow> a \<Longrightarrow> X \<longlonglongrightarrow> b \<Longrightarrow> a = b"
   for a b :: "'a::t2_space"
   using trivial_limit_sequentially by (rule tendsto_unique)