# Theory Discrete_Time_Markov_Chain

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

section ‹Discrete-Time Markov Chain›

theory Discrete_Time_Markov_Chain
imports Markov_Models_Auxiliary
begin

text ‹

Markov chain with discrete time steps and discrete state space.

›

lemma sstart_eq': "sstart Ω (x # xs) = {ω. shd ω = x ∧ stl ω ∈ sstart Ω xs}"
by (auto simp: sstart_eq)

lemma measure_eq_stream_space_coinduct[consumes 1, case_names left right cont]:
assumes "R N M"
assumes R_1: "⋀N M. R N M ⟹ N ∈ space (prob_algebra (stream_space (count_space UNIV)))"
and R_2: "⋀N M. R N M ⟹ M ∈ space (prob_algebra (stream_space (count_space UNIV)))"
and cont: "⋀N M. R N M ⟹ ∃N' M' p. (∀y∈set_pmf p. R (N' y) (M' y)) ∧
(∀x. N' x ∈ space (prob_algebra (stream_space (count_space UNIV)))) ∧ (∀x. M' x ∈ space (prob_algebra (stream_space (count_space UNIV)))) ∧
N = (measure_pmf p ⤜ (λy. distr (N' y) (stream_space (count_space UNIV)) ((##) y))) ∧
M = (measure_pmf p ⤜ (λy. distr (M' y) (stream_space (count_space UNIV)) ((##) y)))"
shows "N = M"
proof -
let ?S = "stream_space (count_space UNIV)"
have "∀N M. R N M ⟶ (∃N' M' p. (∀y∈set_pmf p. R (N' y) (M' y)) ∧
(∀x. N' x ∈ space (prob_algebra ?S)) ∧ (∀x. M' x ∈ space (prob_algebra ?S)) ∧
N = (measure_pmf p ⤜ (λy. distr (N' y) ?S ((##) y))) ∧
M = (measure_pmf p ⤜ (λy. distr (M' y) ?S ((##) y))))"
using cont by auto
then obtain n m p where
p: "⋀N M y. R N M ⟹ y ∈ set_pmf (p N M) ⟹ R (n N M y) (m N M y)" and
n: "⋀N M x. R N M ⟹ n N M x ∈ space (prob_algebra ?S)" and
n_eq: "⋀N M y. R N M ⟹ N = (measure_pmf (p N M) ⤜ (λy. distr (n N M y) ?S ((##) y)))" and
m: "⋀N M x. R N M ⟹ m N M x ∈ space (prob_algebra ?S)" and
m_eq: "⋀N M y. R N M ⟹ M = (measure_pmf (p N M) ⤜ (λy. distr (m N M y) ?S ((##) y)))"
unfolding choice_iff' choice_iff by blast

define A where "A = (SIGMA nm:UNIV. (λx. (n (fst nm) (snd nm) x, m (fst nm) (snd nm) x)) ` p (fst nm) (snd nm))"
have A_singleton: "A `` {nm} = (λx. (n (fst nm) (snd nm) x, m (fst nm) (snd nm) x)) ` p (fst nm) (snd nm)" for nm
by (auto simp: A_def)

have sets_n[measurable_cong, simp]: "sets (n N M y) = sets ?S" if "R N M" for N M y
using n[OF that, of y] by (auto simp: space_prob_algebra)
have sets_m[measurable_cong, simp]: "sets (m N M y) = sets ?S" if "R N M" for N M y
using m[OF that, of y] by (auto simp: space_prob_algebra)
have [simp]: "R N M ⟹ prob_space (n N M y)" for N M y
using n[of N M y] by (auto simp: space_prob_algebra)
have [simp]: "R N M ⟹ prob_space (m N M y)" for N M y
using m[of N M y] by (auto simp: space_prob_algebra)
have [measurable]: "R N M ⟹ n N M ∈ count_space UNIV →⇩M subprob_algebra ?S" for N M
by (rule measurable_prob_algebraD) (auto intro: n)
have [measurable]: "R N M ⟹ m N M ∈ count_space UNIV →⇩M subprob_algebra ?S" for N M
by (rule measurable_prob_algebraD) (auto intro: m)

define n' where "n' N M y = distr (n N M y) ?S ((##) y)" for N M y
define m' where "m' N M y = distr (m N M y) ?S ((##) y)" for N M y
have n'_eq: "R N M ⟹ N = (measure_pmf (p N M) ⤜ n' N M)" for N M unfolding n'_def by (rule n_eq)
have m'_eq: "R N M ⟹ M = (measure_pmf (p N M) ⤜ m' N M)" for N M unfolding m'_def by (rule m_eq)
have [measurable]: "R N M ⟹ n' N M ∈ count_space UNIV →⇩M subprob_algebra ?S" for N M
unfolding n'_def by (rule measurable_distr2[where M="?S"]) measurable
have [measurable]: "R N M ⟹ m' N M ∈ count_space UNIV →⇩M subprob_algebra ?S" for N M
unfolding m'_def by (rule measurable_distr2[where M="?S"]) measurable

have n'_shd: "R N M ⟹ distr (n' N M y) (count_space UNIV) shd = measure_pmf (return_pmf y)" for N M y
unfolding n'_def by (subst distr_distr) (auto simp: comp_def prob_space.distr_const return_pmf.rep_eq)
have m'_shd: "R N M ⟹ distr (m' N M y) (count_space UNIV) shd = measure_pmf (return_pmf y)" for N M y
unfolding m'_def by (subst distr_distr) (auto simp: comp_def prob_space.distr_const return_pmf.rep_eq)
have n'_stl: "R N M ⟹ distr (n' N M y) ?S stl = n N M y" for N M y
unfolding n'_def by (subst distr_distr) (auto simp: comp_def distr_id2)
have m'_stl: "R N M ⟹ distr (m' N M y) ?S stl = m N M y" for N M y
unfolding m'_def by (subst distr_distr) (auto simp: comp_def distr_id2)

define F where "F = (A⇧* `` {(N, M)})"
have "countable F"
unfolding F_def
apply (intro countable_rtrancl countable_insert[of _ "(N, M)"] countable_empty)
apply (rule countable_Image)
apply (auto simp: A_singleton)
done
have F_NM[simp]: "(N, M) ∈ F" unfolding F_def by auto
have R_F[simp]: "R N' M'" if "(N', M') ∈ F" for N' M'
proof -
have "((N, M), (N', M')) ∈ A⇧*" using that by (auto simp: F_def)
then show "R N' M'"
by (induction p=="(N', M')" arbitrary: N' M' rule: rtrancl_induct) (auto simp: ‹R N M› A_def p)
qed
have nm_F: "(n N' M' y, m N' M' y) ∈ F" if "y ∈ p N' M'" "(N', M') ∈ F" for N' M' y
proof -
have *: "((N, M), (N', M')) ∈ A⇧*" using that by (auto simp: F_def)
with that show ?thesis
apply (intro rtrancl.rtrancl_into_rtrancl[OF *])
apply (auto simp: A_def)
done
qed

define Ω where "Ω = (⋃(n, m)∈F. set_pmf (p n m))"
have [measurable]: "Ω ∈ sets (count_space UNIV)" by auto
have in_Ω: "(N, M) ∈ F ⟹ y ∈ p N M ⟹ y ∈ Ω" for N M y
by (auto simp: Ω_def Bex_def)

show ?thesis
proof (intro stream_space_eq_sstart)
from ‹countable F› show "countable Ω"
show "prob_space N" "prob_space M" "sets N = sets ?S" "sets M = sets ?S"
using R_1[OF ‹R N M›] R_2[OF ‹R N M›] by (auto simp add: space_prob_algebra)
have "⋀N M. (N, M) ∈ F ⟹ AE x in N. x !! i ∈ Ω" for i
proof (induction i)
case 0 note NM = 0[THEN R_F, simp] show ?case
apply (subst n'_eq[OF NM])
apply (subst AE_bind[where B="?S"])
apply measurable
apply (auto intro!: AE_distrD[where f=shd and M'="count_space UNIV"]
simp: AE_measure_pmf_iff n[OF NM] n'_shd in_Ω[OF 0] cong: AE_cong_simp)
done
next
case (Suc i) note NM = Suc(2)[THEN R_F, simp]
show ?case
apply (subst n'_eq[OF NM])
apply (subst AE_bind[where B="?S"])
apply measurable
apply (auto intro!: AE_distrD[where f=stl and M'="?S"] Suc(1)[OF nm_F] Suc(2)
simp: AE_measure_pmf_iff n'_stl cong: AE_cong_simp)
done
qed
then have AE_N: "⋀N M. (N, M) ∈ F ⟹ AE x in N. x ∈ streams Ω"
unfolding streams_iff_snth AE_all_countable by auto
then show "AE x in N. x ∈ streams Ω" by (blast intro: F_NM)

have "⋀N M. (N, M) ∈ F ⟹ AE x in M. x !! i ∈ Ω" for i
proof (induction i arbitrary: N M)
case 0 note NM = 0[THEN R_F, simp] show ?case
apply (subst m'_eq[OF NM])
apply (subst AE_bind[where B="?S"])
apply measurable
apply (auto intro!: AE_distrD[where f=shd and M'="count_space UNIV"]
simp: AE_measure_pmf_iff m[OF NM] m'_shd in_Ω[OF 0] cong: AE_cong_simp)
done
next
case (Suc i) note NM = Suc(2)[THEN R_F, simp]
show ?case
apply (subst m'_eq[OF NM])
apply (subst AE_bind[where B="?S"])
apply measurable
apply (auto intro!: AE_distrD[where f=stl and M'="?S"] Suc(1)[OF nm_F] Suc(2)
simp: AE_measure_pmf_iff m'_stl cong: AE_cong_simp)
done
qed
then have AE_M: "⋀N M. (N, M) ∈ F ⟹ AE x in M. x ∈ streams Ω"
unfolding streams_iff_snth AE_all_countable by auto
then show "AE x in M. x ∈ streams Ω" by (blast intro: F_NM)

fix xs assume "xs ∈ lists Ω"
with ‹(N, M) ∈ F› show "emeasure N (sstart Ω xs) = emeasure M (sstart Ω xs)"
proof (induction xs arbitrary: N M)
case Nil
have "prob_space N" "prob_space M" "sets N = sets ?S" "sets M = sets ?S"
using R_1[OF R_F[OF Nil(1)]] R_2[OF R_F[OF Nil(1)]] by (auto simp add: space_prob_algebra)
have "emeasure N (streams Ω) = 1"
by (rule prob_space.emeasure_eq_1_AE[OF ‹prob_space N› _ AE_N[OF Nil(1)]])
(auto simp add: ‹sets N = sets ?S› intro!: streams_sets)
moreover have "emeasure M (streams Ω) = 1"
by (rule prob_space.emeasure_eq_1_AE[OF ‹prob_space M› _ AE_M[OF Nil(1)]])
(auto simp add: ‹sets M = sets ?S› intro!: streams_sets)
ultimately show ?case by simp
next
case (Cons x xs)
note NM = Cons(2)[THEN R_F, simp]
have *: "(##) y -` sstart Ω (x # xs) = (if x = y then sstart Ω xs else {})" for y
by auto
show ?case
apply (subst n'_eq[OF NM])
apply (subst (3) m'_eq[OF NM])
apply (subst emeasure_bind[OF _ _ sstart_sets])
apply simp []
apply measurable []
apply (subst emeasure_bind[OF _ _ sstart_sets])
apply simp []
apply measurable []
apply (intro nn_integral_cong_AE AE_pmfI)
apply (subst n'_def)
apply (subst m'_def)
using Cons(3)
apply (auto intro!: Cons nm_F
simp add: emeasure_distr sets_eq_imp_space_eq[OF sets_n] sets_eq_imp_space_eq[OF sets_m]
space_stream_space *)
done
qed
qed
qed

subsection ‹Discrete Markov Kernel›

locale MC_syntax =
fixes K :: "'s ⇒ 's pmf"
begin

abbreviation acc :: "('s × 's) set" where
"acc ≡ (SIGMA s:UNIV. K s)⇧*"

abbreviation acc_on :: "'s set ⇒ ('s × 's) set" where
"acc_on S ≡ (SIGMA s:UNIV. K s ∩ S)⇧*"

lemma countable_reachable: "countable (acc `` {s})"
by (auto intro!: countable_rtrancl countable_set_pmf simp: Sigma_Image)

lemma countable_acc: "countable X ⟹ countable (acc `` X)"
apply (rule countable_Image)
apply (rule countable_reachable)
apply assumption
done

context
notes [[inductive_internals]]
begin

coinductive enabled where
"enabled (shd ω) (stl ω) ⟹ shd ω ∈ K s ⟹ enabled s ω"

end

lemma alw_enabled: "enabled (shd ω) (stl ω) ⟹ alw (λω. enabled (shd ω) (stl ω)) ω"
by (coinduction arbitrary: ω rule: alw_coinduct) (auto elim: enabled.cases)

abbreviation "S ≡ stream_space (count_space UNIV)"

lemma in_S [measurable (raw)]: "x ∈ space S"

inductive_simps enabled_iff: "enabled s ω"

lemma enabled_Stream: "enabled x (y ## ω) ⟷ y ∈ K x ∧ enabled y ω"
by (subst enabled_iff)  auto

lemma measurable_enabled[measurable]:
"Measurable.pred (stream_space (count_space UNIV)) (enabled s)" (is "Measurable.pred ?S _")
unfolding enabled_def
proof (coinduction arbitrary: s rule: measurable_gfp2_coinduct)
case (step A s)
then have [measurable]: "⋀t. Measurable.pred ?S (A t)" by auto
have *: "⋀x. (∃ω t. s = t ∧ x = ω ∧ A (shd ω) (stl ω) ∧ shd ω ∈ set_pmf (K t)) ⟷
(∃t∈K s. A t (stl x) ∧ t = shd x)"
by auto
note countable_set_pmf[simp]
show ?case
unfolding * by measurable
qed (auto simp: inf_continuous_def)

lemma enabled_iff_snth: "enabled s ω ⟷ (∀i. ω !! i ∈ K ((s ## ω) !! i))"
proof safe
fix i assume "enabled s ω" then show "ω !! i ∈ K ((s ## ω) !! i)"
by (induct i arbitrary: s ω)
(force elim: enabled.cases)+
next
assume "∀i. ω !! i ∈ set_pmf (K ((s ## ω) !! i))" then show "enabled s ω"
by (coinduction arbitrary: s ω)
(auto elim: allE[of _ "Suc i" for i] allE[of _ 0])
qed

primcorec force_enabled where
"force_enabled x ω =
(let y = if shd ω ∈ K x then shd ω else (SOME y. y ∈ K x) in y ## force_enabled y (stl ω))"

lemma force_enabled_in_set_pmf[simp, intro]: "shd (force_enabled x ω) ∈ K x"
by (auto simp: some_in_eq set_pmf_not_empty)

lemma enabled_force_enabled: "enabled x (force_enabled x ω)"
by (coinduction arbitrary: x ω) (auto simp: some_in_eq set_pmf_not_empty)

lemma force_enabled: "enabled x ω ⟹ force_enabled x ω = ω"
by (coinduction arbitrary: x ω) (auto elim: enabled.cases)

lemma Ex_enabled: "∃ω. enabled x ω"
by (rule exI[of _ "force_enabled x undefined"] enabled_force_enabled)+

lemma measurable_force_enabled: "force_enabled x ∈ measurable S S"
proof (rule measurable_stream_space2)
fix n show "(λω. force_enabled x ω !! n) ∈ measurable S (count_space UNIV)"
proof (induction n arbitrary: x)
case (Suc n) show ?case
apply simp
apply (rule measurable_compose_countable'[OF measurable_compose[OF measurable_stl Suc], where I="set_pmf (K x)"])
apply (rule measurable_compose[OF measurable_shd])
apply (auto simp: countable_set_pmf some_in_eq set_pmf_not_empty)
done
qed (auto intro!: measurable_compose[OF measurable_shd])
qed

abbreviation "D ≡ stream_space (Π⇩M s∈UNIV. K s)"

lemma sets_D: "sets D = sets (stream_space (Π⇩M s∈UNIV. count_space UNIV))"
by (intro sets_stream_space_cong sets_PiM_cong) simp_all

lemma space_D: "space D = space (stream_space (Π⇩M s∈UNIV. count_space UNIV))"
using sets_eq_imp_space_eq[OF sets_D] .

lemma measurable_D_D: "measurable D D =
measurable (stream_space (Π⇩M s∈UNIV. count_space UNIV)) (stream_space (Π⇩M s∈UNIV. count_space UNIV))"
by (simp add: measurable_def space_D sets_D)

primcorec walk :: "'s ⇒ ('s ⇒ 's) stream ⇒ 's stream" where
"shd (walk s ω) = (if shd ω s ∈ K s then shd ω s else (SOME t. t ∈ K s))"
| "stl (walk s ω) = walk (if shd ω s ∈ K s then shd ω s else (SOME t. t ∈ K s)) (stl ω)"

lemma enabled_walk: "enabled s (walk s ω)"
by (coinduction arbitrary: s ω) (auto simp: some_in_eq set_pmf_not_empty)

lemma measurable_walk[measurable]: "walk s ∈ measurable D S"
proof -
note measurable_compose[OF measurable_snth, intro!]
note measurable_compose[OF measurable_component_singleton, intro!]
note if_weak_cong[cong del]
note measurable_g = measurable_compose_countable'[OF _ _ countable_reachable]

define n :: nat where "n = 0"
define g where "g = (λ_::('s ⇒ 's) stream. s)"
then have "g ∈ measurable D (count_space (acc `` {s}))"
by auto
then have "(λx. walk (g x) (sdrop n x)) ∈ measurable D S"
proof (coinduction arbitrary: g n rule: measurable_stream_coinduct)
case (shd g) show ?case
by (fastforce intro: measurable_g[OF _ shd])
next
case (stl g) show ?case
by (fastforce simp add: sdrop.simps[symmetric] some_in_eq set_pmf_not_empty
simp del: sdrop.simps intro: rtrancl_into_rtrancl measurable_g[OF _ stl])
qed
then show ?thesis
qed

subsection ‹Trace Space for Discrete-Time Markov Chains›

definition T :: "'s ⇒ 's stream measure" where
"T s = distr (stream_space (Π⇩M s∈UNIV. K s)) S (walk s)"

lemma space_T[simp]: "space (T s) = space S"

lemma sets_T[simp, measurable_cong]: "sets (T s) = sets S"

lemma measurable_T1[simp]: "measurable (T s) M = measurable S M"
by (intro measurable_cong_sets) simp_all

lemma measurable_T2[simp]: "measurable M (T s) = measurable M S"
by (intro measurable_cong_sets) simp_all

lemma in_measurable_T1[measurable (raw)]: "f ∈ measurable S M ⟹ f ∈ measurable (T s) M"
by simp

lemma in_measurable_T2[measurable (raw)]: "f ∈ measurable M S ⟹ f ∈ measurable M (T s)"
by simp

lemma AE_T_enabled: "AE ω in T s. enabled s ω"
unfolding T_def by (simp add: AE_distr_iff enabled_walk)

sublocale T: prob_space "T s" for s
proof -
interpret P: product_prob_space K UNIV ..
interpret prob_space "stream_space (Π⇩M s∈UNIV. K s)"
by (rule P.prob_space_stream_space)
fix s show "prob_space (T s)"
qed

lemma emeasure_T_const[simp]: "emeasure (T s) (space S) = 1"
using T.emeasure_space_1[of s] by simp

lemma nn_integral_T:
assumes f[measurable]: "f ∈ borel_measurable S"
shows "(∫⇧+X. f X ∂T s) = (∫⇧+t. (∫⇧+ω. f (t ## ω) ∂T t) ∂K s)"
proof -
interpret product_prob_space K UNIV ..
interpret D: prob_space "stream_space (Π⇩M s∈UNIV. K s)"
by (rule prob_space_stream_space)

have T: "⋀f s. f ∈ borel_measurable S ⟹ (∫⇧+X. f X ∂T s) = (∫⇧+ω. f (walk s ω) ∂D)"

have "(∫⇧+X. f X ∂T s) = (∫⇧+ω. f (walk s ω) ∂D)"
by (rule T) measurable
also have "… = (∫⇧+d. ∫⇧+ω. f (walk s (d ## ω)) ∂D ∂Π⇩M i∈UNIV. K i)"
also have "… = (∫⇧+d. (∫⇧+ω. f (d s ## walk (d s) ω) * indicator {t. t ∈ K s} (d s) ∂D) ∂Π⇩M i∈UNIV. K i)"
apply (rule nn_integral_cong_AE)
apply (subst walk.ctr)
apply (simp add: frequently_def cong del: if_weak_cong)
apply (auto simp: AE_measure_pmf_iff intro: AE_component)
done
also have "… = (∫⇧+d. ∫⇧+ω. f (d s ## ω) * indicator (K s) (d s) ∂T (d s) ∂Π⇩M i∈UNIV. K i)"
by (subst T) (simp_all split: split_indicator)
also have "… = (∫⇧+t. ∫⇧+ω. f (t ## ω) * indicator (K s) t ∂T t ∂K s)"
by (subst (2) PiM_component[symmetric]) (simp_all add: nn_integral_distr)
also have "… = (∫⇧+t. ∫⇧+ω. f (t ## ω) ∂T t ∂K s)"
by (rule nn_integral_cong_AE) (simp add: AE_measure_pmf_iff)
finally show ?thesis .
qed

lemma nn_integral_T_gfp:
fixes g
defines "l ≡ λf ω. g (shd ω) (f (stl ω))"
assumes [measurable]: "case_prod g ∈ borel_measurable (count_space UNIV ⨂⇩M borel)"
assumes cont_g[THEN inf_continuous_compose, order_continuous_intros]: "⋀s. inf_continuous (g s)"
assumes int_g: "⋀f s. f ∈ borel_measurable S ⟹ (∫⇧+ω. g s (f ω) ∂T s) = g s (∫⇧+ω. f ω ∂T s)"
assumes bnd_g: "⋀f s. g s f ≤ b" "0 ≤ b" "b < ∞"
shows "(∫⇧+ω. gfp l ω ∂T s) = gfp (λf s. ∫⇧+t. g t (f t) ∂K s) s"
proof (rule nn_integral_gfp)
show "⋀s. sets (T s) = sets S" "⋀F. F ∈ borel_measurable S ⟹ l F ∈ borel_measurable S"
by (auto simp: l_def)
show "⋀s. emeasure (T s) (space (T s)) ≠ 0"
by (rewrite T.emeasure_space_1) simp
{ fix s F
have "integral⇧N (T s) (l F) ≤ (∫⇧+x. b ∂T s)"
by (intro nn_integral_mono) (simp add: l_def bnd_g)
also have "… < ∞"
using bnd_g by simp
finally show "integral⇧N (T s) (l F) < ∞" . }
show "inf_continuous (λf s. ∫⇧+ t. g t (f t) ∂K s)"
proof (intro order_continuous_intros)
fix f s
have "(∫⇧+ t. g t (f t) ∂K s) ≤ (∫⇧+ t. b ∂K s)"
by (intro nn_integral_mono bnd_g)
also have "… < ∞"
using bnd_g by simp
finally show "(∫⇧+ t. g t (f t) ∂K s) ≠ ∞"
by simp
qed simp
next
fix s and F :: "'s stream ⇒ ennreal" assume "F ∈ borel_measurable S"
then show "integral⇧N (T s) (l F) = (∫⇧+ t. g t (integral⇧N (T t) F) ∂K s) "
by (rewrite nn_integral_T) (simp_all add: l_def int_g)
qed (auto intro!: order_continuous_intros simp: l_def)

lemma nn_integral_T_lfp:
fixes g
defines "l ≡ λf ω. g (shd ω) (f (stl ω))"
assumes [measurable]: "case_prod g ∈ borel_measurable (count_space UNIV ⨂⇩M borel)"
assumes cont_g[THEN sup_continuous_compose, order_continuous_intros]: "⋀s. sup_continuous (g s)"
assumes int_g: "⋀f s. f ∈ borel_measurable S ⟹ (∫⇧+ω. g s (f ω) ∂T s) = g s (∫⇧+ω. f ω ∂T s)"
shows "(∫⇧+ω. lfp l ω ∂T s) = lfp (λf s. ∫⇧+t. g t (f t) ∂K s) s"
proof (rule nn_integral_lfp)
show "⋀s. sets (T s) = sets S" "⋀F. F ∈ borel_measurable S ⟹ l F ∈ borel_measurable S"
by (auto simp: l_def)
next
fix s and F :: "'s stream ⇒ ennreal" assume "F ∈ borel_measurable S"
then show "integral⇧N (T s) (l F) = (∫⇧+ t. g t (integral⇧N (T t) F) ∂K s) "
by (rewrite nn_integral_T) (simp_all add: l_def int_g)
qed (auto simp: l_def intro!: order_continuous_intros)

lemma emeasure_Collect_T:
assumes f[measurable]: "Measurable.pred S P"
shows "emeasure (T s) {x∈space (T s). P x} = (∫⇧+t. emeasure (T t) {x∈space (T t). P (t ## x)} ∂K s)"
apply (subst (1 2) nn_integral_indicator[symmetric])
apply simp
apply simp
apply (subst nn_integral_T)
apply (auto intro!: nn_integral_cong simp add: space_stream_space indicator_def)
done

lemma AE_T_iff:
assumes [measurable]: "Measurable.pred S P"
shows "(AE ω in T x. P ω) ⟷ (∀y∈K x. AE ω in T y. P (y ## ω))"
by (simp add: AE_iff_nn_integral nn_integral_T[where s=x])
(auto simp add: nn_integral_0_iff_AE AE_measure_pmf_iff split: split_indicator)

lemma AE_T_alw:
assumes [measurable]: "Measurable.pred S P"
assumes P: "⋀s. (x, s) ∈ acc ⟹ AE ω in T s. P ω"
shows "AE ω in T x. alw P ω"
proof -
define F where "F = (λp x. P x ∧ p (stl x))"
have [measurable]: "⋀p. Measurable.pred S p ⟹ Measurable.pred S (F p)"
by (auto simp: F_def)
have "almost_everywhere (T s) ((F ^^ i) top)"
if "(x, s) ∈ acc" for i s
using that
proof (induction i arbitrary: s)
case (Suc i) then show ?case
apply simp
apply (subst F_def)
apply (subst AE_T_iff)
apply (measurable; simp)
apply (auto dest: rtrancl_into_rtrancl)
done
qed simp
then have "almost_everywhere (T x) (gfp F)"
by (subst inf_continuous_gfp) (auto simp: inf_continuous_def AE_all_countable F_def)
then show ?thesis
qed

lemma emeasure_suntil_disj:
assumes [measurable]: "Measurable.pred S P"
assumes *: "⋀t. AE ω in T t. ¬ (P ⊓ (HLD X ⊓ nxt (HLD X suntil P))) ω"
shows "emeasure (T s) {ω∈space (T s). (HLD X suntil P) ω} =
lfp (λF s. emeasure (T s) {ω∈space (T s). P ω} + (∫⇧+t. F t * indicator X t ∂K s)) s"
unfolding suntil_lfp
proof (rule emeasure_lfp[where s=s])
fix F t assume [measurable]: "Measurable.pred (T s) F" and
F: "F ≤ lfp (λa b. P b ∨ HLD X b ∧ a (stl b))"
have "emeasure (T t) {ω ∈ space (T s). P ω ∨ HLD X ω ∧ F (stl ω)} =
emeasure (T t) {ω ∈ space (T t). P ω} + emeasure (T t) {ω∈space (T t). HLD X ω ∧ F (stl ω)}"
show "AE x in T t. ¬ (x ∈ {ω ∈ space (T t). P ω} ∧ x ∈ {ω ∈ space (T t). HLD X ω ∧ F (stl ω)})"
using * by eventually_elim (insert F, auto simp: suntil_lfp[symmetric])
qed auto
also have "emeasure (T t) {ω∈space (T t). HLD X ω ∧ F (stl ω)} =
(∫⇧+t. emeasure (T t) {ω ∈ space (T s). F ω} * indicator X t ∂K t)"
by (subst emeasure_Collect_T) (auto intro!: nn_integral_cong split: split_indicator)
finally show "emeasure (T t) {ω ∈ space (T s). P ω ∨ HLD X ω ∧ F (stl ω)} =
emeasure (T t) {ω ∈ space (T t). P ω} + (∫⇧+ t. emeasure (T t) {ω ∈ space (T s). F ω} * indicator X t ∂K t)" .
qed (auto intro!: order_continuous_intros split: split_indicator)

lemma emeasure_HLD_nxt:
assumes [measurable]: "Measurable.pred S P"
shows "emeasure (T s) {ω∈space (T s). (X ⋅ P) ω} =
(∫⇧+x. emeasure (T x) {ω∈space (T x). P ω} * indicator X x ∂K s)"
by (subst emeasure_Collect_T)
(auto intro!: nn_integral_cong_AE simp: AE_measure_pmf_iff split: split_indicator)

lemma emeasure_HLD:
"emeasure (T s) {ω∈space (T s). HLD X ω} = emeasure (K s) X"
using emeasure_HLD_nxt[of "λω. True" s X] T.emeasure_space_1 by simp

lemma emeasure_suntil_HLD:
assumes [measurable]: "Measurable.pred S P"
shows "emeasure (T s) {x∈space (T s). (not (HLD {t}) suntil (HLD {t} aand nxt P)) x} =
emeasure (T s) {x∈space (T s). ev (HLD {t}) x} * emeasure (T t) {x∈space (T t). P x}"
proof -
let ?P = "emeasure (T t) {ω∈space (T t). P ω}"
let ?F = "λQ F s. emeasure (T s) {ω∈space (T s). Q ω} + (∫⇧+t'. F t' * indicator (- {t}) t' ∂K s)"
have "emeasure (T s) {x∈space (T s). (HLD (-{t}) suntil ({t} ⋅ P)) x} = lfp (?F ({t} ⋅ P)) s"
by (rule emeasure_suntil_disj) (auto simp: HLD_iff)
also have "lfp (?F ({t} ⋅ P)) = (λs. lfp (?F (HLD {t})) s * ?P)"
proof (rule lfp_transfer[symmetric, where α="λx s. x s * emeasure (T t) {ω∈space (T t). P ω}"])
fix F show "(λs. ?F (HLD {t}) F s * ?P) = ?F ({t} ⋅ P) (λs. F s * ?P)"
unfolding emeasure_HLD emeasure_HLD_nxt[OF assms] distrib_right
by (auto simp: fun_eq_iff nn_integral_multc[symmetric]
intro!: arg_cong2[where f="(+)"] nn_integral_cong ac_simps
split: split_indicator)
qed (auto intro!: order_continuous_intros sup_continuous_mono lfp_upperbound
simp: bot_ennreal split: split_indicator)
also have "lfp (?F (HLD {t})) s = emeasure (T s) {x∈space (T s). (HLD (-{t}) suntil HLD {t}) x}"
by (rule emeasure_suntil_disj[symmetric]) (auto simp: HLD_iff)
finally show ?thesis
qed

lemma AE_suntil:
assumes [measurable]: "Measurable.pred S P"
shows "(AE x in T s. (not (HLD {t}) suntil (HLD {t} aand nxt P)) x) ⟷
(AE x in T s. ev (HLD {t}) x) ∧ (AE x in T t. P x)"
apply (subst (1 2 3) T.prob_Collect_eq_1[symmetric])
apply simp
apply simp
apply simp
apply (simp_all add: measure_def emeasure_suntil_HLD del: space_T nxt.simps)
apply (auto simp: T.emeasure_eq_measure mult_eq_1)
done

subsection ‹Fairness›

definition fair :: "'s ⇒ 's ⇒ 's stream ⇒ bool" where
"fair s t = alw (ev (HLD {s})) impl alw (ev (HLD {s} aand nxt (HLD {t})))"

lemma AE_T_fair:
assumes "t' ∈ K t"
shows "AE ω in T s. fair t t' ω"
proof -
let ?M = "λP s. emeasure (T s) {ω∈space (T s). P ω}"
let ?t = "HLD {t}" and ?t' = "HLD {t'}"
define N where "N = alw (ev ?t) aand alw (not (?t aand nxt ?t'))"
let ?until = "not ?t suntil (?t aand nxt (not ?t' aand nxt N))"
have N_stl: "⋀ω. N ω ⟹ N (stl ω)"
by (auto simp: N_def)
have [measurable]: "Measurable.pred S N"
unfolding N_def by measurable

let ?c = "pmf (K t) t'"
let ?R = "λx. 1 ⊓ x * (1 - ennreal ?c)"
have "mono ?R"
by (intro monoI mult_right_mono inf_mono) (auto simp: mono_def field_simps )
have "⋀s. ?M N s ≤ gfp ?R"
proof (induction rule: gfp_ordinal_induct[OF ‹mono ?R›])
fix x s assume x: "⋀s. ?M N s ≤ x"
{ fix ω assume "N ω"
then have "ev (HLD {t}) ω" "N ω"
by (auto simp: N_def)
then have "?until ω"
by (induct rule: ev_induct_strong) (auto simp: N_def intro: suntil.intros dest: N_stl) }
then have "?M N s ≤ ?M ?until s"
by (intro emeasure_mono_AE) auto
also have "… = ?M (ev ?t) s * ?M (not ?t' aand nxt N) t"
by (simp_all add: emeasure_suntil_HLD del: nxt.simps space_T)
also have "… ≤ ?M (ev ?t) s * (∫⇧+s'. 1 ⊓ x * indicator (UNIV - {t'}) s' ∂K t)"
by (auto intro!: mult_left_mono nn_integral_mono T.measure_le_1 emeasure_mono
split: split_indicator simp add: x emeasure_Collect_T[of _ t] simp del: space_T)
also have "… ≤ 1 * (∫⇧+s'. 1 ⊓ x * indicator (UNIV - {t'}) s' ∂K t)"
by (intro mult_right_mono T.measure_le_1) simp
finally show "?M N s ≤ 1 ⊓ x * (1 - ennreal ?c)"
by (subst (asm) nn_integral_cmult_indicator) (auto simp: emeasure_Diff emeasure_pmf_single)
qed (auto intro: Inf_greatest)
also
from ‹mono ?R› have "gfp ?R = ?R (gfp ?R)" by (rule gfp_unfold)
then have "gfp ?R ≤ ?R (gfp ?R)" by simp
with assms[THEN pmf_positive] have "gfp ?R ≤ 0"
by (cases "gfp ?R")
(auto simp: top_unique inf_ennreal.rep_eq field_simps mult_le_0_iff ennreal_1[symmetric]
pmf_le_1 ennreal_minus ennreal_mult[symmetric] ennreal_le_iff2 inf_min min_def
simp del: ennreal_1
split: if_split_asm)
finally have "⋀s. AE ω in T s. ¬ N ω"
by (subst AE_iff_measurable[OF _ refl]) (auto intro: antisym simp: le_fun_def)
then have "AE ω in T s. alw (not N) ω"
by (intro AE_T_alw) auto
moreover
{ fix ω assume "alw (ev (HLD {t})) ω"
then have "alw (alw (ev (HLD {t}))) ω"
unfolding alw_alw .
moreover assume "alw (not N) ω"
then have "alw (alw (ev (HLD {t})) impl ev (HLD {t} aand nxt (HLD {t'}))) ω"
unfolding N_def not_alw_iff not_ev_iff de_Morgan_disj de_Morgan_conj not_not imp_conv_disj .
ultimately have "alw (ev (HLD {t} aand nxt (HLD {t'}))) ω"
by (rule alw_mp) }
then have "∀ω. alw (not N) ω ⟶ fair t t' ω"
by (auto simp: fair_def)
ultimately show ?thesis
qed

lemma enabled_imp_trancl:
assumes "alw (HLD B) ω" "enabled s ω"
shows "alw (HLD (acc_on B `` {s})) ω"
proof -
define t where "t = s"
then have "(s, t) ∈ acc_on B"
by auto
moreover note ‹alw (HLD B) ω›
moreover note ‹enabled s ω›[unfolded ‹t == s›[symmetric]]
ultimately show ?thesis
proof (coinduction arbitrary: t ω rule: alw_coinduct)
case stl from this(1,2,3) show ?case
by (auto simp: enabled.simps[of _ ω] alw.simps[of _ ω] HLD_iff
intro!: exI[of _ "shd ω"] rtrancl_trans[of s t])
next
case (alw t ω) then show ?case
by (auto simp: HLD_iff enabled.simps[of _ ω] alw.simps[of _ ω] intro!: rtrancl_trans[of s t])
qed
qed

lemma AE_T_reachable: "AE ω in T s. alw (HLD (acc `` {s})) ω"
using AE_T_enabled
proof eventually_elim
fix ω assume "enabled s ω"
from enabled_imp_trancl[of UNIV, OF _ this]
show "alw (HLD (acc `` {s})) ω"
by (auto simp: HLD_iff[abs_def] all_imp_alw)
qed

lemma AE_T_all_fair: "AE ω in T s. ∀(t,t')∈SIGMA t:UNIV. K t. fair t t' ω"
proof -
let ?Rn = "SIGMA s:(acc `` {s}). K s"
have "AE ω in T s. ∀(t,t')∈?Rn. fair t t' ω"
proof (subst AE_ball_countable)
show "countable ?Rn"
by (intro countable_SIGMA countable_rtrancl[OF countable_Image]) (auto simp: Image_def)
qed (auto intro!: AE_T_fair)
then show ?thesis
using AE_T_reachable
proof (eventually_elim, safe)
fix ω t t' assume "∀(t,t')∈?Rn. fair t t' ω" "t' ∈ K t" and alw: "alw (HLD (acc `` {s})) ω"
moreover
{ assume "t ∉ acc `` {s}"
then have "alw (not (HLD {t})) ω"
by (intro alw_mono[OF alw]) (auto simp: HLD_iff)
then have "not (alw (ev (HLD {t}))) ω"
unfolding not_alw_iff not_ev_iff by auto
then have "fair t t' ω"
unfolding fair_def by auto }
ultimately show "fair t t' ω"
by auto
qed
qed

lemma fair_imp: assumes "fair t t' ω" "alw (ev (HLD {t})) ω" shows "alw (ev (HLD {t'})) ω"
proof -
{ fix ω assume "ev (HLD {t} aand nxt (HLD {t'})) ω" then have "ev (HLD {t'}) ω"
by induction auto }
with assms show ?thesis
by (auto simp: fair_def elim!: alw_mp intro: all_imp_alw)
qed

lemma AE_T_ev_HLD:
assumes exiting: "⋀t. (s, t) ∈ acc_on (-B) ⟹ ∃t'∈B. (t, t') ∈ acc"
assumes fin: "finite (acc_on (-B) `` {s})"
shows "AE ω in T s. ev (HLD B) ω"
using AE_T_all_fair AE_T_enabled
proof eventually_elim
fix ω assume fair: "∀(t, t')∈(SIGMA s:UNIV. K s). fair t t' ω" and "enabled s ω"

show "ev (HLD B) ω"
proof (rule ccontr)
assume "¬ ev (HLD B) ω"
then have "alw (HLD (- B)) ω"
from enabled_imp_trancl[OF this ‹enabled s ω›]
have "alw (HLD (acc_on (-B) `` {s})) ω"
from pigeonhole_stream[OF this fin]
obtain t where "(s, t) ∈ acc_on (-B)" "alw (ev (HLD {t})) ω"
by auto
from exiting[OF this(1)] obtain t' where "(t, t') ∈ acc" "t' ∈ B"
by auto
from this(1) have "alw (ev (HLD {t'})) ω"
proof induction
case (step u w) then show ?case
using fair fair_imp[of u w ω] by auto
qed fact
{ assume "ev (HLD {t'}) ω" then have "ev (HLD B) ω"
by (rule ev_mono) (auto simp: HLD_iff ‹t' ∈ B›) }
then show False
using ‹alw (ev (HLD {t'})) ω› ‹¬ ev (HLD B) ω› by auto
qed
qed

lemma AE_T_ev_HLD':
assumes exiting: "⋀s. s ∉ X ⟹ ∃t∈X. (s, t) ∈ acc"
assumes fin: "finite (-X)"
shows "AE ω in T s. ev (HLD X) ω"
proof (rule AE_T_ev_HLD)
show "⋀t. (s, t) ∈ acc_on (- X) ⟹ ∃t'∈X. (t, t') ∈ acc"
using exiting by (auto elim: rtrancl.cases)
have "acc_on (- X) `` {s} ⊆ -X ∪ {s}"
by (auto elim: rtrancl.cases)
with fin show "finite (acc_on (- X) `` {s})"
by (auto dest: finite_subset )
qed

lemma AE_T_max_sfirst:
assumes [measurable]: "Measurable.pred S X"
assumes AE: "AE ω in T c. sfirst X (c ## ω) < ∞" and "0 < e"
shows "∃N::nat. 𝒫(ω in T c. N < sfirst X (c ## ω)) < e" (is "∃N. ?P N < e")
proof -
have "?P ⇢ measure (T c) (⋂N::nat. {bT ∈ space (T c). N < sfirst X (c ## bT)})"
using dual_order.strict_trans enat_ord_simps(2)
by (intro T.finite_Lim_measure_decseq) (force simp: decseq_Suc_iff simp del: enat_ord_simps)+
also have "measure (T c) (⋂N::nat. {bT ∈ space (T c). N < sfirst X (c ## bT)}) =
𝒫(bT in T c. sfirst X (c ## bT) = ∞)"
by (auto simp del: not_infinity_eq intro!: arg_cong[where f="measure (T c)"])
(metis less_irrefl not_infinity_eq)
also have "𝒫(bT in T c. sfirst X (c ## bT) = ∞) = 0"
using AE by (intro T.prob_eq_0_AE) auto
finally have "∃N. ∀n≥N. norm (?P n - 0) < e"
using ‹0 < e› by (rule LIMSEQ_D)
then show ?thesis
by (auto simp: measure_nonneg)
qed

subsection ‹First Hitting Time›

lemma nn_integral_sfirst_finite':
assumes "s ∉ H"
assumes [simp]: "finite (acc_on (-H) `` {s})"
assumes until: "AE ω in T s. ev (HLD H) ω"
shows "(∫⇧+ ω. sfirst (HLD H) ω ∂T s) ≠ ∞"
proof -
have R_ne[simp]: "acc_on (-H) `` {s} ≠ {}"
by auto
have [measurable]: "H ∈ sets (count_space UNIV)"
by simp

let ?Pf = "λn t. 𝒫(ω in T t. enat n < sfirst (HLD H) (t ## ω))"
have Pf_mono: "⋀N n t. N ≤ n ⟹ ?Pf n t ≤ ?Pf N t"
by (auto intro!: T.finite_measure_mono simp del: enat_ord_code(1) simp: enat_ord_code(1)[symmetric])

have not_H: "⋀t. (s, t) ∈ acc_on (-H) ⟹ t ∉ H"
using ‹s ∉ H› by (auto elim: rtrancl.cases)

have "∀⇩F n in sequentially. ∀t∈acc_on (-H)``{s}. ?Pf n t < 1"
proof (safe intro!: eventually_ball_finite)
fix t assume "(s, t) ∈ acc_on (-H)"
then have "AE ω in T t. sfirst (HLD H) (t ## ω) < ∞"
unfolding sfirst_finite
proof induction
case (step t u) with step.IH show ?case
by (subst (asm) AE_T_iff) (auto simp: ev_Stream not_H)
qed (simp add: ev_Stream eventually_frequently_simps until)
from AE_T_max_sfirst[OF _ this, of 1]
obtain N where "?Pf N t < 1" by auto
with Pf_mono[of N] show "∀⇩F n in sequentially. ?Pf n t < 1"
by (auto simp: eventually_sequentially intro: le_less_trans)
qed simp
then obtain n where "⋀t. (s, t) ∈ acc_on (-H) ⟹ ?Pf n t < 1"
by (auto simp: eventually_sequentially)
moreover define d where "d = Max (?Pf n ` acc_on (-H) `` {s})"
ultimately have d: "0 ≤ d" "d < 1" "⋀t. (s, t) ∈ acc_on (-H) ⟹ ?Pf (Suc n) t ≤ d"
using Pf_mono[of n "Suc n"] by (auto simp: Max_ge_iff measure_nonneg)

let ?F = "λF ω. if shd ω ∈ H then 0 else F (stl ω) + 1 :: ennreal"
have "sup_continuous ?F"
by (intro order_continuous_intros)
then have "mono ?F"
by (rule sup_continuous_mono)
have lfp_nonneg[simp]: "⋀ω. 0 ≤ lfp ?F ω"
by (subst lfp_unfold[OF ‹mono ?F›]) auto

let ?I = "λF s. ∫⇧+t. (if t ∈ H then 0 else F t + 1) ∂K s"
have "sup_continuous ?I"
by (intro order_continuous_intros) auto
then have "mono ?I"
by (rule sup_continuous_mono)

define p where "p = Suc n / (1 - d)"
have p: "p = Suc n + d * p"
unfolding p_def using d(1,2) by (auto simp: field_simps)
have [simp]: "0 ≤ p"
using d(1,2) by (auto simp: p_def)

have "(∫⇧+ ω. sfirst (HLD H) ω ∂T s) = (∫⇧+ ω. lfp ?F ω ∂T s)"
proof (intro nn_integral_cong_AE)
show "AE x in T s. sfirst (HLD H) x = lfp ?F x"
using until
proof eventually_elim
fix ω assume "ev (HLD H) ω" then show "sfirst (HLD H) ω = lfp ?F ω"
by (induction rule: ev_induct_strong;
subst lfp_unfold[OF ‹mono ?F›], simp add: HLD_iff[abs_def] ac_simps max_absorb2)
qed
qed
also have "… = lfp (?I^^Suc n) s"
unfolding lfp_funpow[OF ‹mono ?I›]
by (subst nn_integral_T_lfp)
(auto simp: nn_integral_add max_absorb2 intro!: order_continuous_intros)
also have "lfp (?I^^Suc n) t ≤ p" if "(s, t) ∈ acc_on (-H)" for t
using that
proof (induction arbitrary: t rule: lfp_ordinal_induct[of "?I^^Suc n"])
case (step S)
have "(?I^^i) S t ≤ i + ?Pf i t * ennreal p" for i
using step(3)
proof (induction i arbitrary: t)
case 0 then show ?case
using T.prob_space step(1)
by (auto simp add: zero_ennreal_def[symmetric] not_H zero_enat_def[symmetric] one_ennreal_def[symmetric])
next
case (Suc i)
then have "t ∉ H"
by (auto simp: not_H)
from Suc.prems have "⋀t'. t' ∈ K t ⟹ t' ∉ H ⟹ (s, t') ∈ acc_on (-H)"
by (rule rtrancl_into_rtrancl) (insert Suc.prems, auto dest: not_H)
then have "(?I ^^ Suc i) S t ≤ ?I (λt. i + ennreal (?Pf i t) * p) t"
by (auto simp: AE_measure_pmf_iff simp del: sfirst_eSuc space_T
also have "… ≤ (∫⇧+ t. ennreal (Suc i) + ennreal 𝒫(ω in T t. enat i < sfirst (HLD H) (t ## ω)) * p ∂K t)"
by (intro nn_integral_mono) auto
also have "… ≤ Suc i + ennreal (?Pf (Suc i) t) * p"
unfolding T.emeasure_eq_measure[symmetric]
by (subst (2) emeasure_Collect_T)
(auto simp: ‹t ∉ H› eSuc_enat[symmetric] nn_integral_add nn_integral_multc ennreal_of_nat_eq_real_of_nat)
finally show ?case
qed
then have "(?I^^Suc n) S t ≤ Suc n + ?Pf (Suc n) t * ennreal p" .
also have "… ≤ p"
using d step by (subst (2) p) (auto intro!: mult_right_mono simp: ennreal_of_nat_eq_real_of_nat ennreal_mult)
finally show ?case .
qed (auto simp: SUP_least intro!: mono_pow ‹mono ?I› simp del: funpow.simps)
finally show ?thesis
unfolding p_def by (auto simp: top_unique)
qed

lemma nn_integral_sfirst_finite:
assumes [simp]: "finite (acc_on (-H) `` {s})"
assumes until: "AE ω in T s. ev (HLD H) ω"
shows "(∫⇧+ ω. sfirst (HLD H) (s ## ω) ∂T s) ≠ ∞"
proof cases
assume "s ∉ H" then show ?thesis

lemma prob_T:
assumes P: "Measurable.pred S P"
shows "𝒫(ω in T s. P ω) = (∫t. 𝒫(ω in T t. P (t ## ω)) ∂K s)"
using emeasure_Collect_T[OF P, of s] unfolding T.emeasure_eq_measure
by (subst (asm) nn_integral_eq_integral)
(auto intro!: measure_pmf.integrable_const_bound[where B=1])

lemma T_subprob[measurable]: "T ∈ measurable (measure_pmf I) (subprob_algebra S)"
by (auto intro!: space_bind simp: space_subprob_algebra) unfold_locales

subsection ‹Markov chain with Initial Distribution›

definition T' :: "'s pmf ⇒ 's stream measure" where
"T' I = bind I (λs. distr (T s) S ((##) s))"

lemma distr_Stream_subprob:
"(λs. distr (T s) S ((##) s)) ∈ measurable (measure_pmf I) (subprob_algebra S)"
apply (intro measurable_distr2[OF _ T_subprob])
apply (subst measurable_cong_sets[where M'="count_space UNIV ⨂⇩M S" and N'=S])
apply (rule sets_pair_measure_cong)
apply auto
done

lemma sets_T': "sets (T' I) = sets S"

lemma prob_space_T': "prob_space (T' I)"
unfolding T'_def
proof (rule measure_pmf.prob_space_bind)
show "AE s in I. prob_space (distr (T s) S ((##) s))"
by (intro AE_measure_pmf_iff[THEN iffD2] ballI T.prob_space_distr) simp
qed (rule distr_Stream_subprob)

lemma AE_T':
assumes [measurable]: "Measurable.pred S P"
shows "(AE x in T' I. P x) ⟷ (∀s∈I. AE x in T s. P (s ## x))"
unfolding T'_def by (simp add: AE_bind[OF distr_Stream_subprob] AE_measure_pmf_iff AE_distr_iff)

lemma emeasure_T':
assumes [measurable]: "X ∈ sets S"
shows "emeasure (T' I) X = (∫⇧+s. emeasure (T s) {ω∈space S. s ## ω ∈ X} ∂I)"
unfolding T'_def
by (simp add: emeasure_bind[OF _ distr_Stream_subprob] emeasure_distr vimage_def Int_def conj_ac)

lemma prob_T':
assumes [measurable]: "Measurable.pred S P"
shows "𝒫(x in T' I. P x) = (∫s. 𝒫(x in T s. P (s ## x)) ∂I)"
proof -
interpret T': prob_space "T' I" by (rule prob_space_T')
show ?thesis
using emeasure_T'[of "{x∈space (T' I). P x}" I]
unfolding T'.emeasure_eq_measure T.emeasure_eq_measure sets_eq_imp_space_eq[OF sets_T']
apply simp
apply (subst (asm) nn_integral_eq_integral)
apply (auto intro!: measure_pmf.integrable_const_bound[where B=1] integral_cong arg_cong2[where f=measure]
simp: AE_measure_pmf measure_nonneg space_stream_space)
done
qed

lemma T_eq_T': "T s = T' (K s)"
proof (rule measure_eqI)
fix X assume X: "X ∈ sets (T s)"
then have [measurable]: "X ∈ sets S"
by simp
have X_eq: "X = {x∈space (T s). x ∈ X}"
using sets.sets_into_space[OF X] by auto
show "emeasure (T s) X = emeasure (T' (K s)) X"
apply (subst X_eq)
apply (subst emeasure_Collect_T, simp)
apply (subst emeasure_T', simp)
apply simp
done

lemma T_eq_bind: "T s = (measure_pmf (K s) ⤜ (λt. distr (T t) S ((##) t)))"
by (subst T_eq_T') (simp add: T'_def)

lemma T_split:
"T s = (T s ⤜ (λω. distr (T ((s ## ω) !! n)) S (λω'. stake n ω @- ω')))"
proof (induction n arbitrary: s)
case 0 then show ?case
apply (simp add: distr_cong[OF refl sets_T[symmetric, of s] refl])
apply (subst bind_const')
apply unfold_locales
..
next
case (Suc n)
let ?K = "measure_pmf (K s)" and ?m = "λn ω ω'. stake n ω @- ω'"
note sets_stream_space_cong[simp, measurable_cong]

have "T s = (?K ⤜ (λt. distr (T t) S ((##) t)))"
by (rule T_eq_bind)
also have "… = (?K ⤜ (λt. distr (T t ⤜ (λω. distr (T ((t ## ω) !! n)) S (?m n ω))) S ((##) t)))"
unfolding Suc[symmetric] ..
also have "… = (?K ⤜ (λt. T t ⤜ (λω. distr (distr (T ((t ## ω) !! n)) S (?m n ω)) S ((##) t))))"
by (simp add: distr_bind[where K=S, OF measurable_distr2[where M=S]] space_stream_space)
also have "… = (?K ⤜ (λt. T t ⤜ (λω. distr (T ((t ## ω) !! n)) S (?m (Suc n) (t ## ω)))))"
by (simp add: distr_distr space_stream_space comp_def)
also have "… = (?K ⤜ (λt. distr (T t) S ((##) t) ⤜ (λω. distr (T (ω !! n)) S (?m (Suc n) ω))))"
by (simp add: space_stream_space bind_distr[OF _ measurable_distr2[where M=S]] del: stake.simps)
also have "… = (T s ⤜ (λω. distr (T (ω !! n)) S (?m (Suc n) ω)))"
unfolding T_eq_bind[of s]
by (subst bind_assoc[OF measurable_distr2[where M=S] measurable_distr2[where M=S], OF _ T_subprob])
finally show ?case
by simp
qed

lemma nn_integral_T_split:
assumes f[measurable]: "f ∈ borel_measurable S"
shows "(∫⇧+ω. f ω ∂T s) = (∫⇧+ω. (∫⇧+ω'. f (stake n ω @- ω') ∂T ((s ## ω) !! n)) ∂T s)"
apply (subst T_split[of s n])
apply (simp add: nn_integral_bind[OF f measurable_distr2[where M=S]])
apply (subst nn_integral_distr)
done

lemma emeasure_T_split:
assumes P[measurable]: "Measurable.pred S P"
shows "emeasure (T s) {ω∈space (T s). P ω} =
(∫⇧+ω. emeasure (T ((s ## ω) !! n)) {ω'∈space (T ((s ## ω) !! n)). P (stake n ω @- ω')} ∂T s)"
apply (subst T_split[of s n])
apply (subst emeasure_bind[OF _ measurable_distr2[where M=S]])
apply (subst emeasure_distr)
apply simp_all
done

lemma prob_T_split:
assumes P[measurable]: "Measurable.pred S P"
shows "𝒫(ω in T s. P ω) = (∫ω. 𝒫(ω' in T ((s ## ω) !! n). P (stake n ω @- ω')) ∂T s)"
using emeasure_T_split[OF P, of s n]
unfolding T.emeasure_eq_measure
by (subst (asm) nn_integral_eq_integral)
(auto intro!: T.integrable_const_bound[where B=1] measure_measurable_subprob_algebra2[where N=S]
simp: T.emeasure_eq_measure SIGMA_Collect_eq)

lemma enabled_imp_alw:
"(⋃s∈X. set_pmf (K s)) ⊆ X ⟹ x ∈ X ⟹ enabled x ω ⟹ alw (HLD X) ω"
proof (coinduction arbitrary: ω x)
case alw then show ?case
unfolding enabled.simps[of _ ω]
by (auto simp: HLD_iff)
qed

lemma alw_HLD_iff_sconst:
"alw (HLD {x}) ω ⟷ ω = sconst x"
proof
assume "alw (HLD {x}) ω" then show "ω = sconst x"
by (coinduction arbitrary: ω) (auto simp: HLD_iff)
qed (auto simp: alw_sconst HLD_iff)

lemma enabled_iff_sconst:
assumes [simp]: "set_pmf (K x) = {x}" shows "enabled x ω ⟷ ω = sconst x"
proof
assume "enabled x ω" then show "ω = sconst x"
by (coinduction arbitrary: ω) (auto elim: enabled.cases)
next
assume "ω = sconst x" then show "enabled x ω"
by (coinduction arbitrary: ω) auto
qed

lemma AE_sconst:
assumes [simp]: "set_pmf (K x) = {x}"
shows "(AE ω in T x. P ω) ⟷ P (sconst x)"
proof -
have "(AE ω in T x. P ω) ⟷ (AE ω in T x. P ω ∧ ω = sconst x)"
using AE_T_enabled[of x] by (simp add: enabled_iff_sconst)
also have "… = (AE ω in T x. P (sconst x) ∧ ω = sconst x)"
by (simp del: AE_conj_iff cong: rev_conj_cong)
also have "… = (AE ω in T x. P (sconst x))"
using AE_T_enabled[of x] by (simp add: enabled_iff_sconst)
finally show ?thesis
by simp
qed

lemma ev_eq_lfp: "ev P = lfp (λF ω. P ω ∨ (¬ P ω ∧ F (stl ω)))"
unfolding ev_def by (intro antisym lfp_mono) blast+

lemma INF_eq_zero_iff_ennreal: "((⨅i∈A. f i) = (0::ennreal)) = (∀x>0. ∃i∈A. f i < x)"
using INF_eq_bot_iff[where 'a=ennreal] unfolding bot_ennreal_def zero_ennreal_def by auto

lemma inf_continuous_cmul:
fixes c :: ennreal
assumes f: "inf_continuous f" and c: "c < ⊤"
shows "inf_continuous (λx. c * f x)"
proof (rule inf_continuous_compose[OF _ f], clarsimp simp add: inf_continuous_def)
fix M :: "nat ⇒ ennreal" assume M: "decseq M"
show "c * (⨅i. M i) = (⨅i. c * M i)"
using M
by (intro LIMSEQ_unique[OF ennreal_tendsto_cmult[OF c] LIMSEQ_INF] LIMSEQ_INF)
(auto simp: decseq_def mult_left_mono)
qed

lemma AE_T_ev_HLD_infinite:
fixes X :: "'s set" and r :: real
assumes "r < 1"
assumes r: "⋀x. x ∈ X ⟹ measure (K x) X ≤ r"
shows "AE ω in T x. ev (HLD (- X)) ω"
proof -
{ fix x assume "x ∈ X"
have "0 ≤ r" using r[OF ‹x ∈ X›] measure_nonneg[of "K x" X] by (blast  intro: order.trans)
define P where "P F x = ∫⇧+y. indicator X y * (F y ⊓ 1) ∂K x" for F x
have [measurable]: "X ∈ sets (count_space UNIV)" by auto
have bnd: "(∫⇧+ y. indicator X y * (f y ⊓ 1) ∂K x) ≤ 1" for x f
by (intro measure_pmf.nn_integral_le_const AE_pmfI) (auto split: split_indicator)
have "emeasure (T x) {ω∈space (T x). alw (HLD X) ω} =
emeasure (T x) {ω∈space (T x). gfp (λF ω. shd ω ∈ X ∧ F (stl ω)) ω}"
also have "… = gfp P x"
apply (rule emeasure_gfp)
apply (auto intro!: order_continuous_intros inf_continuous_cmul split: split_indicator simp: P_def)
subgoal for x f using bnd[of x f] by (auto simp: top_unique)
subgoal for P x
apply (subst T_eq_bind)
apply (subst emeasure_bind[where N=S])
apply simp
apply (rule measurable_distr2[where M=S])
apply (auto intro: T_subprob[THEN measurable_space] intro!: nn_integral_cong_AE AE_pmfI
simp: emeasure_distr split: split_indicator)
apply (simp_all add: space_stream_space T.emeasure_le_1 inf.absorb1)
done
apply (intro le_funI)
apply (subst nn_integral_indicator[symmetric])
apply simp
apply (intro nn_integral_mono)
apply (auto split: split_indicator)
done
also have "… ≤ (INF n. ennreal r ^ n)"
proof (intro INF_greatest)
have mono_P: "mono P"
by (force simp: le_fun_def mono_def P_def intro!: nn_integral_mono intro: le_infI1 split: split_indicator)
fix n show "gfp P x ≤ ennreal r ^ n"
using ‹x ∈ X›
proof (induction n arbitrary: x)
case 0 then show ?case
by (subst gfp_unfold[OF mono_P]) (auto intro!: measure_pmf.nn_integral_le_const AE_pmfI split: split_indicator simp: P_def)
next
case (Suc n x)
have "gfp P x = P (gfp P) x" by (subst gfp_unfold[OF mono_P]) rule
also have "… ≤ P (λx. ennreal r ^ n) x"
unfolding P_def[of _ x] by (auto intro!: nn_integral_mono le_infI1 Suc split: split_indicator)
also have "… ≤ ennreal r ^ (Suc n)"
using Suc by (auto simp: P_def nn_integral_multc measure_pmf.emeasure_eq_measure intro!: mult_mono ennreal_leI r)
finally show ?case .
qed
qed
also have "… = 0"
unfolding ennreal_power[OF ‹0 ≤ r›]
proof (intro LIMSEQ_unique[OF LIMSEQ_INF])
show "decseq (λi. ennreal (r ^ i))"
using ‹0 ≤ r› ‹r < 1› by (auto intro!: ennreal_leI power_decreasing simp: decseq_def)
have "(λi. ennreal (r ^ i)) ⇢ ennreal 0"
using ‹0 ≤ r› ‹r < 1› by (intro tendsto_ennrealI LIMSEQ_power_zero) auto
then show "(λi. ennreal (r ^ i)) ⇢ 0" by simp
qed
finally have *: "emeasure (T x) {ω∈space (T x). alw (HLD X) ω} = 0" by auto
have "AE ω in T ```