Theory Markov_Models_Auxiliary

(* Author: Johannes Hölzl <hoelzl@in.tum.de> *)

section ‹Auxiliary Theory›

text ‹Parts of it should be moved to the Isabelle repository›

theory Markov_Models_Auxiliary
imports
  "HOL-Probability.Probability"
  "HOL-Library.Rewrite"
  "HOL-Library.Linear_Temporal_Logic_on_Streams"
  Coinductive.Coinductive_Stream
  Coinductive.Coinductive_Nat
begin

lemma lfp_upperbound: "(y. x  f y)  x  lfp f"
  unfolding lfp_def by (intro Inf_greatest) (auto intro: order_trans)

(* ?? *)
lemma lfp_arg: "(λt. lfp (F t)) = lfp (λx t. F t (x t))"
  apply (auto simp: lfp_def le_fun_def fun_eq_iff intro!: Inf_eqI Inf_greatest)
  subgoal for x y
    by (rule INF_lower2[of "top(x := y)"]) auto
  done

lemma lfp_pair: "lfp (λf (a, b). F (λa b. f (a, b)) a b) (a, b) = lfp F a b"
  unfolding lfp_def
  by (auto intro!: INF_eq simp: le_fun_def)
     (auto intro!: exI[of _ "λ(a, b). x a b" for x])

lemma all_Suc_split: "(i. P i)  (P 0  (i. P (Suc i)))"
  using nat_induct by auto

definition "with P f d = (if x. P x then f (SOME x. P x) else d)"

lemma withI[case_names default exists]:
  "((x. ¬ P x)  Q d)  (x. P x  Q (f x))  Q (with P f d)"
  unfolding with_def by (auto intro: someI2)

context order
begin

definition
  "maximal f S = {xS. yS. f y  f x}"

lemma maximalI: "x  S  (y. y  S  f y  f x)  x  maximal f S"
  by (simp add: maximal_def)

lemma maximalI_trans: "x  maximal f S  f x  f y  y  S  y  maximal f S"
  unfolding maximal_def by (blast intro: antisym order_trans)

lemma maximalD1: "x  maximal f S  x  S"
  by (simp add: maximal_def)

lemma maximalD2: "x  maximal f S  y  S  f y  f x"
  by (simp add: maximal_def)

lemma maximal_inject: "x  maximal f S  y  maximal f S  f x = f y"
  by (rule order.antisym) (simp_all add: maximal_def)

lemma maximal_empty[simp]: "maximal f {} = {}"
  by (simp add: maximal_def)

lemma maximal_singleton[simp]: "maximal f {x} = {x}"
  by (auto simp add: maximal_def)

lemma maximal_in_S: "maximal f S  S"
  by (auto simp: maximal_def)

end

context linorder
begin

lemma maximal_ne:
  assumes "finite S" "S  {}"
  shows "maximal f S  {}"
  using assms
proof (induct rule: finite_ne_induct)
  case (insert s S)
  show ?case
  proof cases
    assume "xS. f x  f s"
    with insert have "s  maximal f (insert s S)"
      by (auto intro!: maximalI)
    then show ?thesis
      by auto
  next
    assume "¬ (xS. f x  f s)"
    then have "maximal f (insert s S) = maximal f S"
      by (auto simp: maximal_def)
    with insert show ?thesis
      by auto
  qed
qed simp

end

lemma mono_les:
  fixes s S N and l1 l2 :: "'a  real" and K :: "'a  'a pmf"
  defines "Δ x  l2 x - l1 x"
  assumes s: "s  S" and S: "(sS. set_pmf (K s))  S  N"
  assumes int_l1[simp]: "s. s  S  integrable (K s) l1"
  assumes int_l2[simp]: "s. s  S  integrable (K s) l2"
  assumes to_N: "s. s  S  tN. (s, t)  (SIGMA s:UNIV. K s)*"
  assumes l1: "s. s  S  (t. l1 t K s) + c s  l1 s"
  assumes l2: "s. s  S  l2 s  (t. l2 t K s) + c s"
  assumes eq: "s. s  N  l2 s  l1 s"
  assumes finitary: "finite (Δ ` (SN))"
  shows "l2 s  l1 s"
proof -
  define M where "M = {sSN. tSN. Δ t  Δ s}"

  have [simp]: "s. sS  integrable (K s) Δ"
    by (simp add: Δ_def[abs_def])

  have M_unqiue: "s t. s  M  t  M  Δ s = Δ t"
    by (auto intro!: antisym simp: M_def)
  have M1: "s. s  M  s  S  N"
    by (auto simp: M_def)
  have M2: "s t. s  M  t  S  N  Δ t  Δ s"
    by (auto simp: M_def)
  have M3: "s t. s  M  t  S  N  t  M  Δ t < Δ s"
    by (auto simp: M_def less_le)

  have N: "sN. Δ s  0"
    using eq by (simp add: Δ_def)

  { fix s assume s: "s  M" "M  N = {}"
    then have "s  S - N"
      by (auto dest: M1)
    with to_N[of s] obtain t where "(s, t)  (SIGMA s:UNIV. K s)*" and "t  N"
      by (auto simp: M_def)
    from this(1) s  M have "Δ s  0"
    proof (induction rule: converse_rtrancl_induct)
      case (step s s')
      then have s: "s  M" "s  S" "s  N" and s': "s'  S  N" "s'  K s"
        using S M  N = {} by (auto dest: M1)
      have "s'  M"
      proof (rule ccontr)
        assume "s'  M"
        with s  S s' s  M
        have "0 < pmf (K s) s'" "Δ s' < Δ s"
          by (auto intro: M2 M3 pmf_positive)

        have "Δ s  ((t. l2 t K s) + c s) - ((t. l1 t K s) + c s)"
          unfolding Δ_def using s  S s  N by (intro diff_mono l1 l2) auto
        then have "Δ s  (s'. Δ s' K s)"
          using s  S by (simp add: Δ_def)
        also have " < (s'. Δ s K s)"
          using s'  K s Δ s' < Δ s sS S sM
          by (intro measure_pmf.integral_less_AE[where A="{s'}"])
             (auto simp: emeasure_measure_pmf_finite AE_measure_pmf_iff set_pmf_iff[symmetric]
                   intro!: M2)
        finally show False
          using measure_pmf.prob_space[of "K s"] by simp
      qed
      with step.IH tN N have "Δ s'  0" "s'  M"
        by auto
      with sS show "Δ s  0"
        by (force simp: M_def)
    qed (insert N tN, auto) }

  show ?thesis
  proof cases
    assume "M  N = {}"
    have "Max (Δ`(SN))  Δ`(SN)"
      using s  S by (intro Max_in finitary) auto
    then obtain t where "t  S  N" "Δ t = Max (Δ`(SN))"
      unfolding image_iff by metis
    then have "t  M"
      by (auto simp: M_def finitary intro!: Max_ge)
    have "Δ s  Δ t"
      using tM sS by (auto dest: M2)
    also have "Δ t  0"
      using tM M  N = {} by fact
    finally show ?thesis
      by (simp add: Δ_def)
  next
    assume "M  N  {}"
    then obtain t where "t  M" "t  N" by auto
    with N sS have "Δ s  0"
      by (intro order_trans[of "Δ s" "Δ t" 0]) (auto simp: M_def)
    then show ?thesis
      by (simp add: Δ_def)
  qed
qed

lemma unique_les:
  fixes s S N and l1 l2 :: "'a  real" and K :: "'a  'a pmf"
  defines "Δ x  l2 x - l1 x"
  assumes s: "s  S" and S: "(sS. set_pmf (K s))  S  N"
  assumes "s. s  S  integrable (K s) l1"
  assumes "s. s  S  integrable (K s) l2"
  assumes "s. s  S  tN. (s, t)  (SIGMA s:UNIV. K s)*"
  assumes "s. s  S  l1 s = (t. l1 t K s) + c s"
  assumes "s. s  S  l2 s = (t. l2 t K s) + c s"
  assumes "s. s  N  l2 s = l1 s"
  assumes 1: "finite (Δ ` (SN))"
  shows "l2 s = l1 s"
proof -
  have "finite ((λx. l2 x - l1 x) ` (SN))"
    using 1 by (auto simp: Δ_def[abs_def])
  moreover then have "finite (uminus ` (λx. l2 x - l1 x) ` (SN))"
    by auto
  ultimately show ?thesis
    using assms
    by (intro antisym mono_les[of s S K N l2 l1 c] mono_les[of s S K N l1 l2 c])
       (auto simp: image_comp comp_def)
qed

lemma inf_continuous_suntil_disj[order_continuous_intros]:
  assumes Q: "inf_continuous Q"
  assumes disj: "x ω. ¬ (P ω  Q x ω)"
  shows "inf_continuous (λx. P suntil Q x)"
  unfolding inf_continuous_def
proof (safe intro!: ext)
  fix M ω i assume "(P suntil Q (i. M i)) ω" "decseq M" then show "(P suntil Q (M i)) ω"
    unfolding inf_continuousD[OF Q decseq M] by induction (auto intro: suntil.intros)
next
  fix M ω assume *: "(i. P suntil Q (M i)) ω" "decseq M"
  then have "(P suntil Q (M 0)) ω"
    by auto
  from this * show "(P suntil Q (i. M i)) ω"
    unfolding inf_continuousD[OF Q decseq M]
  proof induction
    case (base ω) with disj[of ω "M _"] show ?case by (auto intro: suntil.intros elim: suntil.cases)
  next
    case (step ω) with disj[of ω "M _"] show ?case by (auto intro: suntil.intros elim: suntil.cases)
  qed
qed

lemma inf_continuous_nxt[order_continuous_intros]: "inf_continuous P  inf_continuous (λx. nxt (P x) ω)"
  by (auto simp: inf_continuous_def image_comp)

lemma sup_continuous_nxt[order_continuous_intros]: "sup_continuous P  sup_continuous (λx. nxt (P x) ω)"
  by (auto simp: sup_continuous_def image_comp)

lemma mcont_ennreal_of_enat: "mcont Sup (≤) Sup (≤) ennreal_of_enat"
  by (auto intro!: mcontI monotoneI contI ennreal_of_enat_Sup)

lemma mcont2mcont_ennreal_of_enat[cont_intro]:
  "mcont lub ord Sup (≤) f  mcont lub ord Sup (≤) (λx. ennreal_of_enat (f x))"
  by (auto intro: ccpo.mcont2mcont[OF complete_lattice_ccpo'] mcont_ennreal_of_enat)

declare stream.exhaust[cases type: stream]

lemma scount_eq_emeasure: "scount P ω = emeasure (count_space UNIV) {i. P (sdrop i ω)}"
proof cases
  assume "alw (ev P) ω"
  moreover then have "infinite {i. P (sdrop i ω)}"
    using infinite_iff_alw_ev[of P ω] by simp
  ultimately show ?thesis
    by (simp add: scount_infinite_iff[symmetric])
next
  assume "¬ alw (ev P) ω"
  moreover then have "finite {i. P (sdrop i ω)}"
    using infinite_iff_alw_ev[of P ω] by simp
  ultimately show ?thesis
    by (simp add: not_alw_iff not_ev_iff scount_eq_card)
qed

lemma measurable_scount[measurable]:
  assumes [measurable]: "Measurable.pred (stream_space M) P"
  shows "scount P  measurable (stream_space M) (count_space UNIV)"
  unfolding scount_eq[abs_def] by measurable

lemma measurable_sfirst2:
  assumes [measurable]: "Measurable.pred (N M stream_space M) (λ(x, ω). P x ω)"
  shows "(λ(x, ω). sfirst (P x) ω)  measurable (N M  stream_space M) (count_space UNIV)"
  apply (coinduction rule: measurable_enat_coinduct)
  apply simp
  apply (rule exI[of _ "λx. 0"])
  apply (rule exI[of _ "λ(x, ω). (x, stl ω)"])
  apply (rule exI[of _ "λ(x, ω). P x ω"])
  apply (subst sfirst.simps[abs_def])
  apply (simp add: fun_eq_iff)
  done

lemma measurable_sfirst2'[measurable (raw)]:
  assumes [measurable (raw)]: "f  N M stream_space M" "Measurable.pred (N M stream_space M) (λx. P (fst x) (snd x))"
  shows "(λx. sfirst (P x) (f x))  measurable N (count_space UNIV)"
  using measurable_sfirst2[measurable] by measurable

lemma measurable_sfirst[measurable]:
  assumes [measurable]: "Measurable.pred (stream_space M) P"
  shows "sfirst P  measurable (stream_space M) (count_space UNIV)"
  by measurable

lemma measurable_epred[measurable]: "epred  count_space UNIV M count_space UNIV"
  by (rule measurable_count_space)

lemma nn_integral_stretch:
  "f  borel M borel  c  0  (+x. f (c * x) lborel) = (1 / ¦c¦::real) * (+x. f x lborel)"
  using nn_integral_real_affine[of f c 0] by (simp add: mult.assoc[symmetric] ennreal_mult[symmetric])

lemma prod_sum_distrib:
  fixes f g :: "'a  'b  'c::comm_semiring_1"
  assumes "finite I" shows "(i. i  I  finite (J i))  (iI. jJ i. f i j) = (mPiE I J. iI. f i (m i))"
  using finite I
proof induction
  case (insert i I) then show ?case
    by (auto simp: PiE_insert_eq finite_PiE sum.reindex inj_combinator sum.swap[of _ "PiE I J"]
                   sum.cartesian_product' sum_distrib_left sum_distrib_right
             intro!: sum.cong prod.cong arg_cong[where f="(*) x" for x])
qed simp

lemma prod_add_distrib:
  fixes f g :: "'a  'b::comm_semiring_1"
  assumes "finite I" shows "(iI. f i + g i) = (JPow I. (iJ. f i) * (iI - J. g i))"
proof -
  have "(iI. f i + g i) = (iI. b{True, False}. if b then f i else g i)"
    by simp
  also have " = (mI E {True, False}. iI. if m i then f i else g i)"
    using finite I by (rule prod_sum_distrib) simp
  also have " = (JPow I. (iJ. f i) * (iI - J. g i))"
    by (rule sum.reindex_bij_witness[where i="λJ. λiI. iJ" and j="λm. {iI. m i}"])
       (auto simp: fun_eq_iff prod.If_cases finite I intro!: arg_cong2[where f="(*)"] prod.cong)
  finally show ?thesis .
qed

subclass (in linordered_nonzero_semiring) ordered_semiring_0
  proof qed

lemma (in linordered_nonzero_semiring) prod_nonneg: "(aA. 0  f a)  0  prod f A"
  by (induct A rule: infinite_finite_induct) simp_all

lemma (in linordered_nonzero_semiring) prod_mono:
  "iA. 0  f i  f i  g i  prod f A  prod g A"
  by (induct A rule: infinite_finite_induct) (auto intro!: prod_nonneg mult_mono)

lemma (in linordered_nonzero_semiring) prod_mono2:
  assumes "finite J" "I  J" "i. i  I  0  g i  g i  f i" "(i. i  J - I  1  f i)"
  shows "prod g I  prod f J"
proof -
  have "prod g I = (iJ. if i  I then g i else 1)"
    using finite J I  J by (simp add: prod.If_cases Int_absorb1)
  also have "  prod f J"
    using assms by (intro prod_mono) auto
  finally show ?thesis .
qed

lemma (in linordered_nonzero_semiring) prod_mono3:
  assumes "finite J" "I  J" "i. i  J  0  g i" "i. i  I  g i  f i" "(i. i  J - I  g i  1)"
  shows "prod g J  prod f I"
proof -
  have "prod g J  (iJ. if i  I then f i else 1)"
    using assms by (intro prod_mono) auto
  also have " = prod f I"
    using finite J I  J by (simp add: prod.If_cases Int_absorb1)
  finally show ?thesis .
qed

lemma (in linordered_nonzero_semiring) one_le_prod: "(i. i  I  1  f i)  1  prod f I"
proof (induction I rule: infinite_finite_induct)
  case (insert i I) then show ?case
    using mult_mono[of 1 "f i" 1 "prod f I"]
    by (auto intro: order_trans[OF zero_le_one])
qed auto

lemma sum_plus_one_le_prod_plus_one:
  fixes p :: "'a  'b::linordered_nonzero_semiring"
  assumes "i. i  I  0  p i"
  shows "(iI. p i) + 1  (iI. p i + 1)"
proof cases
  assume [simp]: "finite I"
  with assms have [simp]: "J  I  0  prod p J" for J
    by (intro prod_nonneg) auto
  have "1 + (iI. p i) = (Jinsert {} ((λx. {x})`I). (iJ. p i) * (iI - J. 1))"
    by (subst sum.insert) (auto simp: sum.reindex)
  also have "  (JPow I. (iJ. p i) * (iI - J. 1))"
    using assms by (intro sum_mono2) auto
  finally show ?thesis
    by (subst prod_add_distrib) (auto simp: add.commute)
qed simp

lemma summable_iff_convergent_prod:
  fixes p :: "nat  real" assumes p: "i. 0  p i"
  shows "summable p  convergent (λn. i<n. p i + 1)"
  unfolding summable_iff_convergent
proof
  assume "convergent (λn. i<n. p i + 1)"
  then obtain x where x: "(λn. i<n. p i + 1)  x"
    by (auto simp: convergent_def)
  then have "1  x"
    by (rule tendsto_lowerbound) (auto intro!: always_eventually one_le_prod p)

  have "convergent (λn. 1 + (i<n. p i))"
  proof (intro Bseq_mono_convergent BseqI allI)
    show "0 < x" using 1  x by auto
  next
    fix n
    have "norm ((i<n. p i) + 1)  (i<n. p i + 1)"
      using p by (simp add: sum_nonneg sum_plus_one_le_prod_plus_one p)
    also have "  x"
      using assms
      by (intro tendsto_lowerbound[OF x])
          (auto simp: eventually_sequentially intro!: exI[of _ n] prod_mono2)
    finally show "norm (1 + sum p {..<n})  x"
      by (simp add: add.commute)
  qed (insert p, auto intro!: sum_mono2)
  then show "convergent (λn. i<n. p i)"
    unfolding convergent_add_const_iff .
next
  assume "convergent (λn. i<n. p i)"
  then obtain x where x: "(λn. exp (i<n. p i))  exp x"
    by (force simp: convergent_def intro!: tendsto_exp)
  show "convergent (λn. i<n. p i + 1)"
  proof (intro Bseq_mono_convergent BseqI allI)
    show "0 < exp x" by simp
  next
    fix n
    have "norm (i<n. p i + 1)  exp (i<n. p i)"
      using p exp_ge_add_one_self[of "p _"] by (auto simp add: prod_nonneg exp_sum add.commute intro!: prod_mono)
    also have "  exp x"
      using p
      by (intro tendsto_lowerbound[OF x]) (auto simp: eventually_sequentially intro!: sum_mono2 )
    finally show "norm (i<n. p i + 1)  exp x" .
  qed (insert p, auto intro!: prod_mono2)
qed

primrec eexp :: "ereal  ennreal"
  where
    "eexp MInfty = 0"
  | "eexp (ereal r) = ennreal (exp r)"
  | "eexp PInfty = top"

lemma
  shows eexp_minus_infty[simp]: "eexp (-) = 0"
    and eexp_infty[simp]: "eexp  = top"
  using eexp.simps by simp_all

lemma eexp_0[simp]: "eexp 0 = 1"
  by (simp add: zero_ereal_def)

lemma eexp_inj[simp]: "eexp x = eexp y  x = y"
  by (cases x; cases y; simp)

lemma eexp_mono[simp]: "eexp x  eexp y  x  y"
  by (cases x; cases y; simp add: top_unique)

lemma eexp_strict_mono[simp]: "eexp x < eexp y  x < y"
  by (simp add: less_le)

lemma exp_eq_0_iff[simp]: "eexp x = 0  x = -"
  using eexp_inj[of x "-"] unfolding eexp_minus_infty .

lemma eexp_surj: "range eexp = UNIV"
proof -
  have part: "UNIV = {0}  {0 <..< top}  {top::ennreal}"
    by (auto simp: less_top)
  show ?thesis
    unfolding part
    by (force simp: image_iff less_top less_top_ennreal intro!: eexp.simps[symmetric] eexp.simps dest: exp_total)
qed

lemma continuous_on_eexp': "continuous_on UNIV eexp"
  by (rule continuous_onI_mono) (auto simp: eexp_surj)

lemma continuous_on_eexp[continuous_intros]: "continuous_on A f  continuous_on A (λx. eexp (f x))"
  by (rule continuous_on_compose2[OF continuous_on_eexp']) auto

lemma tendsto_eexp[tendsto_intros]: "(f  x) F  ((λx. eexp (f x))  eexp x) F"
  by (rule continuous_on_tendsto_compose[OF continuous_on_eexp']) auto

lemma measurable_eexp[measurable]: "eexp  borel M borel"
  using continuous_on_eexp' by (rule borel_measurable_continuous_onI)

lemma eexp_add: "¬ ((x =   y = -)  (x = -  y = ))  eexp (x + y) = eexp x * eexp y"
  by (cases x; cases y; simp add: exp_add ennreal_mult ennreal_top_mult ennreal_mult_top)

lemma sum_Pinfty:
  fixes f :: "'a  ereal"
  shows "sum f I =   (finite I  (iI. f i = ))"
  by (induction I rule: infinite_finite_induct) auto

lemma sum_Minfty:
  fixes f :: "'a  ereal"
  shows "sum f I = -  (finite I  ¬ (iI. f i = )  (iI. f i = -))"
  by (induction I rule: infinite_finite_induct)
     (auto simp: sum_Pinfty)

lemma eexp_sum: "¬ (iI. jI. f i = -  f j = )  eexp (iI. f i) = (iI. eexp (f i))"
proof (induction I rule: infinite_finite_induct)
  case (insert i I)
  have "eexp (sum f (insert i I)) = eexp (f i) * eexp (sum f I)"
    using insert.prems insert.hyps by (auto simp: sum_Pinfty sum_Minfty intro!: eexp_add)
  then show ?case
    using insert by auto
qed simp_all

lemma eexp_suminf:
  assumes wf_f: "¬ {-, }  range f" and f: "summable f"
  shows "(λn. i<n. eexp (f i))  eexp (i. f i)"
proof -
  have "(λn. eexp (i<n. f i))  eexp (i. f i)"
    by (intro tendsto_eexp summable_LIMSEQ f)
  also have "(λn. eexp (i<n. f i)) = (λn. i<n. eexp (f i))"
    using wf_f by (auto simp: fun_eq_iff image_iff eq_commute intro!: eexp_sum)
  finally show ?thesis .
qed

lemma continuous_onI_antimono:
  fixes f :: "'a::linorder_topology  'b::{dense_order,linorder_topology}"
  assumes "open (f`A)"
    and mono: "x y. x  A  y  A  x  y  f y  f x"
  shows "continuous_on A f"
proof (rule continuous_on_generate_topology[OF open_generated_order], safe)
  have monoD: "x y. x  A  y  A  f y < f x  x < y"
    by (auto simp: not_le[symmetric] mono)
  have "x. x  A  f x < b  x < a" if a: "a  A" and fa: "f a < b" for a b
  proof -
    obtain y where "f a < y" "{f a ..< y}  f`A"
      using open_right[OF open (f`A), of "f a" b] a fa
      by auto
    obtain z where z: "f a < z" "z < min b y"
      using dense[of "f a" "min b y"] f a < y f a < b by auto
    then obtain c where "z = f c" "c  A"
      using {f a ..< y}  f`A[THEN subsetD, of z] by (auto simp: less_imp_le)
    with a z show ?thesis
      by (auto intro!: exI[of _ c] simp: monoD)
  qed
  then show "C. open C  C  A = f -` {..<b}  A" for b
    by (intro exI[of _ "(x{xA. f x < b}. {x <..})"])
       (auto intro: le_less_trans[OF mono] less_imp_le)

  have "x. x  A  b < f x  x > a" if a: "a  A" and fa: "b < f a" for a b
  proof -
    note a fa
    moreover
    obtain y where "y < f a" "{y <.. f a}  f`A"
      using open_left[OF open (f`A), of "f a" b]  a fa
      by auto
    then obtain z where z: "max b y < z" "z < f a"
      using dense[of "max b y" "f a"] y < f a b < f a by auto
    then obtain c where "z = f c" "c  A"
      using {y <.. f a}  f`A[THEN subsetD, of z] by (auto simp: less_imp_le)
    with a z show ?thesis
      by (auto intro!: exI[of _ c] simp: monoD)
  qed
  then show "C. open C  C  A = f -` {b <..}  A" for b
    by (intro exI[of _ "(x{xA. b < f x}. {..< x})"])
       (auto intro: less_le_trans[OF _ mono] less_imp_le)
qed

lemma minus_add_eq_ereal: "¬ ((a =   b = -)  (a = -  b = ))  - (a + b::ereal) = -a - b"
  by (cases a; cases b; simp)

lemma setsum_negf_ereal: "¬ {-, }  f`I  (iI. - f i) = - (iI. f i::ereal)"
  by (induction I rule: infinite_finite_induct)
     (auto simp: minus_add_eq_ereal sum_Minfty sum_Pinfty,
      (subst minus_add_eq_ereal; auto simp: sum_Pinfty sum_Minfty image_iff minus_ereal_def)+)

lemma convergent_minus_iff_ereal: "convergent (λx. - f x::ereal)  convergent f"
  unfolding convergent_def  by (metis ereal_uminus_uminus ereal_Lim_uminus)

lemma summable_minus_ereal: "¬ {-, }  range f  summable (λn. f n)  summable (λn. - f n::ereal)"
  unfolding summable_iff_convergent
  by (subst setsum_negf_ereal) (auto simp: convergent_minus_iff_ereal)

lemma (in product_prob_space) product_nn_integral_component:
  assumes "f  borel_measurable (M i)""i  I"
  shows "integralN (PiM I M) (λx. f (x i)) = integralN (M i) f"
proof -
  from assms show ?thesis
    apply (subst PiM_component[symmetric, OF i  I])
    apply (subst nn_integral_distr[OF measurable_component_singleton])
    apply simp_all
    done
qed

lemma ennreal_inverse_le[simp]: "inverse x  inverse y  y  (x::ennreal)"
  by (cases "0 < x"; cases x; cases "0 < y"; cases y; auto simp: top_unique inverse_ennreal)

lemma inverse_inverse_ennreal[simp]: "inverse (inverse x::ennreal) = x"
  by (cases "0 < x"; cases x; auto simp: inverse_ennreal)

lemma range_inverse_ennreal: "range inverse = (UNIV::ennreal set)"
proof -
  have "x. y = inverse x" for y :: ennreal
    by (intro exI[of _ "inverse y"]) simp
  then show ?thesis
    unfolding surj_def by auto
qed

lemma continuous_on_inverse_ennreal': "continuous_on (UNIV :: ennreal set) inverse"
  by (rule continuous_onI_antimono) (auto simp: range_inverse_ennreal)

lemma sums_minus_ereal: "¬ {- , }  f ` UNIV  (λn. - f n::ereal) sums x  f sums - x"
  unfolding sums_def
  apply (subst ereal_Lim_uminus)
  apply (subst (asm) setsum_negf_ereal)
  apply auto
  done

lemma suminf_minus_ereal: "¬ {- , }  f ` UNIV  summable f  (n. - f n :: ereal) = - suminf f"
  apply (rule sums_unique[symmetric])
  apply (rule sums_minus_ereal)
  apply (auto simp: ereal_uminus_eq_reorder)
  done

end