Theory Misc_Tensor_Product

section Misc_Tensor_Product› -- Miscelleanous results missing from other theories›

theory Misc_Tensor_Product
  imports "HOL-Analysis.Elementary_Topology" "HOL-Analysis.Abstract_Topology"
    "HOL-Analysis.Abstract_Limits" "HOL-Analysis.Function_Topology" "HOL-Cardinals.Cardinals"
    "HOL-Analysis.Infinite_Sum" "HOL-Analysis.Harmonic_Numbers" Containers.Containers_Auxiliary
    Complex_Bounded_Operators.Extra_General
    Complex_Bounded_Operators.Extra_Vector_Spaces
    Complex_Bounded_Operators.Extra_Ordered_Fields
begin

unbundle lattice_syntax

lemma local_defE: "(x. x=y  P)  P" by metis
    ― ‹A helper lemma to introduce a local ``definition`` in the current goal when backwards reasoning.
        apply (rule local_defE[where x=‹stuff›])› will insert termx=stuff as a premise.
        This can be useful before using apply transfer› because it will introduce some 
        additional knowledge about the properties of termx into the transferred goal.›

lemma inv_prod_swap[simp]: inv prod.swap = prod.swap
  by (simp add: inv_unique_comp)

lemma filterlim_parametric[transfer_rule]: 
  includes lifting_syntax
  assumes [transfer_rule]: bi_unique S
  shows ((R ===> S) ===> rel_filter S ===> rel_filter R ===> (=)) filterlim filterlim
  using filtermap_parametric[transfer_rule] le_filter_parametric[transfer_rule] apply fail?
  unfolding filterlim_def
  by transfer_prover


definition rel_topology :: ('a  'b  bool)  ('a topology  'b topology  bool) where
  rel_topology R S T  (rel_fun (rel_set R) (=)) (openin S) (openin T)
  (U. openin S U  Domainp (rel_set R) U)  (U. openin T U  Rangep (rel_set R) U)

lemma rel_topology_eq[relator_eq]: rel_topology (=) = (=)
  unfolding rel_topology_def using openin_inject
  by (auto simp: rel_fun_eq rel_set_eq fun_eq_iff)

lemma Rangep_conversep[simp]: Rangep (R¯¯) = Domainp R
  by blast

lemma Domainp_conversep[simp]: Domainp (R¯¯) = Rangep R
  by blast

lemma conversep_rel_fun:
  includes lifting_syntax
  shows (T ===> U)¯¯ = (T¯¯) ===> (U¯¯)
  by (auto simp: rel_fun_def)

lemma rel_topology_conversep[simp]: rel_topology (R¯¯) = ((rel_topology R)¯¯)
  by (auto simp add: rel_topology_def[abs_def] simp flip: conversep_rel_fun[where U=(=), simplified])

lemma openin_parametric[transfer_rule]:
  includes lifting_syntax
  shows (rel_topology R ===> rel_set R ===> (=)) openin openin
  by (auto simp add: rel_fun_def rel_topology_def)

lemma topspace_parametric [transfer_rule]:
  includes lifting_syntax
  shows (rel_topology R ===> rel_set R) topspace topspace
proof -
  have *: ytopspace T'. R x y if rel_topology R T T' x  topspace T for x T T' and R :: 'q  'r  bool
  proof -
    from that obtain U where openin T U and x  U
      unfolding topspace_def
      by auto
    from openin T U
    have Domainp (rel_set R) U
      using rel_topology R T T' rel_topology_def by blast
    then obtain V where [transfer_rule]: rel_set R U V
      by blast
    with x  U obtain y where R x y and y  V
      by (meson rel_set_def)
    from rel_set R U V rel_topology R T T' openin T U
    have openin T' V
      by (simp add: rel_topology_def rel_fun_def)
    with y  V have y  topspace T'
      using openin_subset by auto
    with R x y show ytopspace T'. R x y
      by auto
  qed

  show ?thesis
    using *[where ?R.1=R]
    using *[where ?R.1=R¯¯]
    by (auto intro!: rel_setI)
qed

lemma [transfer_rule]:
  includes lifting_syntax
  assumes [transfer_rule]: bi_total S
  assumes [transfer_rule]: bi_unique S
  assumes [transfer_rule]: bi_total R
  assumes [transfer_rule]: bi_unique R
  shows (rel_topology R ===> rel_topology S ===> (R ===> S) ===> (=)) continuous_map continuous_map
  unfolding continuous_map_def Pi_def
  by transfer_prover


lemma limitin_closedin:
  assumes limitin T f c F
  assumes range f  S
  assumes closedin T S
  assumes ¬ trivial_limit F
  shows c  S
proof -
  from assms have T closure_of S = S
    by (simp add: closure_of_eq)
  moreover have c  T closure_of S
    using assms(1) _ assms(4) apply (rule limitin_closure_of)
    using range_subsetD[OF assms(2)] by auto
  ultimately show ?thesis
    by simp
qed


lemma closure_nhds_principal: a  closure A  inf (nhds a) (principal A)  bot
proof (rule iffI)
  show inf (nhds a) (principal A)  bot if a  closure A
  proof (cases a  A)
    case True
    thus ?thesis
      unfolding filter_eq_iff eventually_inf eventually_principal eventually_nhds by force
  next
    case False
    have "at a within A  bot"
      using False that by (subst at_within_eq_bot_iff) auto
    also have "at a within A = inf (nhds a) (principal A)"
      using False by (simp add: at_within_def)
    finally show ?thesis .
  qed
  show a  closure A if inf (nhds a) (principal A)  bot
    by (metis Diff_empty Diff_insert0 at_within_def closure_subset not_in_closure_trivial_limitI subsetD that)
qed


lemma limit_in_closure:
  assumes lim: (f  x) F
  assumes nt: F  bot
  assumes inA: F x in F. f x  A
  shows x  closure A
proof (rule Lim_in_closed_set[of _ _ F])
  show "F x in F. f x  closure A"
    using inA by eventually_elim (use closure_subset in blast)
qed (use assms in auto)

lemma filterlim_nhdsin_iff_limitin:
  l  topspace T  filterlim f (nhdsin T l) F  limitin T f l F
  unfolding limitin_def
proof safe
  fix U assume *: "l  topspace T" "filterlim f (nhdsin T l) F" "openin T U" "l  U"
  hence "eventually (λy. y  U) (nhdsin T l)"
    unfolding eventually_nhdsin by blast
  thus "eventually (λx. f x  U) F"
    using *(2) eventually_compose_filterlim by blast
next
  assume *: "l  topspace T" "U. openin T U  l  U  (F x in F. f x  U)"
  show "filterlim f (nhdsin T l) F"
    unfolding filterlim_def le_filter_def eventually_filtermap
  proof safe
    fix P :: "'a  bool"
    assume "eventually P (nhdsin T l)"
    then obtain U where U: "openin T U" "l  U" "xU. P x"
      using *(1) unfolding eventually_nhdsin by blast
    with * have "eventually (λx. f x  U) F"
      by blast
    thus "eventually (λx. P (f x)) F"
      by eventually_elim (use U in blast)
  qed
qed

lemma pullback_topology_bi_cont: 
  fixes g :: 'a  ('b  'c::topological_space)
    and f :: 'a  'a  'a and f' :: 'c  'c  'c
  assumes gf_f'g: a b i. g (f a b) i = f' (g a i) (g b i)
  assumes f'_cont: a' b'. (case_prod f'  f' a' b') (nhds a' ×F nhds b')
  defines T  pullback_topology UNIV g euclidean
  shows LIM (x,y) nhdsin T a ×F nhdsin T b. f x y :> nhdsin T (f a b)
proof -
  have topspace[simp]: topspace T = UNIV
    unfolding T_def topspace_pullback_topology by simp
  have openin: openin T U  (V. open V  U = g -` V) for U
    by (simp add: assms openin_pullback_topology)

  have 1: nhdsin T a = filtercomap g (nhds (g a))
    for a :: 'a
    by (auto simp add: filter_eq_iff eventually_filtercomap eventually_nhds eventually_nhdsin openin)

  have ((g  case_prod f)  g (f a b)) (nhdsin T a ×F nhdsin T b)
  proof (unfold tendsto_def, intro allI impI)
    fix S assume open S and gfS: g (f a b)  S
    obtain U where gf_PiE: g (f a b)  PiE UNIV U and openU: i. openin euclidean (U i)
      and finiteD: finite {i. U i  topspace euclidean} and US: PiE UNIV U  S
      using product_topology_open_contains_basis[OF open S[unfolded open_fun_def] gfS]
      by auto

    define D where D = {i. U i  UNIV}
    with finiteD have finite D
      by auto

    from openU have openU: open (U i) for i
      by auto

    have *: f' (g a i) (g b i)  U i for i
      by (metis PiE_mem gf_PiE iso_tuple_UNIV_I gf_f'g)

    have F x in nhds (g a i) ×F nhds (g b i). case_prod f' x  U i for i
      using tendsto_def[THEN iffD1, rule_format, OF f'_cont openU *, of i] by -

    then obtain Pa Pb where eventually (Pa i) (nhds (g a i)) and eventually (Pb i) (nhds (g b i))
      and PaPb_plus: (x y. Pa i x  Pb i y  f' x y  U i) for i
      unfolding eventually_prod_filter by (metis prod.simps(2))

    from i. eventually (Pa i) (nhds (g a i))
    obtain Ua where open (Ua i) and a_Ua: g a i  Ua i and Ua_Pa: Ua i  Collect (Pa i) for i
      unfolding eventually_nhds
      apply atomize_elim
      by (metis mem_Collect_eq subsetI)
    from i. eventually (Pb i) (nhds (g b i))
    obtain Ub where open (Ub i) and b_Ub: g b i  Ub i and Ub_Pb: Ub i  Collect (Pb i) for i
      unfolding eventually_nhds
      apply atomize_elim
      by (metis mem_Collect_eq subsetI)
    have UaUb_plus: x  Ua i  y  Ub i  f' x y  U i for i x y
      by (metis PaPb_plus Ua_Pa Ub_Pb mem_Collect_eq subsetD)

    define Ua' where Ua' i = (if iD then Ua i else UNIV) for i
    define Ub' where Ub' i = (if iD then Ub i else UNIV) for i

    have Ua'_UNIV: U i = UNIV  Ua' i = UNIV for i
      by (simp add: D_def Ua'_def)
    have Ub'_UNIV: U i = UNIV  Ub' i = UNIV for i
      by (simp add: D_def Ub'_def)
    have [simp]: open (Ua' i) for i
      by (simp add: Ua'_def open (Ua _))
    have [simp]: open (Ub' i) for i
      by (simp add: Ub'_def open (Ub _))
    have a_Ua': g a i  Ua' i for i
      by (simp add: Ua'_def a_Ua)
    have b_Ub': g b i  Ub' i for i
      by (simp add: Ub'_def b_Ub)
    have UaUb'_plus: a'  Ua' i  b'  Ub' i  f' a' b'  U i for i a' b'
      apply (cases i  D)
      using UaUb_plus by (auto simp add: Ua'_def  Ub'_def D_def)

    define Ua'' where Ua'' = Pi UNIV Ua'
    define Ub'' where Ub'' = Pi UNIV Ub'

    have open Ua''
      using finiteD Ua'_UNIV
      by (auto simp add: open_fun_def Ua''_def PiE_UNIV_domain
            openin_product_topology_alt D_def intro!: exI[where x=Ua'] intro: rev_finite_subset)
    have open Ub''
      using finiteD Ub'_UNIV
      by (auto simp add: open_fun_def Ub''_def PiE_UNIV_domain
            openin_product_topology_alt D_def intro!: exI[where x=Ub'] intro: rev_finite_subset)
    have a_Ua'': g a  Ua''
      by (simp add: Ua''_def a_Ua')
    have b_Ub'': g b  Ub''
      by (simp add: Ub''_def b_Ub')
    have UaUb''_plus: a'  Ua''  b'  Ub''  f' (a' i) (b' i)  U i for i a' b'
      using UaUb'_plus by (force simp add: Ua''_def  Ub''_def)

    define Ua''' where Ua''' = g -` Ua''
    define Ub''' where Ub''' = g -` Ub''
    have openin T Ua'''
      using open Ua'' by (auto simp: openin Ua'''_def)
    have openin T Ub'''
      using open Ub'' by (auto simp: openin Ub'''_def)
    have a_Ua'': a  Ua'''
      by (simp add: Ua'''_def a_Ua'')
    have b_Ub'': b  Ub'''
      by (simp add: Ub'''_def b_Ub'')
    have UaUb'''_plus: a  Ua'''  b  Ub'''  f' (g a i) (g b i)  U i for i a b
      by (simp add: Ua'''_def UaUb''_plus Ub'''_def)

    define Pa' where Pa' a  a  Ua''' for a
    define Pb' where Pb' b  b  Ub''' for b

    have Pa'_nhd: eventually Pa' (nhdsin T a)
      using openin T Ua'''
      by (auto simp add: Pa'_def eventually_nhdsin intro!: exI[of _ Ua'''] a_Ua'')
    have Pb'_nhd: eventually Pb' (nhdsin T b)
      using openin T Ub'''
      by (auto simp add: Pb'_def eventually_nhdsin intro!: exI[of _ Ub'''] b_Ub'')
    have Pa'Pb'_plus: (g  case_prod f) (a, b)  S if Pa' a Pb' b for a b
      using that UaUb'''_plus US
      by (auto simp add: Pa'_def Pb'_def PiE_UNIV_domain Pi_iff gf_f'g)

    show F x in nhdsin T a ×F nhdsin T b. (g  case_prod f) x  S
      using Pa'_nhd Pb'_nhd Pa'Pb'_plus
      unfolding eventually_prod_filter
      apply -
      apply (rule exI[of _ Pa'])
      apply (rule exI[of _ Pb'])
      by simp
  qed
  then show ?thesis
    unfolding 1 filterlim_filtercomap_iff by -
qed

definition has_sum_in T f A x  limitin T (sum f) x (finite_subsets_at_top A)


lemma has_sum_in_finite:
  assumes "finite F"
  assumes sum f F  topspace T
  shows "has_sum_in T f F (sum f F)"
  using assms
  by (simp add: finite_subsets_at_top_finite has_sum_in_def limitin_def eventually_principal)


definition summable_on_in T f A  (x. has_sum_in T f A x)

definition infsum_in T f A = (let L = Collect (has_sum_in T f A) in if card L = 1 then the_elem L else 0)
(* The reason why we return 0 also in the case that there are several solutions is to make sure infsum_in is parametric.
(See lemma 'infsum_in_parametric' below. *)

lemma hausdorff_OFCLASS_t2_space: OFCLASS('a::topological_space, t2_space_class) if Hausdorff_space (euclidean :: 'a topology)
proof intro_classes
  fix a b :: 'a
  assume a  b
  from that
  show U V. open U  open V  a  U  b  V  U  V = {}
    unfolding Hausdorff_space_def disjnt_def
    using a  b by auto
qed

lemma hausdorffI: 
  assumes x y. x  topspace T  y  topspace T  x  y  U V. openin T U  openin T V  x  U  y  V  U  V = {}
  shows Hausdorff_space T
  using assms by (auto simp: Hausdorff_space_def disjnt_def)

lemma hausdorff_euclidean[simp]: Hausdorff_space (euclidean :: _::t2_space topology)
  apply (rule hausdorffI)
  by (metis (mono_tags, lifting) hausdorff open_openin)

lemma has_sum_in_unique:
  assumes Hausdorff_space T
  assumes has_sum_in T f A l
  assumes has_sum_in T f A l'
  shows l = l'
  using assms(2,3)[unfolded has_sum_in_def] _ assms(1)
  apply (rule limitin_Hausdorff_unique)
  by simp

lemma infsum_in_def':
  assumes Hausdorff_space T
  shows infsum_in T f A = (if summable_on_in T f A then (THE s. has_sum_in T f A s) else 0)
proof (cases Collect (has_sum_in T f A) = {})
  case True
  then show ?thesis using True
    by (auto simp: infsum_in_def summable_on_in_def Let_def card_1_singleton_iff)
next
  case False
  then have summable_on_in T f A
    by (metis (no_types, lifting) empty_Collect_eq summable_on_in_def)
  from False Hausdorff_space T
  have card (Collect (has_sum_in T f A)) = 1
    by (metis (mono_tags, opaque_lifting) has_sum_in_unique is_singletonI' is_singleton_altdef mem_Collect_eq)
  then show ?thesis
    using summable_on_in T f A
    by (smt (verit, best) assms card_1_singletonE has_sum_in_unique infsum_in_def mem_Collect_eq singletonI the_elem_eq the_equality)
qed

lemma has_sum_in_infsum_in: 
  assumes Hausdorff_space T and summable: summable_on_in T f A
  shows has_sum_in T f A (infsum_in T f A)
  apply (simp add: infsum_in_def'[OF Hausdorff_space T] summable)
  apply (rule theI'[of has_sum_in T f A])
  using has_sum_in_unique[OF Hausdorff_space T, of f A] summable
  by (meson summable_on_in_def)


lemma infsum_in_finite:
  assumes "finite F"
  assumes Hausdorff_space T
  assumes sum f F  topspace T
  shows "infsum_in T f F = sum f F"
  using has_sum_in_finite[OF assms(1,3)]
  using assms(2) has_sum_in_infsum_in has_sum_in_unique summable_on_in_def by blast

lemma nhdsin_mono:
  assumes [simp]: x. openin T' x  openin T x
  assumes [simp]: topspace T = topspace T'
  shows nhdsin T a  nhdsin T' a
  unfolding nhdsin_def 
  by (auto intro!: INF_superset_mono)


lemma has_sum_in_cong: 
  assumes "x. xA  f x = g x"
  shows "has_sum_in T f A x  has_sum_in T g A x"
proof -
  have (F x in finite_subsets_at_top A. sum f x  U)  (F x in finite_subsets_at_top A. sum g x  U) for U
    apply (rule eventually_subst)
    apply (subst eventually_finite_subsets_at_top)
    by (metis (mono_tags, lifting) assms empty_subsetI finite.emptyI subset_eq sum.cong)
  then show ?thesis
    by (simp add: has_sum_in_def limitin_def)
qed

lemma infsum_in_eqI':
  fixes f g :: 'a  'b::comm_monoid_add
  assumes x. has_sum_in T f A x  has_sum_in T g B x
  shows infsum_in T f A = infsum_in T g B
  by (simp add: infsum_in_def assms[abs_def] summable_on_in_def)

lemma infsum_in_cong:
  assumes "x. xA  f x = g x"
  shows "infsum_in T f A = infsum_in T g A"
  using assms infsum_in_eqI' has_sum_in_cong by blast

lemma limitin_cong: "limitin T f c F  limitin T g c F" if "eventually (λx. f x = g x) F"
  by (smt (verit, best) eventually_elim2 limitin_transform_eventually that)

lemma has_sum_in_reindex:
  assumes inj_on h A
  shows has_sum_in T g (h ` A) x  has_sum_in T (g  h) A x
proof -
  have has_sum_in T g (h ` A) x  limitin T (sum g) x (finite_subsets_at_top (h ` A))
    by (simp add: has_sum_in_def)
  also have   limitin T (λF. sum g (h ` F)) x (finite_subsets_at_top A)
    apply (subst filtermap_image_finite_subsets_at_top[symmetric])
    by (simp_all add: assms eventually_filtermap limitin_def)
  also have   limitin T (sum (g  h)) x (finite_subsets_at_top A)
    apply (rule limitin_cong)
    apply (rule eventually_finite_subsets_at_top_weakI)
    apply (rule sum.reindex)
    using assms inj_on_subset by blast
  also have   has_sum_in T (g  h) A x
    by (simp add: has_sum_in_def)
  finally show ?thesis .
qed

lemma summable_on_in_reindex:
  assumes inj_on h A
  shows summable_on_in T g (h ` A)  summable_on_in T (g  h) A
  by (simp add: assms summable_on_in_def has_sum_in_reindex)

lemma infsum_in_reindex:
  assumes inj_on h A
  shows infsum_in T g (h ` A) = infsum_in T (g  h) A
  by (metis Collect_cong assms has_sum_in_reindex infsum_in_def)

lemma has_sum_in_reindex_bij_betw:
  assumes "bij_betw g A B"
  shows   "has_sum_in T (λx. f (g x)) A s  has_sum_in T f B s"
proof -
  have has_sum_in T (λx. f (g x)) A s  has_sum_in T f (g ` A) s
    by (metis (mono_tags, lifting) assms bij_betw_imp_inj_on has_sum_in_cong has_sum_in_reindex o_def)
  also have  = has_sum_in T f B s
    using assms bij_betw_imp_surj_on by blast
  finally show ?thesis .
qed


lemma has_sum_euclidean_iff: has_sum_in euclidean f A s  (f has_sum s) A
  by (simp add: has_sum_def has_sum_in_def)

lemma summable_on_euclidean_eq: summable_on_in euclidean f A  f summable_on A
  by (auto simp add: infsum_def infsum_in_def has_sum_euclidean_iff[abs_def] has_sum_def
      t2_space_class.Lim_def summable_on_def summable_on_in_def)

lemma infsum_euclidean_eq: infsum_in euclidean f A = infsum f A
  by (auto simp add: infsum_def infsum_in_def' summable_on_euclidean_eq
      has_sum_euclidean_iff[abs_def] has_sum_def t2_space_class.Lim_def)

lemma infsum_in_reindex_bij_betw:
  assumes "bij_betw g A B"
  shows   "infsum_in T (λx. f (g x)) A = infsum_in T f B"
proof -
  have infsum_in T (λx. f (g x)) A = infsum_in T f (g ` A)
    by (metis (mono_tags, lifting) assms bij_betw_imp_inj_on infsum_in_cong infsum_in_reindex o_def)
  also have  = infsum_in T f B
    using assms bij_betw_imp_surj_on by blast
  finally show ?thesis .
qed

lemma limitin_parametric[transfer_rule]:
  includes lifting_syntax
  assumes [transfer_rule]: bi_unique S
  shows (rel_topology S ===> (R ===> S) ===> S ===> rel_filter R ===> (⟷)) limitin limitin
proof (intro rel_funI, rename_tac T T' f f' l l' F F')
  fix T T' f f' l l' F F'
  assume [transfer_rule]: rel_topology S T T'
  assume [transfer_rule]: (R ===> S) f f'
  assume [transfer_rule]: S l l'
  assume [transfer_rule]: rel_filter R F F'

  have topspace: l  topspace T  l'  topspace T'
    by transfer_prover

  have open1: F x in F. f x  U
    if openin T U and l  U and lhs: (V. openin T' V  l'  V  (F x in F'. f' x  V))
    for U
  proof -
    from rel_topology S T T' openin T U
    obtain V where openin T' V and [transfer_rule]: rel_set S U V
      by (smt (verit, best) Domainp.cases rel_fun_def rel_topology_def)
    with S l l' have l'  V
      by (metis (no_types, lifting) assms bi_uniqueDr rel_setD1 that(2))
    with lhs openin T' V
    have F x in F'. f' x  V
      by auto
    then show F x in F. f x  U
      by transfer simp
  qed

  have open2: F x in F'. f' x  V
    if openin T' V and l'  V and lhs: (U. openin T U  l  U  (F x in F. f x  U))
    for V
  proof -
    from rel_topology S T T' openin T' V
    obtain U where openin T U and [transfer_rule]: rel_set S U V
      by (auto simp: rel_topology_def rel_fun_def)
    with S l l' have l  U
      by (metis (full_types) assms bi_unique_def rel_setD2 that(2))
    with lhs openin T U
    have F x in F. f x  U
      by auto
    then show F x in F'. f' x  V
      by transfer simp
  qed

  from topspace open1 open2
  show limitin T f l F = limitin T' f' l' F'
    unfolding limitin_def by auto
qed

lemma finite_subsets_at_top_parametric[transfer_rule]:
  includes lifting_syntax
  assumes [transfer_rule]: bi_unique R
  shows (rel_set R ===> rel_filter (rel_set R)) finite_subsets_at_top finite_subsets_at_top
proof (intro rel_funI)
  fix A B assume rel_set R A B
  from bi_unique R obtain f where Rf: R x (f x) if x  A for x
    by (metis (no_types, opaque_lifting) rel_set R A B rel_setD1)
  have inj_on f A
    by (metis (no_types, lifting) Rf assms bi_unique_def inj_onI)
  have B = f ` A
    by (metis (mono_tags, lifting) Rf rel_set R A B assms bi_uniqueDr bi_unique_rel_set_lemma image_cong)

  have RfX: rel_set R X (f ` X) if X  A for X
    apply (rule rel_setI)
    subgoal
      by (metis (no_types, lifting) Rf inj_on f A in_mono inj_on_image_mem_iff that)
    subgoal
      by (metis (no_types, lifting) Rf imageE subsetD that)
    done

  have Piff: (X. finite X  X  A  (Y. finite Y  X  Y  Y  A  P (f ` Y))) 
              (X. finite X  X  B  (Y. finite Y  X  Y  Y  B  P Y)) for P
  proof (rule iffI)
    assume X. finite X  X  A  (Y. finite Y  X  Y  Y  A  P (f ` Y))
    then obtain X where finite X and X  A and XP: finite Y  X  Y  Y  A  P (f ` Y) for Y
      by auto
    define X' where X' = f ` X
    have finite X'
      by (metis X'_def finite X finite_imageI)
    have X'  B
      by (smt (verit, best) Rf X'_def X  A rel_set R A B assms bi_uniqueDr image_subset_iff rel_setD1 subsetD)
    have P Y' if finite Y' and X'  Y' and Y'  B for Y'
    proof -
      define Y where Y = (f -` Y')  A
      have finite Y
        by (metis Y_def inj_on f A finite_vimage_IntI that(1))
      moreover have X  Y
        by (metis (no_types, lifting) X'_def Y_def X  A image_subset_iff_subset_vimage le_inf_iff that(2))
      moreover have Y  A
        by (metis (no_types, lifting) Y_def inf_le2)
      ultimately have P (f ` Y)
        by (rule XP)
      then show P Y'
        by (metis (no_types, lifting) Int_greatest Y_def B = f ` A dual_order.refl image_subset_iff_subset_vimage inf_le1 subset_antisym subset_image_iff that(3))
    qed
    then show X. finite X  X  B  (Y. finite Y  X  Y  Y  B  P Y)
      by (metis (no_types, opaque_lifting) X'  B finite X')
  next
    assume X. finite X  X  B  (Y. finite Y  X  Y  Y  B  P Y)
    then obtain X where finite X and X  B and XP: finite Y  X  Y  Y  B  P Y for Y
      by auto
    define X' where X' = (f -` X)  A
    have finite X'
      by (simp add: X'_def finite X inj_on f A finite_vimage_IntI)
    have X'  A
      by (simp add: X'_def)
    have P (f ` Y') if finite Y' and X'  Y' and Y'  A for Y'
    proof -
      define Y where Y = f ` Y'
      have finite Y
        by (metis Y_def finite_imageI that(1))
      moreover have X  Y
        using X'_def Y_def B = f ` A X  B that(2) by blast
      moreover have Y  B
        by (metis Y_def B = f ` A image_mono that(3))
      ultimately have P Y
        by (rule XP)
      then show P (f ` Y')
        by (smt (z3) Y_def B = f ` A imageE imageI subset_antisym subset_iff that(3) vimage_eq)
    qed
    then show X. finite X  X  A  (Y. finite Y  X  Y  Y  A  P (f ` Y))
      by (metis X'  A finite X')
  qed

  define Z where Z = filtermap (λM. (M, f`M)) (finite_subsets_at_top A)
  have F (x, y) in Z. rel_set R x y
    by (auto intro!: eventually_finite_subsets_at_top_weakI simp add: Z_def eventually_filtermap RfX)
  moreover have map_filter_on {(x, y). rel_set R x y} fst Z = finite_subsets_at_top A
    apply (rule filter_eq_iff[THEN iffD2])
    apply (subst eventually_map_filter_on)
    subgoal
      by (auto intro!: eventually_finite_subsets_at_top_weakI simp add: Z_def eventually_filtermap RfX)[1]
    subgoal
      by (auto simp add: Z_def eventually_filtermap eventually_finite_subsets_at_top RfX)
    done
  moreover have map_filter_on {(x, y). rel_set R x y} snd Z = finite_subsets_at_top B
    apply (rule filter_eq_iff[THEN iffD2])
    apply (subst eventually_map_filter_on)
    subgoal
      by (auto intro!: eventually_finite_subsets_at_top_weakI simp add: Z_def eventually_filtermap RfX)[1]
    subgoal
      by (simp add: Z_def eventually_filtermap eventually_finite_subsets_at_top RfX Piff)
    done
  ultimately show rel_filter (rel_set R) (finite_subsets_at_top A) (finite_subsets_at_top B)
    by (rule rel_filter.intros[where Z=Z])
qed

lemma sum_parametric'[transfer_rule]:
  includes lifting_syntax
  fixes R :: 'a  'b  bool and S :: 'c::comm_monoid_add  'd::comm_monoid_add  bool
  assumes [transfer_rule]: bi_unique R
  assumes [transfer_rule]: (S ===> S ===> S) (+) (+)
  assumes [transfer_rule]: S 0 0
  shows ((R ===> S) ===> rel_set R ===> S) sum sum
proof (intro rel_funI)
  fix A B f g assume rel_set R A B and (R ===> S) f g
  from bi_unique R obtain p where Rf: R x (p x) if x  A for x
    by (metis (no_types, opaque_lifting) rel_set R A B rel_setD1)
  have inj_on p A
    by (metis (no_types, lifting) Rf bi_unique R bi_unique_def inj_onI)
  have B = p ` A
    by (metis (mono_tags, lifting) Rf rel_set R A B bi_unique R bi_uniqueDr bi_unique_rel_set_lemma image_cong)

  define A_copy where A_copy = A

  have *: S (f x + sum f F) (g (p x) + sum g (p ` F))
    if [transfer_rule]: S (sum f F) (sum g (p ` F)) and [simp]: x  A for x F
    by (metis (no_types, opaque_lifting) Rf (R ===> S) f g assms(2) rel_fun_def that(1) that(2))
  have ind_step: S (sum f (insert x F)) (sum g (p ` insert x F)) 
    if S (sum f F) (sum g (p ` F)) x  A x  F finite F F  A for x F
  proof -
    have "sum g (p ` insert x F) = g (p x) + sum g (p ` F)"
      unfolding image_insert using that
      by (subst sum.insert) (use inj_onD[OF inj_on p A, of x] in auto)
    thus ?thesis
      using that * by simp
  qed

  have S (xA. f x) (xp ` A. g x) if A  A_copy
    using that
   apply (induction A rule:infinite_finite_induct)
    unfolding A_copy_def
    subgoal
      by (metis (no_types, lifting) inj_on p A assms(3) finite_image_iff inj_on_subset sum.infinite)
    using S 0 0 ind_step by auto
  hence S (xA. f x) (xp ` A. g x)
    by (simp add: A_copy_def)
  also have  = (xB. g x)
    by (metis (full_types) B = p ` A)
  finally show S (xA. f x) (xB. g x)
    by -
qed


lemma has_sum_in_parametric[transfer_rule]:
  includes lifting_syntax
  fixes R :: 'a  'b  bool and S :: 'c::comm_monoid_add  'd::comm_monoid_add  bool
  assumes [transfer_rule]: bi_unique R
  assumes [transfer_rule]: bi_unique S
  assumes [transfer_rule]: (S ===> S ===> S) (+) (+)
  assumes [transfer_rule]: S 0 0
  shows (rel_topology S ===> (R ===> S) ===> (rel_set R) ===> S ===> (=)) has_sum_in has_sum_in
proof -
  note sum_parametric'[transfer_rule]
  show ?thesis
    unfolding has_sum_in_def
    by transfer_prover
qed

lemma has_sum_in_topspace: has_sum_in T f A s  s  topspace T
  by (metis has_sum_in_def limitin_def)

lemma summable_on_in_parametric[transfer_rule]: 
  includes lifting_syntax
  fixes R :: 'a  'b  bool
  assumes [transfer_rule]: bi_unique R
  assumes [transfer_rule]: bi_unique S
  assumes [transfer_rule]: (S ===> S ===> S) (+) (+)
  assumes [transfer_rule]: S 0 0
  shows (rel_topology S ===> (R ===> S) ===> (rel_set R) ===> (=)) summable_on_in summable_on_in
proof (intro rel_funI)
  fix T T' assume [transfer_rule]: rel_topology S T T'
  fix f f' assume [transfer_rule]: (R ===> S) f f'
  fix A A' assume [transfer_rule]: rel_set R A A'

  define ExT ExT' where ExT P  (xCollect (Domainp S). P x) and ExT' P'  (xCollect (Rangep S). P' x) for P P'
  have [transfer_rule]: ((S ===> (⟷)) ===> (⟷)) ExT ExT'
    by (smt (z3) Domainp_iff ExT'_def ExT_def RangePI Rangep.cases mem_Collect_eq rel_fun_def)
  from rel_topology S T T' have top1: topspace T  Collect (Domainp S)
    unfolding rel_topology_def
    by (metis (no_types, lifting) Domainp_set mem_Collect_eq openin_topspace subsetI)
  from rel_topology S T T' have top2: topspace T'  Collect (Rangep S)
    unfolding rel_topology_def
    by (metis (no_types, lifting) RangePI Rangep.cases mem_Collect_eq openin_topspace rel_setD2 subsetI)

  have ExT (has_sum_in T f A) = ExT' (has_sum_in T' f' A')
    by transfer_prover
  with top1 top2 show summable_on_in T f A  summable_on_in T' f' A'
    by (metis ExT'_def ExT_def has_sum_in_topspace in_mono summable_on_in_def)
qed

lemma not_summable_infsum_in_0: ¬ summable_on_in T f A  infsum_in T f A = 0
  by (smt (verit, del_insts) Collect_empty_eq card_eq_0_iff infsum_in_def summable_on_in_def zero_neq_one)

lemma infsum_in_parametric[transfer_rule]: 
  includes lifting_syntax
  fixes R :: 'a  'b  bool
  assumes [transfer_rule]: bi_unique R
  assumes [transfer_rule]: bi_unique S
  assumes [transfer_rule]: (S ===> S ===> S) (+) (+)
  assumes [transfer_rule]: S 0 0
  shows (rel_topology S ===> (R ===> S) ===> (rel_set R) ===> S) infsum_in infsum_in
proof (intro rel_funI)
  fix T T' assume [transfer_rule]: rel_topology S T T'
  fix f f' assume [transfer_rule]: (R ===> S) f f'
  fix A A' assume [transfer_rule]: rel_set R A A'
  have S_has_sum: (S ===> (=)) (has_sum_in T f A) (has_sum_in T' f' A')
    by transfer_prover

  have sum_iff: summable_on_in T f A  summable_on_in T' f' A'
    by transfer_prover

  define L L' where L = Collect (has_sum_in T f A) and L' = Collect (has_sum_in T' f' A')

  have LT: L  topspace T
    by (metis (mono_tags, lifting) Ball_Collect L_def has_sum_in_topspace subset_iff)
  have TS: topspace T  Collect (Domainp S)
    by (metis (no_types, lifting) Ball_Collect Domainp_set rel_topology S T T' openin_topspace rel_topology_def)
  have LT': L'  topspace T'
    by (metis Ball_Collect L'_def has_sum_in_topspace subset_eq)
  have T'S: topspace T'  Collect (Rangep S)
    by (metis (mono_tags, opaque_lifting) Ball_Collect RangePI rel_topology S T T' rel_fun_def rel_setD2 topspace_parametric)
  have Sss': S s s'  has_sum_in T f A s  has_sum_in T' f' A' s' for s s'
    using S_has_sum
    by (metis (mono_tags, lifting) rel_funE)

  have rel_set S L L'
    by (smt (verit) Domainp.cases L'_def L_def Rangep.cases L  topspace T L'  topspace T' s' s. S s s'  has_sum_in T f A s = has_sum_in T' f' A' s' topspace T  Collect (Domainp S) topspace T'  Collect (Rangep S) in_mono mem_Collect_eq rel_setI)

  have cardLL': card L = 1  card L' = 1
    by (metis (no_types, lifting) rel_set S L L' assms(2) bi_unique_rel_set_lemma card_image)

  have S (infsum_in T f A) (infsum_in T' f' A') if card L  1
    using that cardLL' by (simp add: infsum_in_def L'_def L_def Let_def that S 0 0 flip: sum_iff)

  moreover have S (infsum_in T f A) (infsum_in T' f' A') if [simp]: card L = 1
  proof -
    have [simp]: card L' = 1
      using that cardLL' by simp
    have S (the_elem L) (the_elem L')
      using rel_set S L L'
      by (metis (no_types, opaque_lifting) card L' = 1 is_singleton_altdef is_singleton_the_elem rel_setD1 singleton_iff that)
    then show ?thesis
      by (simp add: infsum_in_def flip: L'_def L_def)
  qed

  ultimately show S (infsum_in T f A) (infsum_in T' f' A')
    by auto
qed

lemma infsum_parametric[transfer_rule]: 
  includes lifting_syntax
  assumes [transfer_rule]: bi_unique R
  shows ((R ===> (=)) ===> (rel_set R) ===> (=)) infsum infsum
  unfolding infsum_euclidean_eq[symmetric]
  by transfer_prover

lemma summable_on_transfer[transfer_rule]: 
  includes lifting_syntax
  assumes [transfer_rule]: bi_unique R
  shows ((R ===> (=)) ===> (rel_set R) ===> (=)) Infinite_Sum.summable_on Infinite_Sum.summable_on
  unfolding summable_on_euclidean_eq[symmetric]
  by transfer_prover

lemma abs_gbinomial: abs (a gchoose n) = (-1)^(n - nat (ceiling a)) * (a gchoose n)
proof -
  have (i=0..<n. abs (a - of_nat i)) = (- 1) ^ (n - nat (ceiling a)) * (i=0..<n. a - of_nat i)
  proof (induction n)
    case 0
    then show ?case
      by simp
  next
    case (Suc n)
    consider (geq) of_int n  a | (lt) of_int n < a
      by fastforce
    then show ?case
    proof cases
      case geq
      from geq have abs (a - of_int n) = - (a - of_int n)
        by simp
      moreover from geq have (Suc n - nat (ceiling a)) = (n - nat (ceiling a)) + 1
        by (metis Suc_diff_le Suc_eq_plus1 ceiling_le nat_le_iff)
      ultimately show ?thesis
        apply (simp add: Suc)
        by (metis (no_types, lifting) ¦a - of_int (int n)¦ = - (a - of_int (int n)) mult.assoc mult_minus_right of_int_of_nat_eq)
    next
      case lt
      from lt have abs (a - of_int n) = (a - of_int n)
        by simp
      moreover from lt have (Suc n - nat (ceiling a)) = (n - nat (ceiling a))
        by (smt (verit, ccfv_threshold) Suc_leI cancel_comm_monoid_add_class.diff_cancel diff_commute diff_diff_cancel diff_le_self less_ceiling_iff linorder_not_le order_less_le zless_nat_eq_int_zless)
      ultimately show ?thesis
        by (simp add: Suc)
    qed
  qed
  then show ?thesis
    by (simp add: gbinomial_prod_rev abs_prod)
qed

lemma gbinomial_sum_lower_abs: 
  fixes a :: 'a::{floor_ceiling}
  defines a'  nat (ceiling a)
  assumes of_nat m  a-1
  shows "(km. abs (a gchoose k)) = 
                 (-1)^a' * ((-1) ^ m * (a - 1 gchoose m)) 
               - (-1)^a' * of_bool (a'>0) * ((-1) ^ (a'-1) * (a-1 gchoose (a'-1)))
               + (k<a'. abs (a gchoose k))"
proof -
  from assms
  have a'  Suc m
    using ceiling_mono by force

  have (km. abs (a gchoose k)) = (k=a'..m. abs (a gchoose k)) + (k<a'. abs (a gchoose k))
    apply (subst asm_rl[of {..m} = {a'..m}  {..<a'}])
    using a'  Suc m apply auto[1]
    apply (subst sum.union_disjoint)
    by auto
  also have  = (k=a'..m. (-1)^(k-a') * (a gchoose k)) + (k<a'. abs (a gchoose k))
    apply (rule arg_cong[where f=λx. x + _])
    apply (rule sum.cong[OF refl])
    apply (subst abs_gbinomial)
    using a'_def by blast
  also have  = (k=a'..m. (-1)^k * (-1)^a' * (a gchoose k)) + (k<a'. abs (a gchoose k))
    apply (rule arg_cong[where f=λx. x + _])
    apply (rule sum.cong[OF refl])
    by (simp add: power_diff_conv_inverse)
  also have  = (-1)^a' * (k=a'..m. (a gchoose k) * (-1)^k) + (k<a'. abs (a gchoose k))
    by (auto intro: sum.cong simp: sum_distrib_left)
  also have  = (-1)^a' * (km. (a gchoose k) * (-1)^k) - (-1)^a' * (k<a'. (a gchoose k) * (-1)^k) + (k<a'. abs (a gchoose k))
    apply (subst asm_rl[of {..m} = {..<a'}  {a'..m}])
    using a'  Suc m apply auto[1]
    apply (subst sum.union_disjoint)
    by (auto simp: distrib_left)
  also have  = (-1)^a' * ((- 1) ^ m * (a - 1 gchoose m)) - (-1)^a' * (k<a'. (a gchoose k) * (-1)^k) + (k<a'. abs (a gchoose k))
    apply (subst gbinomial_sum_lower_neg)
    by simp
  also have  = (-1)^a' * ((-1) ^ m * (a - 1 gchoose m)) - (-1)^a' 
               * of_bool (a'>0) * ((-1) ^ (a'-1) * (a-1 gchoose (a'-1)))
               + (k<a'. abs (a gchoose k))
    apply (cases a' = 0)
    subgoal
      by simp
    subgoal
      by (subst asm_rl[of {..<a'} = {..a'-1}]) (auto simp: gbinomial_sum_lower_neg)
    done
  finally show ?thesis
    by -
qed

lemma abs_gbinomial_leq1:
  fixes a :: 'a :: {linordered_field}
  assumes abs a  1
  shows abs (a gchoose b)  1
proof -
  have *: -1  a a  1
    using abs_le_D2 assms minus_le_iff abs_le_iff assms by auto
  have abs (a gchoose b) = abs ((i = 0..<b. a - of_nat i) / fact b)
    by (simp add: gbinomial_prod_rev)
  also have  = abs ((i=0..<b. a - of_nat i)) / fact b
    apply (subst abs_divide)
    by simp
  also have  = (i=0..<b. abs (a - of_nat i)) / fact b
    apply (subst abs_prod) by simp
  also have   (i=0..<b. of_nat (Suc i)) / fact b
  proof (intro divide_right_mono prod_mono conjI)
    fix i assume "i  {0..<b}"
    have "¦a - of_nat i¦  ¦a¦ + ¦of_nat i¦"
      by linarith
    also have "¦a¦  1"
      by fact
    finally show "¦a - of_nat i¦  of_nat (Suc i)"
      by simp
  qed auto
  also have  = fact b / fact b
    by (subst (2) fact_prod_Suc) auto
  also have  = 1
    by simp
  finally show ?thesis
    by -
qed

lemma gbinomial_summable_abs:
  fixes a :: real
  assumes a  0 and a  1
  shows summable (λn. abs (a gchoose n))
proof -
  define a' where a' = nat (ceiling a)
  have a': a' = 0  a' = 1
    by (metis One_nat_def a'_def assms(2) ceiling_le_one less_one nat_1 nat_mono order_le_less)
  have aux1: abs x  x'  abs y  y'  abs z  z'  x - y + z  x' + y' + z' for x y z x' y' z' :: real
    by auto
  have (in. ¦a gchoose i¦) = (- 1) ^ a' * ((- 1) ^ n * (a - 1 gchoose n)) -
    (- 1) ^ a' * of_bool (0 < a') * ((- 1) ^ (a' - 1) * (a - 1 gchoose (a' - 1))) +
    (k<a'. ¦a gchoose k¦) for n
    unfolding a'_def  by (rule gbinomial_sum_lower_abs) (use assms in auto)
  also have n  1 + 1 + 1 for n
    by (rule aux1) (use a' in auto simp add: abs_mult abs_gbinomial_leq1 assms)
  also have  = 3
    by simp
  finally show ?thesis
    by (meson abs_ge_zero bounded_imp_summable)
qed

lemma summable_tendsto_times_n:
  fixes f :: nat  real
  assumes pos: n. f n  0
  assumes dec: decseq (λn. (n+M) * f (n + M))
  assumes sum: summable f
  shows (λn. n * f n)  0
proof (rule ccontr)
  assume lim_not_0: ¬ (λn. n * f n)  0
  obtain B where (λn. (n+M) * f (n+M))  B and nfB': (n+M) * f (n+M)  B for n
    apply (rule decseq_convergent[where B=0, OF dec])
    using pos that by auto
  then have lim_B: (λn. n * f n)  B
    by - (rule LIMSEQ_offset)
  have B  0
    apply (subgoal_tac n. n * f n  0)
    using Lim_bounded2 lim_B apply blast
    by (simp add: pos)
  moreover have B  0
    using lim_B lim_not_0 by blast
  ultimately have B > 0
    by linarith

  have ge: f n  B / n if n  M for n
    using nfB'[of n-M] that B > 0  by (auto simp: divide_simps mult_ac)

  have summable (λn. B / n)
    by (rule summable_comparison_test'[where N=M]) (use sum B > 0 ge in auto)

  moreover have ¬ summable (λn. B / n)
  proof (rule ccontr)
    define C where C = (n. 1 / real n)
    assume ¬ ¬ summable (λn. B / real n)
    then have summable (λn. inverse B * (B / real n))
      using summable_mult by blast
    then have summable (λn. 1 / real n)
      using B  0 by auto
    then have (n=1..m. 1 / real n)  C for m
      unfolding C_def by (rule sum_le_suminf) auto
    then have harm m  C for m
      by (simp add: harm_def inverse_eq_divide)
    then have harm (nat (ceiling (exp C)))  C
      by -
    then have ln (real (nat (ceiling (exp C))) + 1)  C
      by (smt (verit, best) ln_le_harm)
    then show False
      by (smt (z3) exp_ln ln_ge_iff of_nat_0_le_iff real_nat_ceiling_ge)
  qed

  ultimately show False
    by simp
qed
  


lemma gbinomial_tendsto_0:
  fixes a :: real
  assumes a > -1
  shows (λn. (a gchoose n))  0
proof -
  have thesis1: (λn. (a gchoose n))  0 if a  0 for a :: real
  proof -
    define m where m = nat (floor a)
    have m: a  real m a  real m + 1
      by (simp_all add: m_def that)
    show ?thesis
    proof (insert m, induction m arbitrary: a)
      case 0
      then have *: a  0 a  1
        using assms by auto
      show ?case
        using gbinomial_summable_abs[OF *]
        using summable_LIMSEQ_zero tendsto_rabs_zero_iff by blast
    next
      case (Suc m)
      have 1: (λn. (a-1 gchoose n))  0
        by (rule Suc.IH) (use Suc.prems in auto)
      then have (λn. (a-1 gchoose Suc n))  0
        using filterlim_sequentially_Suc by blast
      with 1 have (λn. (a-1 gchoose n) + (a-1 gchoose Suc n))  0
        by (simp add: tendsto_add_zero)
      then have (λn. (a gchoose Suc n))  0
        using gbinomial_Suc_Suc[of a-1] by simp
      then show ?case
        using filterlim_sequentially_Suc by blast
    qed
  qed

  have thesis2: (λn. (a gchoose n))  0 if a > -1 a  0
  proof -
    have decseq: decseq (λn. abs (a gchoose n))
    proof (rule decseq_SucI)
      fix n
      have ¦a gchoose Suc n¦ = ¦a gchoose n¦ * (¦a - real n¦ / (1 + n))
        unfolding gbinomial_prod_rev by (simp add: abs_mult) 
      also have   ¦a gchoose n¦
        apply (rule mult_left_le)
        using assms that(2) by auto
      finally show ¦a gchoose Suc n¦  ¦a gchoose n¦
        by -
    qed
    have abs_a1: abs (a+1) = a+1
      using assms by auto

    have 0  ¦a + 1 gchoose n¦ for n
      by simp
    moreover have decseq (λn. (n+1) * abs (a+1 gchoose (n+1)))
      using decseq apply (simp add: gbinomial_rec abs_mult)
      by (smt (verit, best) decseq_def mult.commute mult_left_mono)
    moreover have summable (λn. abs (a+1 gchoose n))
      apply (rule gbinomial_summable_abs)
      using that by auto
    ultimately have (λn. n * abs (a+1 gchoose n))  0
      by (rule summable_tendsto_times_n)
    then have (λn. Suc n * abs (a+1 gchoose Suc n))  0
      by (rule_tac LIMSEQ_ignore_initial_segment[where k=1 and a=0, simplified])
    then have (λn. abs (Suc n * (a+1 gchoose Suc n)))  0
      by (simp add: abs_mult)
    then have (λn. (a+1) * abs (a gchoose n))  0
      apply (subst (asm) gbinomial_absorption)
      by (simp add: abs_mult abs_a1)
    then have (λn. abs (a gchoose n))  0
      using that(1) by force
    then show (λn. (a gchoose n))  0
      by (rule tendsto_rabs_zero_cancel)
  qed

  from thesis1 thesis2 assms show ?thesis
    using linorder_linear by blast
qed


(* lemma gbinomial_minus1[simp]: ‹(-1 gchoose n) = (case n of 0 ⇒ 1 | _ ⇒ -1)›
  apply (cases n)
   apply auto
  unfolding gbinomial_prod_rev
  apply auto
  by auto *)

lemma gbinomial_abs_sum:
  fixes a :: real
  assumes a > 0 and a  1
  shows (λn. abs (a gchoose n)) sums 2
proof -
  define a' where a' = nat (ceiling a)
  have a' = 1
    using a'_def assms(1) assms(2) by linarith
  have lim: (λn. (a - 1 gchoose n))  0
    by (simp add: assms(1) gbinomial_tendsto_0)
  have (kn. abs (a gchoose k)) = (- 1) ^ a' * ((- 1) ^ n * (a - 1 gchoose n)) -
    (- 1) ^ a' * of_bool (0 < a') * ((- 1) ^ (a'-1) * (a - 1 gchoose (a' - 1))) +
    (k<a'. ¦a gchoose k¦) for n
    unfolding a'_def
    apply (rule gbinomial_sum_lower_abs)
    using assms(2) by linarith
  also have n = 2 - (- 1) ^ n * (a - 1 gchoose n) for n
    using assms
    by (auto simp add: a' = 1)
  finally have (kn. abs (a gchoose k)) = 2 - (- 1) ^ n * (a - 1 gchoose n) for n
    by -
  moreover have (λn. 2 - (- 1) ^ n * (a - 1 gchoose n))  2
  proof -
    have (λn. ((-1) ^ n * (a-1 gchoose n)))  0
      by (rule tendsto_rabs_zero_cancel) (use lim in simp add: abs_mult tendsto_rabs_zero_iff)
    then have (λn. 2 - (- 1) ^ n * (a - 1 gchoose n))  2 - 0
      by (rule tendsto_diff[rotated]) simp
    then show ?thesis
      by simp
  qed
  ultimately have (λn. kn. abs (a gchoose k))  2
    by auto
  then show ?thesis
    using sums_def_le by blast
qed

lemma sums_has_sum:
  fixes s :: 'a :: banach
  assumes sums: f sums s
  assumes abs_sum: summable (λn. norm (f n))
  shows (f has_sum s) UNIV
proof (rule has_sumI_metric)
  fix e :: real assume 0 < e
  define e' where e' = e/2
  then have e' > 0
    using 0 < e half_gt_zero by blast
  from suminf_exist_split[where r=e', OF 0<e' abs_sum]
  obtain N where norm (i. norm (f (i + N))) < e'
    by auto
  then have N: (i. norm (f (i + N))) < e'
    by auto
  then have N': norm (i. f (i + N)) < e'
    apply (rule dual_order.strict_trans2)
    by (auto intro!: summable_norm summable_iff_shift[THEN iffD2] abs_sum)

  define X where X = {..<N}
  then have finite X
    by auto
  moreover have dist (sum f Y) s < e if finite Y and X  Y for Y
  proof -
    have dist (sum f Y) s = norm (s - sum f {..<N} - sum f (Y-{..<N}))
      by (metis X_def diff_diff_eq2 dist_norm norm_minus_commute sum.subset_diff that(1) that(2))
    also have   norm (s - sum f {..<N}) + norm (sum f (Y-{..<N}))
      using norm_triangle_ineq4 by blast
    also have  = norm (i. f (i + N)) + norm (sum f (Y-{..<N}))
      apply (subst suminf_minus_initial_segment)
      using sums sums_summable apply blast
      using sums sums_unique by blast
    also have  < e' + norm (sum f (Y-{..<N}))
      using N' by simp
    also have   e' + norm (iY-{..<N}. norm (f i))
      apply (rule add_left_mono)
      by (smt (verit, best) real_norm_def sum_norm_le)
    also have   e' + (iY-{..<N}. norm (f i))
      apply (rule add_left_mono)
      by (simp add: sum_nonneg)
    also have "(iY-{..<N}. norm (f i)) = (i|i+NY. norm (f (i + N)))"
      by (rule sum.reindex_bij_witness[of _ "λi. i + N" "λi. i - N"]) auto
    also have e' +   e' + (i. norm (f (i + N)))
      by (auto intro!: add_left_mono sum_le_suminf summable_iff_shift[THEN iffD2] abs_sum finite_inverse_image finite Y)
    also have   e' + e'
      using N by simp
    also have  = e
      by (simp add: e'_def)
    finally show ?thesis
      by -
  qed
  ultimately show X. finite X  X  UNIV  (Y. finite Y  X  Y  Y  UNIV  dist (sum f Y) s < e)
    by auto
qed

lemma sums_has_sum_pos:
  fixes s :: real
  assumes f sums s
  assumes n. f n  0
  shows (f has_sum s) UNIV
  apply (rule sums_has_sum)
  apply (simp add: assms(1))
  using assms(1) assms(2) summable_def by auto

lemma gbinomial_abs_has_sum:
  fixes a :: real
  assumes a > 0 and a  1
  shows ((λn. abs (a gchoose n)) has_sum 2) UNIV
  apply (rule sums_has_sum_pos)
   apply (rule gbinomial_abs_sum)
  using assms by auto

lemma gbinomial_abs_has_sum_1:
  fixes a :: real
  assumes a > 0 and a  1
  shows ((λn. abs (a gchoose n)) has_sum 1) (UNIV-{0})
proof -
  have ((λn. abs (a gchoose n)) has_sum 2-(n{0}. abs (a gchoose n))) (UNIV-{0})
    apply (rule has_sum_Diff)
      apply (rule gbinomial_abs_has_sum)
    using assms apply auto[2]
     apply (rule has_sum_finite)
    by auto
  then show ?thesis
    by simp
qed

lemma gbinomial_abs_summable:
  fixes a :: real
  assumes a > 0 and a  1
  shows (λn. (a gchoose n)) abs_summable_on UNIV
  using assms by (auto intro!: has_sum_imp_summable gbinomial_abs_has_sum)

lemma gbinomial_abs_summable_1:
  fixes a :: real
  assumes a > 0 and a  1
  shows (λn. (a gchoose n)) abs_summable_on UNIV-{0}
  using assms by (auto intro!: has_sum_imp_summable gbinomial_abs_has_sum_1)

lemma has_sum_singleton[simp]: (f has_sum y) {x}  f x = y for y :: 'a :: {comm_monoid_add, t2_space}
  using has_sum_finite[of {x}] infsumI[of f "{x}" y] by auto


lemma has_sum_sums: f sums s if (f has_sum s) UNIV
proof -
  have (λn. sum f {..<n})  s
  proof (unfold tendsto_def, intro allI impI)
    fix S assume open S and s  S
    with (f has_sum s) UNIV
    have F F in finite_subsets_at_top UNIV. sum f F  S
      using has_sum_def tendsto_def by blast
    then
    show F x in sequentially. sum f {..<x}  S
      using eventually_compose_filterlim filterlim_lessThan_at_top by blast
  qed
  then show ?thesis
    by (simp add: sums_def)
qed

lemma The_eqI1:
  assumes x y. F x  F y  x = y
  assumes z. F z
  assumes x. F x  P x = Q x
  shows P (The F) = Q (The F)
  by (metis assms(1) assms(2) assms(3) theI)

lemma summable_on_uminus[intro!]: 
  fixes f :: 'a  'b :: real_normed_vector (* Can probably be shown for a much wider type class. *)
  assumes f summable_on A
  shows (λi. - f i) summable_on A
  apply (subst asm_rl[of (λi. - f i) = (λi. (-1) *R f i)])
   apply simp
  using assms by (rule summable_on_scaleR_right)

lemma summable_on_diff:
  fixes f g :: "'a  'b::real_normed_vector"  (* Can probably be shown for a much wider type class. *)
  assumes f summable_on A
  assumes g summable_on A
  shows (λx. f x - g x) summable_on A
  using summable_on_add[where f=f and g=λx. - g x] summable_on_uminus[where f=g]
  using assms by auto


lemma gbinomial_1: (1 gchoose n) = of_bool (n1)
proof -
  consider (0) n=0 | (1) n=1 | (bigger) m where n=Suc (Suc m)
    by (metis One_nat_def not0_implies_Suc)
  then show ?thesis
  proof cases
    case 0
    then show ?thesis
      by simp
  next
    case 1
    then show ?thesis
      by simp
  next
    case bigger
    then show ?thesis
      using gbinomial_rec[where a=0 and k=Suc m]
      by simp
  qed
qed



lemma gbinomial_a_Suc_n:
  (a gchoose Suc n) = (a gchoose n) * (a-n) / Suc n
  by (simp add: gbinomial_prod_rev)

lemma has_sum_in_0[simp]:
  assumes 0  topspace T
  assumes x. xA  f x = 0
  shows has_sum_in T f A 0
proof -
  have has_sum_in T (λ_. 0) A 0
    using assms
    by (simp add: has_sum_in_def sum.neutral_const[abs_def])
  then show ?thesis
    apply (rule has_sum_in_cong[THEN iffD2, rotated])
    using assms by simp
qed

lemma summable_on_in_cong:
  assumes "x. xA  f x = g x"
  shows "summable_on_in T f A  summable_on_in T g A"
  by (simp add: summable_on_in_def has_sum_in_cong[OF assms])

lemma infsum_in_0:
  assumes Hausdorff_space T and 0  topspace T
  assumes x. xM  f x = 0
  shows infsum_in T f M = 0
proof -
  have has_sum_in T f M 0
    using assms
    by (auto intro!: has_sum_in_0 Hausdorff_imp_t1_space)
  then show ?thesis
    by (meson assms(1) has_sum_in_infsum_in has_sum_in_unique not_summable_infsum_in_0)
qed

lemma summable_on_in_finite:
  fixes f :: 'a  'b::{comm_monoid_add,topological_space}
  assumes "finite F"
  assumes sum f F  topspace T
  shows "summable_on_in T f F"
  using assms summable_on_in_def has_sum_in_finite by blast

lemma has_sum_diff:
  fixes f g :: "'a  'b::{topological_ab_group_add}"
  assumes (f has_sum a) A
  assumes (g has_sum b) A
  shows ((λx. f x - g x) has_sum (a - b)) A
  by (auto intro!: has_sum_add has_sum_uminus[THEN iffD2] assms simp add: simp flip: add_uminus_conv_diff)

lemma has_sum_of_real:
  fixes f :: "'a  real"
  assumes (f has_sum a) A
  shows ((λx. of_real (f x)) has_sum (of_real a :: 'b::{real_algebra_1,real_normed_vector})) A
  apply (rule has_sum_comm_additive[unfolded o_def, where f=of_real])
  by (auto intro!: additive.intro assms tendsto_of_real)

lemma summable_on_cdivide:
  fixes f :: "'a  'b :: {t2_space, topological_semigroup_mult, division_ring}"
  assumes f summable_on A
  shows "(λx. f x / c) summable_on A"
  apply (subst division_ring_class.divide_inverse)
  using assms summable_on_cmult_left by blast

lemma has_sum_in_weaker_topology:
  assumes continuous_map T U (λf. f)
  assumes has_sum_in T f A l
  shows has_sum_in U f A l
  using continuous_map_limit[OF assms(1)]
  using assms(2)
  by (auto simp: has_sum_in_def o_def)

lemma summable_on_in_weaker_topology:
  assumes continuous_map T U (λf. f)
  assumes summable_on_in T f A
  shows summable_on_in U f A
  by (meson assms(1,2) has_sum_in_weaker_topology summable_on_in_def)

lemma norm_abs[simp]: norm (abs x) = norm x for x :: 'a :: {idom_abs_sgn, real_normed_div_algebra}
proof -
  have norm x = norm (sgn x * abs x)
    by (simp add: sgn_mult_abs)
  also have  = norm ¦x¦
    by (simp add: norm_mult norm_sgn)
  finally show ?thesis
    by simp
qed

(* Strengthening of  *) thm abs_summable_product (* with narrower typeclass *)
lemma abs_summable_product:
  fixes x :: "'a  'b::real_normed_div_algebra"
  assumes x2_sum: "(λi. (x i)2) abs_summable_on A"
    and y2_sum: "(λi. (y i)2) abs_summable_on A"
  shows "(λi. x i * y i) abs_summable_on A"
proof (rule nonneg_bdd_above_summable_on)
  show 0  norm (x i * y i) for i
    by simp
  show bdd_above (sum (λi. norm (x i * y i)) ` {F. F  A  finite F})
  proof (rule bdd_aboveI2, rename_tac F)
    fix F assume F  {F. F  A  finite F}
    then have "finite F" and "F  A"
      by auto

    have "norm (x i * y i)  norm (x i * x i) + norm (y i * y i)" for i
      unfolding norm_mult
      by (smt mult_left_mono mult_nonneg_nonneg mult_right_mono norm_ge_zero)
    hence "(iF. norm (x i * y i))  (iF. norm ((x i)2) + norm ((y i)2))"
      using [[simp_trace]]
      by (simp add: power2_eq_square sum_mono)
    also have " = (iF. norm ((x i)2)) + (iF. norm ((y i)2))"
      by (simp add: sum.distrib)
    also have "  (iA. norm ((x i)2)) + (iA. norm ((y i)2))"
      using x2_sum y2_sum finite F F  A by (auto intro!: finite_sum_le_infsum add_mono)
    finally show (xaF. norm (x xa * y xa))  (iA. norm ((x i)2)) + (iA. norm ((y i)2))
      by simp
  qed
qed

lemma Cauchy_Schwarz_ineq_infsum:
  fixes x :: "'a  'b::{real_normed_div_algebra}"
  assumes x2_sum: "(λi. (x i)2) abs_summable_on A"
    and y2_sum: "(λi. (y i)2) abs_summable_on A"
  shows (iA. norm (x i * y i))  sqrt (iA. (norm (x i))2) * sqrt (iA. (norm (y i))2)
proof -
  (* have ‹(norm (∑i∈A. x i * y i)) ≤ (∑i∈A. norm (x i * y i))›
    by (simp add: Misc_Tensor_Product.abs_summable_product assms(2) norm_infsum_bound x2_sum)
  also *) have (iA. norm (x i * y i))  sqrt (iA. (norm (x i))2) * sqrt (iA. (norm (y i))2)
  proof (rule infsum_le_finite_sums)
    show (λi. x i * y i) abs_summable_on A
      using Misc_Tensor_Product.abs_summable_product x2_sum y2_sum by blast
    fix F assume finite F and F  A


    have sum1: (λi. (norm (x i))2) summable_on A
      by (metis (mono_tags, lifting) norm_power summable_on_cong x2_sum)
    have sum2: (λi. (norm (y i))2) summable_on A
      by (metis (no_types, lifting) norm_power summable_on_cong y2_sum)

    have (iF. norm (x i * y i))2 = (iF. norm (x i) * norm (y i))2
      by (simp add: norm_mult)
    also have   (iF. (norm (x i))2) * (iF. (norm (y i))2)
      using Cauchy_Schwarz_ineq_sum by fastforce
    also have   (iA. (norm (x i))2) * (iF. (norm (y i))2)
      using sum1 finite F F  A 
      by (auto intro!: mult_right_mono finite_sum_le_infsum sum_nonneg)
    also have   (iA. (norm (x i))2) * (iA. (norm (y i))2)
      using sum2 finite F F  A 
      by (auto intro!: mult_left_mono finite_sum_le_infsum infsum_nonneg)
    also have  = (sqrt (iA. (norm (x i))2) * sqrt (iA. (norm (y i))2))2
      by (smt (verit, best) calculation real_sqrt_mult real_sqrt_pow2 zero_le_power2)
  finally show (iF. norm (x i * y i))  sqrt (iA. (norm (x i))2) * sqrt (iA. (norm (y i))2)
    apply (rule power2_le_imp_le)
    by (auto intro!: mult_nonneg_nonneg infsum_nonneg)
  qed
  then show ?thesis
    by -
qed

lemma continuous_map_pullback_both:
  assumes cont: continuous_map T1 T2 g'
  assumes g'g: x. f1 x  topspace T1  x  A1  g' (f1 x) = f2 (g x)
  assumes top1: f1 -` topspace T1  A1  g -` A2
  shows continuous_map (pullback_topology A1 f1 T1) (pullback_topology A2 f2 T2) g
proof -
  from cont
  have continuous_map (pullback_topology A1 f1 T1) T2 (g'  f1)
    by (rule continuous_map_pullback)
  then have continuous_map (pullback_topology A1 f1 T1) T2 (f2  g)
    apply (rule continuous_map_eq)
    by (simp add: g'g topspace_pullback_topology)
  then show ?thesis
    apply (rule continuous_map_pullback')
    by (simp add: top1 topspace_pullback_topology)
qed

lemma onorm_case_prod_plus_leq: onorm (case_prod plus :: _  'a::real_normed_vector)  sqrt 2
  apply (rule onorm_bound)
  using norm_plus_leq_norm_prod by auto

lemma bounded_linear_case_prod_plus[simp]: bounded_linear (case_prod plus)
  apply (rule bounded_linear_intro[where K=sqrt 2])
  by (auto simp add: scaleR_right_distrib norm_plus_leq_norm_prod mult.commute)

lemma pullback_topology_twice:
  assumes (f -` B)  A = C
  shows pullback_topology A f (pullback_topology B g T) = pullback_topology C (g o f) T
proof -
  have aux: S = A  S = B if A = B for A B S :: 'z
    using that by simp
  have *: (V. (openin T U  V = g -` U  B)  S = f -` V  A) = (openin T U  S = (g  f) -` U  C) for S U
    apply (cases openin T U)
    using assms
    by (auto intro!: aux simp: vimage_comp)
  then have *: (V. (U. openin T U  V = g -` U  B)  S = f -` V  A) = (U. openin T U  S = (g  f) -` U  C) for S
    by metis
  show ?thesis
    by (auto intro!: * simp: topology_eq openin_pullback_topology)
qed

lemma pullback_topology_homeo_cong:
  assumes homeomorphic_map T S g
  assumes range f  topspace T
  shows pullback_topology A f T = pullback_topology A (g o f) S
proof -
  have Us. openin S Us  f -` Ut  A = (g  f) -` Us  A if openin T Ut for Ut
    apply (rule exI[of _ g ` Ut])
    using assms that apply auto
    using homeomorphic_map_openness_eq apply blast
    by (smt (verit, best) homeomorphic_map_maps homeomorphic_maps_map openin_subset rangeI subsetD)
  moreover have Ut. openin T Ut  (g  f) -` Us  A = f -` Ut  A if openin S Us for Us
    apply (rule exI[of _ (g -` Us)  topspace T])
    using assms that apply auto
    by (meson continuous_map_open homeomorphic_imp_continuous_map)
  ultimately show ?thesis
    by (auto simp: topology_eq openin_pullback_topology)
qed

definition opensets_in T = Collect (openin T)
  ― ‹This behaves more nicely with the @{method transfer}-method (and friends) than constopenin.
      So when rewriting a subgoal, using, e.g., termUopensets T. xxx instead of termU. openin T U  xxx can make @{method transfer} work better. ›

lemma opensets_in_parametric[transfer_rule]:
  includes lifting_syntax
  assumes bi_unique R
  shows (rel_topology R ===> rel_set (rel_set R)) opensets_in opensets_in
proof (intro rel_funI rel_setI)
  fix S T
  assume rel_topo: rel_topology R S T
  fix U
  assume U  opensets_in S
  then show V  opensets_in T. rel_set R U V
    by (smt (verit, del_insts) Domainp.cases mem_Collect_eq opensets_in_def rel_fun_def rel_topo rel_topology_def)
next
  fix S T assume rel_topo: rel_topology R S T
  fix U assume U  opensets_in T
  then show V  opensets_in S. rel_set R V U
    by (smt (verit) RangepE mem_Collect_eq opensets_in_def rel_fun_def rel_topo rel_topology_def)
qed

lemma hausdorff_parametric[transfer_rule]:
  includes lifting_syntax
  assumes [transfer_rule]: bi_unique R
  shows (rel_topology R ===> (⟷)) Hausdorff_space Hausdorff_space
proof -
  have Hausdorff_space_def': Hausdorff_space T  (xtopspace T. ytopspace T. x  y  (U  opensets_in T. V  opensets_in T. x  U  y  V  U  V = {}))
    for T :: 'z topology
    unfolding opensets_in_def Hausdorff_space_def disjnt_def Bex_def by auto
  show ?thesis
    unfolding Hausdorff_space_def'
    by transfer_prover
qed

lemma sum_cmod_pos: 
  assumes x. xA  f x  0
  shows (xA. cmod (f x)) = cmod (xA. f x)
  by (metis (mono_tags, lifting) Re_sum assms cmod_Re sum.cong sum_nonneg)

lemma min_power_distrib_left: (min x y) ^ n = min (x ^ n) (y ^ n) if x  0 and y  0 for x y :: _ :: linordered_semidom
  by (metis linorder_le_cases min.absorb_iff2 min.order_iff power_mono that(1) that(2))

lemma abs_summable_times: 
  fixes f :: 'a  'c::{real_normed_algebra} and g :: 'b  'c
  assumes sum_f: f abs_summable_on A
  assumes sum_g: g abs_summable_on B
  shows (λ(i,j). f i * g j) abs_summable_on A × B
proof -
  have a1: (λj. norm (f i) * norm (g j)) abs_summable_on B if i  A for i
    using sum_g by (simp add: summable_on_cmult_right)
  then have a2: (λj. f i * g j) abs_summable_on B if i  A for i
    apply (rule abs_summable_on_comparison_test)
     apply (fact that)
    by (simp add: norm_mult_ineq)
  from sum_f
  have (λx. yB. norm (f x) * norm (g y)) abs_summable_on A
    by (auto simp add: infsum_cmult_right' infsum_nonneg intro!: summable_on_cmult_left)
  then have b1: (λx. yB. norm (f x * g y)) abs_summable_on A
    apply (rule abs_summable_on_comparison_test)
    using a1 a2 by (simp_all add: norm_mult_ineq infsum_mono infsum_nonneg)
  from a2 b1 show ?thesis
    by (intro abs_summable_on_Sigma_iff[THEN iffD2]) auto
qed


definition the_default def S = (if card S = 1 then (THE x. x  S) else def)

lemma card1I:
  assumes "a  A"
  assumes "x. x  A  x = a"
  shows card A = 1
  by (metis One_nat_def assms(1) assms(2) card_eq_Suc_0_ex1)

lemma the_default_CollectI:
  assumes "P a"
    and "x. P x  x = a"
  shows "P (the_default d (Collect P))"
proof -
  have card: card (Collect P) = 1
    apply (rule card1I)
    using assms by auto
  from assms have P (THE x. P x)
    by (rule theI)
  then show ?thesis
    by (simp add: the_default_def card)
qed


lemma the_default_singleton[simp]: the_default def {x} = x
  unfolding the_default_def by auto

lemma the_default_empty[simp]: the_default def {} = def
  unfolding the_default_def by auto

lemma the_default_The: the_default z S = (THE x. x  S) if card S = 1
  by (simp add: that the_default_def)

lemma the_default_parametricity[transfer_rule]:
  includes lifting_syntax
  assumes [transfer_rule]: bi_unique T
  shows (T ===> rel_set T ===> T) the_default the_default
proof (intro rel_funI, rename_tac def def' S S')
  fix def def' assume [transfer_rule]: T def def'
  fix S S' assume [transfer_rule]: rel_set T S S'
  have card_eq: card S = card S'
    by transfer_prover
  show T (the_default def S) (the_default def' S')
  proof (cases card S = 1)
    case True
    define theS theS' where [no_atp]: theS = (THE x. x  S) and [no_atp]: theS' = (THE x. x  S')
    from True have cardS': card S' = 1
      by (simp add: card_eq)
    have theS  S
      unfolding theS_def
      by (rule theI') (use True in simp add: card_eq_Suc_0_ex1)
    moreover have theS'  S'
      unfolding theS'_def
      by (rule theI') (use cardS' in simp add: card_eq_Suc_0_ex1)
    ultimately have T theS theS'
      using rel_set T S S' True cardS'
      by (auto simp: rel_set_def card_1_singleton_iff)
    then show ?thesis
      by (simp add: True cardS' the_default_def theS_def theS'_def)
  next
    case False
    then have cardS': card S'  1
      by (simp add: card_eq)
    show ?thesis
      using False cardS' T def def'
      by (auto simp add: the_default_def)
  qed
qed

definition rel_pred T P Q = rel_set T (Collect P) (Collect Q)

lemma Collect_parametric[transfer_rule]:
  includes lifting_syntax
  shows (rel_pred T ===> rel_set T) Collect Collect
  by (auto simp: rel_pred_def)

lemma fold_graph_finite:
― ‹Exists as @{thm [source] comp_fun_commute_on.fold_graph_finite}, but the
    localecomp_fun_commute_on-assumption is not needed.›
  assumes "fold_graph f z A y"
  shows "finite A"
  using assms by induct simp_all

lemma fold_graph_parametric[transfer_rule]:
  includes lifting_syntax
  assumes [transfer_rule, simp]: bi_unique T
  shows ((T ===> U ===> U) ===> U ===> rel_set T ===> rel_pred U)
          fold_graph fold_graph
proof (intro rel_funI, rename_tac f f' z z' A A')
  fix f f' assume [transfer_rule, simp]: (T ===> U ===> U) f f'
  fix z z' assume [transfer_rule, simp]: U z z'
  fix A A' assume [transfer_rule, simp]: rel_set T A A'
  have one_direction: y'. fold_graph f' z' A' y'  U y y' if fold_graph f z A y 
    and [transfer_rule]: U z z' (T ===> U ===> U) f f' rel_set T A A' bi_unique T
    for f f' z z' A A' y and U :: 'c1  'd1  bool and T :: 'a1  'b1  bool
    using fold_graph f z A y  rel_set T A A'
  proof (induction arbitrary: A')
    case emptyI
    then show ?case
      by (metis U z z' empty_iff equals0I fold_graph.intros(1) rel_setD2)
  next
    case (insertI x A y)
    from insertI have foldA: fold_graph f z A y and T_xA[transfer_rule]: rel_set T (insert x A) A' and xA: x  A
      by simp_all
    define DT RT where DT = Collect (Domainp T) and RT = Collect (Rangep T)
    from T_xA have x  DT
      by (metis DT_def DomainPI insertCI mem_Collect_eq rel_set_def)
    then obtain x' where [transfer_rule]: T x x'
      unfolding DT_def by blast
    have x'  A'
      apply transfer by simp
    define A'' where A'' = A' - {x'}
    then have A'_def: A' = insert x' A''
      using x'  A' by fastforce
    have x'  A''
      unfolding A''_def by simp
    have [transfer_rule]: rel_set T A A''
      apply (subst asm_rl[of A = (insert x A) - {x}])
      using insertI.hyps apply blast
      unfolding A''_def
      by transfer_prover
    from insertI.IH[OF this]
    obtain y'' where foldA'': fold_graph f' z' A'' y'' and [transfer_rule]: U y y''
      by auto
    define y' where y' = f' x' y''
    have fold_graph f' z' A' y'
      unfolding A'_def y'_def
      using x'  A'' foldA''
      by (rule fold_graph.intros)
    moreover have U (f x y) y'
      unfolding y'_def by transfer_prover
    ultimately show ?case
      by auto
  qed

  show rel_pred U (fold_graph f z A) (fold_graph f' z' A')
    unfolding rel_pred_def rel_set_def bex_simps
    apply safe
    subgoal
      by (rule one_direction[of f z A _ U z' T f']) auto
    subgoal
      by (rule one_direction[of f' z' A' _ U¯¯ z T¯¯ f, simplified])
         (auto simp flip: conversep_rel_fun)
    done
qed

lemma Domainp_rel_filter:
  assumes Domainp r = S
  shows Domainp (rel_filter r) F  (F  principal (Collect S))
proof (intro iffI, elim Domainp.cases, hypsubst)
  fix G 
  assume rel_filter r F G
  then obtain Z where rZ: F (x, y) in Z. r x y
    and ZF: "map_filter_on {(x, y). r x y} fst Z = F" 
    and "map_filter_on {(x, y). r x y} snd Z = G"
    using rel_filter.simps by blast
  show F  principal (Collect S)
    using rZ 
    by (auto simp flip: ZF assms intro!: filter_leI  elim!: eventually_mono
             simp: eventually_principal eventually_map_filter_on case_prod_unfold DomainPI)
next
  assume asm: F  principal (Collect S)
  define Z where Z = inf (filtercomap fst F) (principal {(x, y). r x y})
  have rZ: F (x, y) in Z. r x y
    by (simp add: Z_def eventually_inf_principal)
  moreover 
  have (F x in Z. P (fst x)  (case x of (x, xa)  r x xa)) = eventually P F for P
    using asm apply (auto simp add: le_principal Z_def eventually_inf_principal eventually_filtercomap)
    by (smt (verit, del_insts) DomainpE assms eventually_elim2)
  then have map_filter_on {(x, y). r x y} fst Z = F
    by (simp add: filter_eq_iff eventually_map_filter_on rZ)
  ultimately show Domainp (rel_filter r) F
    by (auto simp: Domainp_iff intro!: exI rel_filter.intros)
qed


lemma map_filter_on_cong:
  assumes [simp]: F x in F. x  D
  assumes x. x  D  f x = g x
  shows map_filter_on D f F = map_filter_on D g F
  apply (rule filter_eq_iff[THEN iffD2, rule_format])
  apply (simp add: eventually_map_filter_on)
  apply (rule eventually_subst)
  apply (rule always_eventually)
  using assms(2) by auto 


lemma filtermap_cong: 
  assumes F x in F. f x = g x
  shows filtermap f F = filtermap g F
  apply (rule filter_eq_iff[THEN iffD2, rule_format])
  apply (simp add: eventually_filtermap)
  by (smt (verit, del_insts) assms eventually_elim2)

lemma filtermap_INF_eq: 
  assumes inj_f: inj_on f X
  assumes B_nonempty: B  {}
  assumes F_bounded: b. bB  F b  principal X
  shows filtermap f ( (F ` B)) = (bB. filtermap f (F b))
proof (rule antisym)
  show filtermap f ( (F ` B))  (bB. filtermap f (F b))
    by (rule filtermap_INF)
  define f1 where f1 = inv_into X f
  have f1f: x  X  f1 (f x) = x for x
    by (simp add: inj_f f1_def)
  have ff1: x  f ` X  x = f (f1 x) for x
    by (simp add: f1_def f_inv_into_f)

  have filtermap f (F b)  principal (f ` X) if b  B for b
    by (metis F_bounded filtermap_mono filtermap_principal that)
  then have (bB. filtermap f (F b))  (bB. principal (f ` X))
    by (simp add: INF_greatest INF_lower2) 
  also have  = principal (f ` X)
    by (simp add: B_nonempty)
  finally have F x in bB. filtermap f (F b). x  f ` X
    using B_nonempty le_principal by auto
  then have *: F x in bB. filtermap f (F b). x = f (f1 x)
    apply (rule eventually_mono)
    by (simp add: ff1)

  have F x in F b. x  X if b  B for b
    using F_bounded le_principal that by blast
  then have **: F x in F b. f1 (f x) = x if b  B for b
    apply (rule eventually_mono)
    using that by (simp_all add: f1f)

  have (bB. filtermap f (F b)) = filtermap f (filtermap f1 (bB. filtermap f (F b)))
    apply (simp add: filtermap_filtermap)
    using * by (rule filtermap_cong[where f=id, simplified])
  also have   filtermap f (bB. filtermap f1 (filtermap f (F b)))
    apply (rule filtermap_mono)
    by (rule filtermap_INF)
  also have  = filtermap f (bB. F b)
    apply (rule arg_cong[where f=filtermap _])
    apply (rule INF_cong, rule refl)
    unfolding filtermap_filtermap
    using ** by (rule filtermap_cong[where g=id, simplified])
  finally show (bB. filtermap f (F b))  filtermap f ( (F ` B))
    by -
qed

lemma filtermap_inf_eq:
  assumes inj_on f X
  assumes F1  principal X
  assumes F2  principal X
  shows filtermap f (F1  F2) = filtermap f F1  filtermap f F2
proof -
  have filtermap f (F1  F2) = filtermap f (INF F{F1,F2}. F)
    by simp
  also have  = (INF F{F1,F2}. filtermap f F)
    apply (rule filtermap_INF_eq[where X=X])
    using assms by auto
  also have  = filtermap f F1  filtermap f F2
    by simp
  finally show ?thesis
    by -
qed


definition transfer_bounded_filter_Inf B M = Inf M  principal B

lemma Inf_transfer_bounded_filter_Inf: Inf M = transfer_bounded_filter_Inf UNIV M
  by (metis inf_top.right_neutral top_eq_principal_UNIV transfer_bounded_filter_Inf_def)

lemma Inf_bounded_transfer_bounded_filter_Inf:
  assumes F. F  M  F  principal B
  assumes M  {}
  shows Inf M = transfer_bounded_filter_Inf B M
  by (simp add: Inf_less_eq assms(1) assms(2) inf_absorb1 transfer_bounded_filter_Inf_def)


lemma transfer_bounded_filter_Inf_parametric[transfer_rule]:
  includes lifting_syntax
  fixes r :: 'rep  'abs  bool
  assumes [transfer_rule]: bi_unique r
  shows (rel_set r ===> rel_set (rel_filter r) ===> rel_filter r)
     transfer_bounded_filter_Inf transfer_bounded_filter_Inf
proof (intro rel_funI, unfold transfer_bounded_filter_Inf_def)
  fix BF BG assume BFBG[transfer_rule]: rel_set r BF BG
  fix Fs Gs assume FsGs[transfer_rule]: rel_set (rel_filter r) Fs Gs
  define D R where D = Collect (Domainp r) and R = Collect (Rangep r)
  
  have rel_set r D R
     by (smt (verit) D_def Domainp_iff R_def RangePI Rangep.cases mem_Collect_eq rel_setI)
  with bi_unique r
  obtain f where R = f ` D and [simp]: inj_on f D and rf0: xD  r x (f x) for x
    using bi_unique_rel_set_lemma
    by metis
  have rf: r x y  x  D  f x = y for x y
    apply (auto simp: rf0)
    using D_def apply auto[1]
    using D_def assms bi_uniqueDr rf0 by fastforce

  from BFBG
  have BF  D
     by (metis rel_setD1 rf subsetI)

  have G: G = filtermap f F if rel_filter r F G for F G
    using that proof cases
    case (1 Z)
    then have Z[simp]: F (x, y) in Z. r x y
      by -
    then have filtermap f F = filtermap f (map_filter_on {(x, y). r x y} fst Z)
      using 1 by simp
    also have  = map_filter_on {(x, y). r x y} (f  fst) Z
      unfolding map_filter_on_UNIV[symmetric]
      apply (subst map_filter_on_comp)
      using Z by simp_all
    also have  = G
      apply (simp add: o_def rf)
      apply (subst map_filter_on_cong[where g=snd])
      using Z apply (rule eventually_mono)
      using 1 by (auto simp: rf)
    finally show ?thesis
      by simp
  qed

  have rf_filter: rel_filter r F G  F  principal D  filtermap f F = G for F G
    apply (intro iffI conjI)
      apply (metis D_def DomainPI Domainp_rel_filter)
    using G apply simp
    by (metis D_def Domainp_iff Domainp_rel_filter G)

  have FD: F  principal D if F  Fs for F
    by (meson FsGs rel_setD1 rf_filter that)

  from BFBG
  have [simp]: BG = f ` BF
    by (auto simp: rel_set_def rf)

  from FsGs
  have [simp]: Gs = filtermap f ` Fs
    using G apply (auto simp: rel_set_def rf)
    by fastforce

  show rel_filter r ( Fs  principal BF) ( Gs  principal BG)
  proof (cases Fs = {})
    case True
    then have Gs = {}
      by transfer
    have rel_filter r (principal BF) (principal BG)
      by transfer_prover
    with True Gs = {} show ?thesis
      by simp
  next
    case False
    note False[simp]
    then have [simp]: Gs  {}
      by transfer
    have rel_filter r ( Fs  principal BF) (filtermap f ( Fs  principal BF))
      apply (rule rf_filter[THEN iffD2])
      by (simp add: BF  D le_infI2)
    then show ?thesis
      using FD BF  D
      by (simp add: Inf_less_eq 
          flip: filtermap_inf_eq[where X=D] filtermap_INF_eq[where X=D] flip: filtermap_principal)
  qed
qed


definition transfer_inf_principal F M = F  principal M

lemma transfer_inf_principal_parametric[transfer_rule]:
  includes lifting_syntax
  assumes [transfer_rule]: bi_unique T
  shows (rel_filter T ===> rel_set T ===> rel_filter T) transfer_inf_principal transfer_inf_principal
proof -
  have *: transfer_inf_principal F M = transfer_bounded_filter_Inf M {F} for F :: 'z filter and M
    by (simp add: transfer_inf_principal_def[abs_def] transfer_bounded_filter_Inf_def)
  show ?thesis
    unfolding * 
    apply transfer_prover_start
    apply transfer_step+
    by transfer_prover
qed


lemma continuous_map_is_continuous_at_point:
  assumes continuous_map T U f
  shows filterlim f (nhdsin U (f l)) (atin T l)
  by (metis assms atin_degenerate bot.extremum continuous_map_atin filterlim_iff_le_filtercomap filterlim_nhdsin_iff_limitin)

lemma set_compr_2_image_collect: {f x y |x y. P x y} = case_prod f ` Collect (case_prod P)
  by fast

lemma closure_image_closure: continuous_on (closure S) f  closure (f ` closure S) = closure (f ` S)
  by (smt (verit) closed_closure closure_closure closure_mono closure_subset image_closure_subset image_mono set_eq_subset)


lemma has_sum_reindex_bij_betw:
  assumes "bij_betw g A B"
  shows   "((λx. f (g x)) has_sum l) A  (f has_sum l) B"
proof -
  have ((λx. f (g x)) has_sum l) A  (f has_sum l) (g ` A)
    apply (rule has_sum_reindex[symmetric, unfolded o_def])
    using assms bij_betw_imp_inj_on by blast
  also have   (f has_sum l) B
    using assms bij_betw_imp_surj_on by blast
  finally show ?thesis .
qed

lemma enum_inj:
  assumes "i < CARD('a)" and "j < CARD('a)"
  shows "(Enum.enum ! i :: 'a::enum) = Enum.enum ! j  i = j"
  using inj_on_nth[OF enum_distinct, where I={..<CARD('a)}]
  using assms by (auto dest: inj_onD simp flip: card_UNIV_length_enum)

lemma closedin_vimage:
  assumes closedin U S
  assumes continuous_map T U f
  shows closedin T (topspace T  (f -` S))
  by (meson assms(1) assms(2) continuous_map_closedin_preimage_eq)

lemma join_forall: (x. P x)  (x. Q x)  (x. P x  Q x)
  by auto

lemma closedin_if_converge_inside:
  fixes A :: 'a set
  assumes AT: A  topspace T
  assumes xA: (F::'a filter) f x. F    limitin T f x F  range f  A  x  A
  shows closedin T A
proof (cases A = {})
  case True
  then show ?thesis by simp
next
  case False
  then obtain a where a  A
    by auto
  define Ac where Ac = topspace T - A
  have U. openin T U  x  U  U  Ac if x  Ac for x
  proof (rule ccontr)
    assume U. openin T U  x  U  U  Ac
    then have UA: U  A  {} if openin T Uand x  U for U
      by (metis Ac_def Diff_mono Diff_triv openin_subset subset_refl that)
    have [simp]: x  topspace T
      using that by (simp add: Ac_def)

    define F where F = nhdsin T x  principal A
    have F  
      apply (subst filter_eq_iff)
      apply (auto intro!: exI[of _ λ_. False] simp: F_def eventually_inf eventually_principal
          eventually_nhdsin)
      by (meson UA disjoint_iff)

    define f where f y = (if yA then y else a) for y
    with a  A have range f  A
      by force

    have F y in F. f y  U if openin T U and x  U for U
    proof -
      have eventually (λx. x  U) (nhdsin T x)
        using eventually_nhdsin that by fastforce
      moreover have R. (xA. R x)  (x. x  U  R x  f x  U)
        apply (rule exI[of _ λx. x  A])
        by (simp add: f_def)
      ultimately show ?thesis
        by (auto simp add: F_def eventually_inf eventually_principal)
    qed
    then have limitin T f x F
      unfolding limitin_def by simp
    with F   range f  A xA
    have x  A
      by simp
    with that show False
      by (simp add: Ac_def)
  qed
  then have openin T Ac
    apply (rule_tac openin_subopen[THEN iffD2])
    by simp
  then show ?thesis
    by (simp add: Ac_def AT closedin_def)
qed

lemma cmod_mono: 0  a  a  b  cmod a  cmod b
  by (simp add: cmod_Re less_eq_complex_def)

lemma choice2: f. (x. Q1 x (f x))  (x. Q2 x (f x))
  if x. y. Q1 x y  Q2 x y
  by (meson that)

lemma choice3: f. (x. Q1 x (f x))  (x. Q2 x (f x))  (x. Q3 x (f x))
  if x. y. Q1 x y  Q2 x y  Q3 x y
  by (meson that)

lemma choice4: f. (x. Q1 x (f x))  (x. Q2 x (f x))  (x. Q3 x (f x))  (x. Q4 x (f x))
  if x. y. Q1 x y  Q2 x y  Q3 x y  Q4 x y
  by (meson that)

lemma choice5: f. (x. Q1 x (f x))  (x. Q2 x (f x))  (x. Q3 x (f x))  (x. Q4 x (f x))  (x. Q5 x (f x))
  if x. y. Q1 x y  Q2 x y  Q3 x y  Q4 x y  Q5 x y
  apply (simp only: flip: all_conj_distrib)
  using that by (rule choice)

lemma is_Sup_unique: is_Sup X a  is_Sup X b  a=b
  by (simp add: Orderings.order_eq_iff is_Sup_def)

lemma has_Sup_bdd_above: has_Sup X  bdd_above X
  by (metis bdd_above.unfold has_Sup_def is_Sup_def)

lemma is_Sup_has_Sup: is_Sup X s  has_Sup X
  using has_Sup_def by blast

class Sup_order = order + Sup + sup +
  assumes is_Sup_Sup: has_Sup X  is_Sup X (Sup X)
  assumes is_Sup_sup: has_Sup {x,y}  is_Sup {x,y} (sup x y)

lemma (in Sup_order) is_Sup_eq_Sup:
  assumes is_Sup X s
  shows s = Sup X
  by (meson assms local.dual_order.antisym local.has_Sup_def local.is_Sup_Sup local.is_Sup_def)

lemma is_Sup_cSup:
  fixes X :: 'a::conditionally_complete_lattice set
  assumes bdd_above X and X  {}
  shows is_Sup X (Sup X)
  using assms by (auto intro!: cSup_upper cSup_least simp: is_Sup_def)

lemma continuous_map_iff_preserves_convergence:
  assumes F a. a  topspace T  limitin T id a F  limitin U f (f a) F
  shows continuous_map T U f
  apply (rule continuous_map_atin[THEN iffD2], intro ballI)
  using assms
  by (simp add: limitin_continuous_map)


lemma SMT_choices:
  ― ‹Was included as SMT.choices in Isabelle and disappeared›
  "Q. x. y ya. Q x y ya  f fa. x. Q x (f x) (fa x)"
  "Q. x. y ya yb. Q x y ya yb  f fa fb. x. Q x (f x) (fa x) (fb x)"
  "Q. x. y ya yb yc. Q x y ya yb yc  f fa fb fc. x. Q x (f x) (fa x) (fb x) (fc x)"
  "Q. x. y ya yb yc yd. Q x y ya yb yc yd 
     f fa fb fc fd. x. Q x (f x) (fa x) (fb x) (fc x) (fd x)"
  "Q. x. y ya yb yc yd ye. Q x y ya yb yc yd ye 
     f fa fb fc fd fe. x. Q x (f x) (fa x) (fb x) (fc x) (fd x) (fe x)"
  "Q. x. y ya yb yc yd ye yf. Q x y ya yb yc yd ye yf 
     f fa fb fc fd fe ff. x. Q x (f x) (fa x) (fb x) (fc x) (fd x) (fe x) (ff x)"
  "Q. x. y ya yb yc yd ye yf yg. Q x y ya yb yc yd ye yf yg 
     f fa fb fc fd fe ff fg. x. Q x (f x) (fa x) (fb x) (fc x) (fd x) (fe x) (ff x) (fg x)"
  by metis+


lemma closedin_pullback_topology:
  "closedin (pullback_topology A f T) S  (C. closedin T C  S = f-`C  A)"
proof (rule iffI)
  define TT PT where TT = topspace T and PT = topspace (pullback_topology A f T)
  assume closed: closedin (pullback_topology A f T) S
  then have S  PT
    using PT_def closedin_subset by blast
  from closed have openin (pullback_topology A f T) (PT - S)
    by (auto intro!: simp: closedin_def PT_def)
  then obtain U where openin T U and S_fUA: PT - S = f -` U  A
    by (auto simp: openin_pullback_topology)
  define C where C = TT - U
  have closedin T C
    using C_def TT_def openin T U by blast
  moreover have S = f -` C  A
    using S_fUA S  PT
    apply (simp only: C_def PT_def TT_def)
    by (metis Diff_Diff_Int Diff_Int_distrib2  inf.absorb_iff2 topspace_pullback_topology vimage_Diff)
  ultimately show C. closedin T C  S = f -` C  A
    by auto
next
  assume U. closedin T U  S = f -` U  A
  then show closedin (pullback_topology A f T) S
    apply (simp add: openin_pullback_topology closedin_def topspace_pullback_topology)
    by blast
qed


lemma regular_space_pullback[intro]:
  assumes regular_space T
  shows regular_space (pullback_topology A f T)
proof (unfold regular_space_def, intro allI impI)
  define TT PT where TT = topspace T and PT = topspace (pullback_topology A f T)
  fix S y
  assume asm: closedin (pullback_topology A f T) S  y  PT - S
  from asm obtain C where closedin T C and S_fCA: S = f -` C  A
    by (auto simp: closedin_pullback_topology)
  from asm S_fCA
  have f y  TT - C
    by (auto simp: PT_def TT_def topspace_pullback_topology)
  then obtain U' V' where openin T U' and openin T V' and f y  U' and C  V' and U'  V' = {}
    by (metis TT_def closedin T C assms regular_space_def disjnt_def)
  define U V where U = f -` U'  A and V = f -` V'  A
  have openin (pullback_topology A f T) U
    using U_def openin T U' openin_pullback_topology by blast
  moreover have openin (pullback_topology A f T) V
    using V_def openin T V' openin_pullback_topology by blast
  moreover have y  U
    by (metis DiffD1 Int_iff PT_def U_def f y  U' asm topspace_pullback_topology vimageI)
  moreover have S  V
    using S_fCA V_def C  V' by blast
  moreover have disjnt U V
    using U_def V_def U'  V' = {} disjnt_def by blast

  ultimately show U V. openin (pullback_topology A f T) U  openin (pullback_topology A f T) V  y  U  S  V  disjnt U V
    apply (rule_tac exI[of _ U], rule_tac exI[of _ V])
    by auto
qed

lemma t3_space_euclidean_regular[iff]: regular_space (euclidean :: 'a::t3_space topology)
  using t3_space
  apply (simp add: regular_space_def disjnt_def)
  by fast

definition increasing_filter :: 'a::order filter  bool where
  ― ‹Definition suggested by cite"increasing-filters"
  increasing_filter F  (F x in F. F y in F. y  x)

lemma increasing_filtermap:
  fixes F :: 'a::order filter and f :: 'a  'b::order and X :: 'a set
  assumes increasing: increasing_filter F
  assumes mono: mono_on X f
  assumes ev_X: eventually (λx. x  X) F
  shows increasing_filter (filtermap f F)
proof -
  from increasing
  have incr: F x in F. F y in F. x  y
    apply (simp add: increasing_filter_def)
    by -
  have F x in F. F y in F. f x  f y
  proof (rule eventually_elim2[OF ev_X incr])
    fix x
    assume x  X
    assume F y in F. x  y
    then show F y in F. f x  f y
    proof (rule eventually_elim2[OF ev_X])
      fix y assume y  X and x  y
      with x  X show f x  f y
        using mono by (simp add: mono_on_def)
    qed
  qed
  then show increasing_filter (filtermap f F)
    by (simp add: increasing_filter_def eventually_filtermap)
qed

lemma increasing_finite_subsets_at_top[simp]: increasing_filter (finite_subsets_at_top X)
  apply (simp add: increasing_filter_def eventually_finite_subsets_at_top)
  by force

lemma monotone_convergence:
  ― ‹Following cite"increasing-filters"
  fixes f :: 'b  'a::{order_topology, conditionally_complete_linorder}
  assumes bounded: F x in F. f x  B
  assumes increasing: increasing_filter (filtermap f F)
  shows l. (f  l) F
proof (cases F  )
  case True
  note [simp] = True
  define S l where S x  (F y in F. f y  x)  x  B 
    and l = Sup (Collect S) for x
  from bounded increasing
  have ev_S: eventually S (filtermap f F)
    by (auto intro!: eventually_conj simp: S_def[abs_def] increasing_filter_def eventually_filtermap)
  have bdd_S: bdd_above (Collect S)
    by (auto simp: S_def)
  have S_nonempty: Collect S  {}
    using ev_S
    by (metis Collect_empty_eq_bot Set.empty_def True eventually_False filtermap_bot_iff)
  have (f  l) F
  proof (rule order_tendstoI; rename_tac x)
    fix x
    assume x < l
    then obtain s where S s and x < s
      using less_cSupD[OF S_nonempty] l_def
      by blast
    then 
    show F y in F. x < f y
      using S_def basic_trans_rules(22) eventually_mono by force
  next
    fix x
    assume asm: l < x
    from ev_S
    show F y in F. f y < x
      unfolding eventually_filtermap
      apply (rule eventually_mono)
      using asm
      by (metis bdd_S cSup_upper dual_order.strict_trans2 l_def mem_Collect_eq)
  qed
  then show l. (f  l) F
    by (auto intro!: exI[of _ l] simp: filterlim_def)
next
  case False
  then show l. (f  l) F
    by (auto intro!: exI)
qed


lemma monotone_convergence_complex:
  fixes f :: 'b  complex
  assumes bounded: F x in F. f x  B
  assumes increasing: increasing_filter (filtermap f F)
  shows l. (f  l) F
proof -
  have inc_re: increasing_filter (filtermap (λx. Re (f x)) F)
    using increasing_filtermap[OF increasing, where f=Re and X=UNIV]
    by (simp add: less_eq_complex_def[abs_def] mono_def monotone_def filtermap_filtermap)
  from bounded have F x in F. Re (f x)  Re B
    using eventually_mono less_eq_complex_def by fastforce
  from monotone_convergence[OF this inc_re]
  obtain re where lim_re: ((λx. Re (f x))  re) F
    by auto
  from bounded have F x in F. Im (f x) = Im B
    by (simp add: less_eq_complex_def[abs_def] eventually_mono)
  then have lim_im: ((λx. Im (f x))  Im B) F
    by (simp add: tendsto_eventually)
  from lim_re lim_im have (f  Complex re (Im B)) F
    by (simp add: tendsto_complex_iff)
  then show ?thesis
    by auto
qed

lemma compact_closed_subset:
  assumes compact s
  assumes closed t
  assumes t  s
  shows compact t
  by (metis assms(1) assms(2) assms(3) compact_Int_closed inf.absorb_iff2)

definition separable where separable S  (B. countable B  S  closure B)

lemma compact_imp_separable: separable S if compact S for S :: 'a::metric_space set
proof -
  from that
  obtain K where finite (K n) and K_cover_S: S  (kK n. ball k (1 / of_nat (n+1))) for n :: nat
  proof (atomize_elim, intro choice2 allI)
    fix n
    have S  (kUNIV. ball k (1 / of_nat (n+1)))
      apply (auto intro!: simp: )
      by (smt (verit, del_insts) dist_eq_0_iff linordered_field_class.divide_pos_pos of_nat_less_0_iff)
    then show K. finite K  S  (kK. ball k (1 / real (n + 1)))
      apply (simp add: compact_eq_Heine_Borel)
      by (meson Elementary_Metric_Spaces.open_ball compactE_image compact S)
  qed
  define B where B = (n. K n)
  have countable B
    using B_def finite (K _) uncountable_infinite by blast
  have S  closure B
  proof (intro subsetI closure_approachable[THEN iffD2, rule_format])
    fix x assume x  S
    fix e :: real assume e > 0
    define n :: nat where n = nat (ceiling (1/e))
    with e > 0 have ne: 1 / real (n+1)  e
    proof -
      have 1 / real (n+1)  1 / ceiling (1/e)
        by (simp add: 0 < e linordered_field_class.frac_le n_def)
      also have   1 / (1/e)
        by (smt (verit, del_insts) 0 < e le_of_int_ceiling linordered_field_class.divide_pos_pos linordered_field_class.frac_le)
      also have  = e
        by simp
      finally show ?thesis
        by -
    qed
    have S  (kK n. ball k (1 / of_nat (n+1)))
      using K_cover_S by presburger
    then obtain k where k  K n and x_ball: x  ball k (1 / of_nat (n+1))
      using x  S by auto
    from k  K n have k  B
      using B_def by blast
    moreover from x_ball have dist k x < e
      by (smt (verit) ne mem_ball)
    ultimately show kB. dist k x < e
      by fast
  qed
  show separable S
    using S  closure B countable B separable_def by blast
qed

lemma infsum_single: 
  assumes "j. j  i  jA  f j = 0"
  shows "infsum f A = (if iA then f i else 0)"
  apply (subst infsum_cong_neutral[where T=A  {i} and g=f])
  using assms by auto

lemma suminf_eqI:
  fixes x :: _::{comm_monoid_add,t2_space}
  assumes f sums x
  shows suminf f = x
  using assms
  by (auto intro!: simp: sums_iff)

lemma suminf_If_finite_set:
  fixes f :: _  _::{comm_monoid_add,t2_space}
  assumes finite F
  shows (xF. f x) = (x. if xF then f x else 0)
  by (auto intro!: suminf_eqI[symmetric] sums_If_finite_set simp: assms)



lemma tendsto_le_complex:
  fixes x y :: complex
  assumes F: "¬ trivial_limit F"
    and x: "(f  x) F"
    and y: "(g  y) F"
    and ev: "eventually (λx. g x  f x) F"
  shows "y  x"
proof (rule less_eq_complexI)
  note F
  moreover have ((λx. Re (f x))  Re x) F
    by (simp add: assms tendsto_Re)
  moreover have ((λx. Re (g x))  Re y) F
    by (simp add: assms tendsto_Re)
  moreover from ev have "eventually (λx. Re (g x)  Re (f x)) F"
    apply (rule eventually_mono)
    by (simp add: less_eq_complex_def)
  ultimately show Re y  Re x
    by (rule tendsto_le)
next
  note F
  moreover have ((λx. Im (g x))  Im y) F
    by (simp add: assms tendsto_Im)
  moreover 
  have ((λx. Im (g x))  Im x) F
  proof -
    have ((λx. Im (f x))  Im x) F
      by (simp add: assms tendsto_Im)
    moreover from ev have F x in F. Im (f x) = Im (g x)
      apply (rule eventually_mono)
      by (simp add: less_eq_complex_def)
    ultimately show ?thesis
      by (rule Lim_transform_eventually)
  qed
  ultimately show Im y = Im x
    by (rule tendsto_unique)
qed

lemma bdd_above_mono2:
  assumes bdd_above (g ` B)
  assumes A  B
  assumes x. x  A  f x  g x
  shows bdd_above (f ` A)
  by (smt (verit, del_insts) Set.basic_monos(7) assms(1) assms(2) assms(3) basic_trans_rules(23) bdd_above.I2 bdd_above.unfold imageI)


lemma infsum_product:
  fixes f :: 'a  'c :: {topological_semigroup_mult,division_ring,banach}
  assumes (λ(x, y). f x * g y) summable_on X × Y
  shows (xX. f x) * (yY. g y) = ((x,y)X×Y. f x * g y)
  using assms
  by (simp add: infsum_cmult_right' infsum_cmult_left' flip: infsum_Sigma'_banach)

lemma infsum_product':
  fixes f :: 'a  'c :: {banach,times,real_normed_algebra} and g :: 'b  'c
  assumes f abs_summable_on X
  assumes g abs_summable_on Y
  shows (xX. f x) * (yY. g y) = ((x,y)X×Y. f x * g y)
  using assms
  by (simp add: abs_summable_times infsum_cmult_right infsum_cmult_left abs_summable_summable flip: infsum_Sigma'_banach)

lemma infsum_bounded_linear_invertible:
  assumes bounded_linear h
  assumes bounded_linear h'
  assumes h' o h = id
  shows infsum (λx. h (f x)) A = h (infsum f A)
proof (cases f summable_on A)
  case True
  then show ?thesis
    using assms(1) infsum_bounded_linear by blast
next
  case False
  have ¬ (λx. h (f x)) summable_on A
  proof (rule ccontr)
    assume ¬ ¬ (λx. h (f x)) summable_on A
    with bounded_linear h' have h' o h o f summable_on A
      by (auto intro: summable_on_bounded_linear simp: o_def)
    then have f summable_on A
      by (simp add: assms(3))
    with False show False
      by blast
  qed
  then show ?thesis
    by (simp add: False assms(1) infsum_not_exists linear_simps(3))
qed


lemma summable_on_bdd_above_real: bdd_above (f ` M) if f summable_on M for f :: 'a  real
proof -
  from that have f abs_summable_on M
    unfolding summable_on_iff_abs_summable_on_real[symmetric]
    by -
  then have bdd_above (sum (λx. norm (f x)) ` {F. F  M  finite F})
    unfolding abs_summable_iff_bdd_above by simp
  then have bdd_above (sum (λx. norm (f x)) ` (λx. {x}) ` M)
    by (rule bdd_above_mono) auto
  then have bdd_above ((λx. norm (f x)) ` M)
    by (simp add: image_image)
  then show ?thesis
    by (simp add: bdd_above_mono2)
qed


end