Theory Kolmogorov_Chentsov

(* Title:      Kolmogorov_Chentsov/Kolmogorov_Chentsov.thy
   Author:     Christian Pardillo Laursen, University of York
*)

section "The Kolomgorov-Chentsov theorem"

theory Kolmogorov_Chentsov
  imports Stochastic_Processes Holder_Continuous Dyadic_Interval Measure_Convergence
begin

subsection "Supporting lemmas"

text ‹ The main contribution of this file is the Kolmogorov-Chentsov theorem: given a stochastic
  process that satisfies some continuity properties, we can construct a H{\"o}lder continuous modification.
  We first prove some auxiliary lemmas before moving on to the main construction. ›

text ‹ Klenke 5.11: Markov inequality. Compare with @{thm nn_integral_Markov_inequality}

lemma nn_integral_Markov_inequality_extended:
  fixes f :: "real  ennreal" and ε :: real and X :: "'a  real"
  assumes mono: "mono_on (range X  {0<..}) f"
    and finite: "x. f x < "
    and e: "ε > 0" "f ε > 0"
    and [measurable]: "X  borel_measurable M"
  shows "emeasure M {p  space M. (X p)  ε}  (+ x. f (X x) M) / f ε"
proof -
  have f_eq: "f = (λx. ennreal (enn2real (f x)))"
    using finite by simp
  have "mono_on (range X) (λx. enn2real (f x))"
    apply (intro mono_onI)
    using mono[THEN mono_onD] finite by (simp add: enn2real_mono)
  then have "f  borel_measurable (restrict_space borel (range X))"
    apply (subst f_eq)
    apply (intro measurable_compose[where f="λx. enn2real (f x)" and g=ennreal])
    using borel_measurable_mono_on_fnc apply blast
    apply simp
    done
  then have "(λx. f (X x))  borel_measurable M"
    apply (intro measurable_compose[where g=f and f=X and N="restrict_space borel (range X)"])
     apply (simp_all add: measurable_restrict_space2)
    done
  then have "{x  space M. f (X x)  f ε}  sets M"
    by measurable
  then have "f ε * emeasure M {x  space M. X x  ε}  (+x{x  space M. f ε  f (X x)}. f ε M)"
    apply (simp add: nn_integral_cmult_indicator)
    using e mono_onD[OF mono] zero_le apply (blast intro: mult_left_mono emeasure_mono)
    done
  also have "...  (+x{x  space M. f ε  f (X x)}. f (X x) M)"
    apply (rule nn_integral_mono)
    subgoal for x
      apply (cases "f ε  f (X x)")
      using ennreal_leI by auto
    done
  also have "...  + x. f (X x) M"
    by (simp add: nn_integral_mono indicator_def)
  finally have "emeasure M {p  space M. ε  X p} * f ε / f ε  (+ x. f (X x) M) / f ε"
    by (simp add: divide_right_mono_ennreal field_simps)
  then show ?thesis
    using mult_divide_eq_ennreal finite[of "ε"] e(2) by simp
qed

lemma nn_integral_Markov_inequality_extended_rnv:
  fixes f :: "real  real" and ε :: real and X :: "'a  'b :: real_normed_vector"
  assumes [measurable]: "X  borel_measurable M"
    and mono: "mono_on {0..} f"
    and e: "ε > 0" "f ε > 0"
  shows "emeasure M {p  space M. norm (X p)  ε}  (+ x. f (norm (X x)) M) / f ε"
  apply (rule nn_integral_Markov_inequality_extended)
  using mono ennreal_leI unfolding mono_on_def apply force
     apply (simp_all add: e)
  done

subsection "Kolmogorov-Chentsov"
text ‹ Klenke theorem 21.6 - Kolmorogov-Chentsov ›

locale Kolmogorov_Chentsov = 
  fixes X :: "(real, 'a, 'b :: polish_space) stochastic_process"
    and a b C γ :: real
  assumes index[simp]: "proc_index X = {0..}"
    and target_borel[simp]: "proc_target X = borel"
    and gt_0: "a > 0" "b > 0" "C > 0"
    and b_leq_a: "b  a"
    and gamma: "γ  {0<..<b/a}"
    and expectation: "s t. s  0; t  0 
          (+ x. dist (X t x) (X s x) powr a proc_source X)  C * dist t s powr (1+b)"
begin

lemma gamma_0_1[simp]:"γ  {0<..1}"
  using gt_0 b_leq_a gamma
  by (metis divide_less_eq_1_pos divide_self greaterThanAtMost_iff 
      greaterThanLessThan_iff nless_le order_less_trans)

lemma gamma_gt_0[simp]: "γ > 0"
  using gamma greaterThanLessThan_iff by blast

lemma gamma_le_1[simp]: "γ  1"
  using gamma_0_1 by auto

abbreviation "source  proc_source X"

lemma X_borel_measurable[measurable]: "X t  borel_measurable source" for t
  by (metis random_process target_borel)

lemma markov: "𝒫(x in source. ε  dist (X t x) (X s x))  (C * dist t s powr (1 + b)) / ε powr a"
  if "s  0" "t  0" "ε > 0" for s t ε
proof -
  let ?inc = "λx. dist (X t x) (X s x) powr a"
  have "emeasure source {x  space source. ε  dist (X t x) (X s x)}
    integralN source ?inc / ε powr a"
    apply (rule nn_integral_Markov_inequality_extended)
    using that(1,2) apply measurable
    subgoal using gt_0(1) imageE powr_mono2 by (auto intro: mono_onI)
    using that apply simp_all
    done
  also have "...  (C * dist t s powr (1 + b)) / ennreal (ε powr a)"
    apply (rule divide_right_mono_ennreal)
    using expectation[OF that(1,2)] ennreal_leI by simp
  finally have "emeasure source {x  space source. ε  dist (X t x) (X s x)}
      (C * dist t s powr (1 + b)) / ε powr a"
    using that(3) divide_ennreal gt_0(3) by simp
  moreover have "C * dist t s powr (1 + b) / ε powr a  0"
    using gt_0(3) by auto
  ultimately show ?thesis
    by (simp add: proc_source.emeasure_eq_measure)
qed

lemma conv_in_prob:
  assumes "t  0"
  shows "tendsto_measure (proc_source X) X (X t) (at t within {0..})"
proof -
  {
    fix p ε :: real assume "0 < p" "0 < ε"
    let ?q = "(p * ε powr a / C) powr (1/(1+b))"
    have "0 < ?q"
      using 0 < p gt_0(3) 0 < ε by simp
    have p_eq: "p = (C * ?q powr (1 + b)) / ε powr a"
      using gt_0 0 < ?q 0 < p by (simp add: field_simps powr_powr)
    have "0 < dist r t  dist r t < ?q  dist 𝒫(x in source. ε  dist (X t x) (X r x)) 0  p"
      if "r  {0..}" for r
    proof safe
      assume "0 < dist r t" "dist r t < ?q"
      have "0  r"
        using that by auto
      from dist r t < ?q have "C * dist r t powr (1 + b) / ε powr a  p"
        apply (subst p_eq)
        using gt_0(2) gt_0(3) apply (simp add: divide_le_cancel powr_mono2)
        done
      then show "dist 𝒫(x in source. ε  dist (process X t x) (process X r x)) 0  p"
        using markov[OF 0  r assms 0 < ε] by (simp add: dist_commute)
    qed
    then have "d>0. r{0..}. 0 < dist r t  dist r t < d 
                dist 𝒫(x in source. ε  dist (X r x) (X t x)) 0  p"
      apply (intro exI[where x="?q"])
      apply (subst(3) dist_commute)
      using 0 < p gt_0(3) 0 < ε dist_commute by fastforce
  } then show ?thesis
    by (simp add: finite_measure.tendsto_measure_leq, safe, intro Lim_withinI)
qed

lemma conv_in_prob_finite:
  assumes "t  0"
  shows "tendsto_measure (proc_source X) X (X t) (at t within {0..T})"
proof -
  have "at t within {0..T}  at t within {0..}"
    by (simp add: at_le)
  then show ?thesis
    apply (rule tendsto_measure_mono)
    using assms by (rule conv_in_prob)
qed

lemma incr: "𝒫(x in source. 2 powr (- γ * n)  dist (X ((k - 1) * 2 powr - n) x) (X (k * 2 powr - n) x))
          C * 2 powr (-n * (1+b-a*γ))"
  if "k  1" "n  0" for k n
proof -
  have "𝒫(x in source. 2 powr (- γ * n)  dist (X ((k - 1) * 2 powr - n) x) (X (k * 2 powr - n) x))
        C * dist ((k - 1) * 2 powr - n) (k * 2 powr - n) powr (1 + b) / (2 powr (- γ * n)) powr a"
    using that by (auto intro: markov)
  also have "... = C * 2 powr (- n - b * n) / 2 powr (- γ * n * a)"
    by (auto simp: dist_real_def powr_powr field_simps)
  also have "... =  C * 2 powr (-n * (1+b-a*γ))"
    by (simp add: field_simps powr_add[symmetric])
  finally show ?thesis .
qed

end

text ‹ In order to construct the modification of $X$, it suffices to construct a modification of $X$ 
  on $\{0..T\}$ for all finite $T$, from which we construct the modification on $\{0..\}$ via a countable
  union. ›

locale Kolmogorov_Chentsov_finite = Kolmogorov_Chentsov +
  fixes T :: real
  assumes zero_le_T: "0 < T"
begin

text ‹ $A_n$ will characterise the set of states with increments that exceed the bounds required for
  H{\"o}lder continuity. As $n \longrightarrow \infty$, this approaches the set of states for which $X$ is not
  H{\"o}lder continuous. We define $N$ as this limit, and show that $N$ is a null set. On $\omega \in \Omega - N$,
  we show that $X(\omega)$ is H{\"o}lder continuous (and therefore uniformly continuious) on the dyadic
   rationals, and construct a modification by taking the continuous extension on the reals. ›

definition "A  λn. if 2 ^ n * T < 1 then space source else 
  {x  space source. 
    Max {dist (X (real_of_int (k - 1) * 2 powr - real n) x) (X (real_of_int k * 2 powr - real n) x)
       | k. k  {1..2^n * T}}  2 powr (-γ * real n)}"

abbreviation "B  λn. (m. A (m + n))"

abbreviation "N  (range B)"

lemma A_geq: "2 ^ n * T  1  A n = {x  space source. 
    Max {dist (X (real_of_int (k - 1) * 2 powr - real n) x) (X (real_of_int k * 2 powr - real n) x)
   | k. k  {1..2^n * T}}  2 powr (-γ * real n)}" for n
  by (simp add: A_def)

lemma A_measurable[measurable]: "A n  sets source"
  unfolding A_def apply (cases "2 ^ n * T < 1")
   apply simp
  apply (simp only: if_False)
  apply measurable
  done

lemma emeasure_A_leq:
  fixes n :: nat
  assumes [simp]: "2^n * T  1"
  shows "emeasure source (A n)  C * T * 2 powr (- n * (b - a * γ))"
proof -
  have nonempty: "{1..2^n * T}  {}"
    using assms by fastforce
  have finite: "finite {1..2^n * T}"
    by simp
  have "emeasure source (A n)  emeasure source (k  {1..2^n * T}.
    {xspace source. dist (X (real_of_int (k - 1) * 2 powr - real n) x) (X (real_of_int k * 2 powr - real n) x)  2 powr (- γ * real n)})"
    (is "emeasure source (A n)  emeasure source ?R")
  proof (rule emeasure_mono, intro subsetI)
    fix x assume *: "x  A n"
    from * have in_space: "x  space source"
      using A_measurable sets.sets_into_space by blast
    from * have "2 powr (- γ * real n)  Max {dist (X (real_of_int (k - 1) * 2 powr - real n) x) (X (real_of_int k * 2 powr - real n) x) |k. k  {1..2 ^ n * T}}"
      using A_geq assms by blast
    then have "k  {1..2 ^ n * T}. 2 powr (- γ * real n)  dist (X (real_of_int (k - 1) * 2 powr - real n) x) (X (real_of_int k * 2 powr - real n) x)"
      apply (simp only: setcompr_eq_image)
      apply (rule Max_finite_image_ex[where P="λx. 2 powr (- γ * real n)  x", OF finite nonempty])
      apply (metis Collect_mem_eq)
      done
    then show "x  ?R"
      using in_space by simp
  next
    show "?R  sets source"
      by measurable
  qed
  also have "...  (k{1..2^n * T}. emeasure source 
  {xspace source. dist (X (real_of_int (k - 1) * 2 powr - real n) x) (X (real_of_int k * 2 powr - real n) x)  2 powr (- γ * real n)})"
    apply (rule emeasure_subadditive_finite)
     apply blast
    apply (subst image_subset_iff)
    apply (intro ballI)
    apply measurable
    done
  also have "...  C * 2 powr (- n * (1 + b - a * γ)) * (card {1..2 ^ n * T})"
  proof -
    {
      fix k assume "k  {1..2 ^ n * T}"
      then have "real_of_int k  1"
        by presburger
      then have "𝒫(x in source. 2 powr (- γ * real n)  dist (X (real_of_int (k - 1) * 2 powr - real n) x) (X (real_of_int k * 2 powr - real n) x))
                C * 2 powr (-(real n) * (1+b-a*γ))"
        using incr gamma by force
    } note X = this
    then have "sum (λk. 𝒫(x in source. 2 powr (- γ * real n)  dist (X (real_of_int (k - 1) * 2 powr - real n) x) (X (real_of_int k * 2 powr - real n) x))) 
                      {1..2 ^ n * T}  of_nat (card {1..2 ^ n * T}) * (C * 2 powr (-(real n) * (1+b-a*γ)))"
      by (fact sum_bounded_above)
    then show ?thesis
      using ennreal_leI by (auto simp: proc_source.emeasure_eq_measure mult.commute)
  qed
  also have "...  C * 2 powr (- n * (1 + b - a * γ)) * 2 ^ n * T"
    using nonempty zle_iff_zadd by force
  also have "...  C * 2 powr (- n * (1+b - a * γ)) * 2^n * T"
    by (simp add:ennreal_leI gt_0(3))
  also have "... = C * 1/(2^n) * 2 powr (- n * (b - a * γ)) * 2^n * T"
    apply (intro ennreal_cong)
    apply (simp add: scale_left_imp_eq field_simps)
    by (smt (verit) powr_add powr_realpow)
  also have "... = C * T * 2 powr (- n * (b - a * γ))"
    by (simp add: field_simps)
  finally show ?thesis .
qed

lemma measure_A_leq: 
  assumes "2^n * T  1"
  shows "measure source (A n)  C * T * 2 powr (- n * (b - a * γ))"
  apply (intro measure_leq_emeasure_ennreal)
  subgoal using gt_0(3) zero_le_T by auto
  using emeasure_A_leq apply (simp add: A_geq assms)
  done

lemma summable_A: "summable (λm. measure source (A m))"
proof -
  have "b - a * γ > 0"
    by (metis diff_gt_0_iff_gt gamma greaterThanLessThan_iff gt_0(1) mult.commute pos_less_divide_eq)
  have 1: "2 powr (- real x * (b - a * γ)) = (1 / 2 powr (b - a * γ)) ^ x" for x
    apply (cases "x = 0")
    by (simp_all add: field_simps powr_add[symmetric] powr_realpow[symmetric] powr_powr)
  have 2: "summable (λn. 2 powr (- n * (b - a * γ)))" (is "summable ?C")
  proof -
    have "summable (λn. (1 / 2 powr (b - a * γ)) ^ n)"
      using b - a * γ > 0 by auto
    then show "summable (λx. 2 powr (- real x * (b - a * γ)))"
      using 1 by simp
  qed
  from zero_le_T obtain N where "2^N * T  1"
    by (metis dual_order.order_iff_strict mult.commute one_less_numeral_iff pos_divide_le_eq
        power_one_over reals_power_lt_ex semiring_norm(76) zero_less_numeral zero_less_power)
  then have "n. n  N  2^n * T  1" 
    by (smt (verit, best) 0 < T mult_right_mono power_increasing_iff)
  then have "n. n  N  norm (measure source (A n))  C * T * 2 powr (- n * (b - a * γ))"
    using measure_A_leq by simp
  moreover have "summable (λn. C * T * 2 powr (- n * (b - a * γ)))"
    using 2 summable_mult by simp
  ultimately show ?thesis
    using summable_comparison_test' by fast
qed

lemma lim_B: "(λn. measure source (B n))  0"
proof -        
  have measure_B_le: "measure source (B n)  (m. measure source (A (m + n)))" for n
    apply (rule proc_source.finite_measure_subadditive_countably)
     subgoal by auto
    apply (subst summable_iff_shift)
    using summable_A by blast
  have lim_A: "(λn. (m. measure source (A (m + n))))  0"
    by (fact suminf_exist_split2[OF summable_A])
  have "convergent (λn. measure source (B n))"
  proof (intro Bseq_monoseq_convergent)
    show "Bseq (λn. Sigma_Algebra.measure source (m. A (m + n)))"
      apply (rule BseqI'[where K="measure source ( (range A))"])
      apply (auto intro!: proc_source.finite_measure_mono)
      done
    show "monoseq (λn. Sigma_Algebra.measure source (m. A (m + n)))"
      apply (intro decseq_imp_monoseq[unfolded decseq_def] allI impI proc_source.finite_measure_mono)
       apply (simp_all add: Union_add_subset)
      done
  qed
  then obtain L where lim_B: "(λn. measure source (B n))  L"
    unfolding convergent_def by auto
  then have "L  0"
    by (simp add: LIMSEQ_le_const)
  moreover have "L  0"
    using measure_B_le by (simp add: LIMSEQ_le[OF lim_B lim_A])
  ultimately show ?thesis
    using lim_B by simp
qed

lemma N_null: "N  null_sets source"
proof -
  have "(λn. measure source (B n))  measure source N"
    apply (rule proc_source.finite_Lim_measure_decseq)
    using A_measurable apply fast
    apply (intro monotoneI, simp add: Union_add_subset)
    done
  then have "measure source N = 0"
    using lim_B LIMSEQ_unique by blast
  then show ?thesis
    by (auto simp add: emeasure_eq_ennreal_measure)
qed

lemma notin_N_index:
  assumes "ω  space source - N"
  obtains n0 where "ω  (n. A (n + n0))"
  using assms by blast

context
  fixes ω
  assumes ω: "ω  space source - N"
begin

definition "n0  SOME m. ω  (n. A (n + m))  m > 0"

lemma
  shows n_zero: "ω  (n. A (n + n0))"
    and n_zero_nonzero: "n0 > 0"
proof -
  have "m. ω  (n. A (n + m))"
    using ω by blast
  then have "m. ω  (n. A (n + m))  m > 0"
    by (metis (no_types, lifting) UNIV_I UN_iff add.comm_neutral not_gr_zero zero_less_Suc)
  then have "ω  (n. A (n + n0))  n0 > 0"
    unfolding n0_def by (rule someI_ex)
  then show "ω  (n. A (n + n0))" "n0 > 0"
    by blast+
qed

lemma nzero_ge: "n. n  n0  2^n * T  1"
proof (rule ccontr)
  fix n assume "n0  n" "¬ 1  2 ^ n * T"
  then have "A n = space source"
    unfolding A_def by simp
  then have "space source  (m. A (m + n))"
    by (smt (verit, del_insts) UNIV_I UN_upper add_0)
  also have "(m. A (m + n))  (m. A (m + n0))"
    by (simp add: Union_add_subset n0  n)
  finally show False
    using ω n_zero by blast
qed

lemma omega_notin: "n. n  n0  ω  A n"
  by (metis n_zero UNIV_I UN_iff add.commute le_Suc_ex)

text ‹Klenke 21.7›

lemma X_dyadic_incr:
  assumes "k  {1..2^n * T}" "n  n0"
  shows "dist (X ((real_of_int k-1)/2^n) ω) (X (real_of_int k/2^n) ω) < 2 powr (- γ * n)"
proof -
  have "finite {1..2^n * T}" "{1..2^n * T}  {}"
    using assms nzero_ge by blast+
  then have fin_nonempty: "finite {dist (X (real_of_int (k - 1) * 2 powr - real n) ω) (X (real_of_int k * 2 powr - real n) ω) |k.
             k  {1..2 ^ n * T}}" "{dist (X (real_of_int (k - 1) * 2 powr - real n) ω) (X (real_of_int k * 2 powr - real n) ω) |k.
             k  {1..2 ^ n * T}}  {}"
    by fastforce+
  have "2 powr (- γ * real n)
     > Max {dist (X (real_of_int (k - 1) * 2 powr - real n) ω) (X (real_of_int k * 2 powr - real n) ω) |k.
             k  {1..2 ^ n * T}}"
    using nzero_ge[OF assms(2)] omega_notin[OF assms(2)] ω A_def by auto
  then have "2 powr (- γ * real n) > dist (X (real_of_int (k - 1) * 2 powr - real n) ω) (X (real_of_int k * 2 powr - real n) ω)"
    using Max_less_iff[OF fin_nonempty] assms(1) by blast
  then show ?thesis
    by (simp, smt (verit, ccfv_threshold) divide_powr_uminus powr_realpow)
qed

text ‹ Klenke (21.8) ›

lemma dist_dyadic_mn:
  assumes mn: "n0  n" "n  m"
    and t_dyadic: "t  dyadic_interval_step m 0 T"
    and u_dyadic_n: "u  dyadic_interval_step n 0 T"
    and ut: "u  t" "t - u < 2/2^n"
  shows "dist (X u ω) (X t ω)  2 powr (- γ * n) / (1 - 2 powr - γ)"
proof -
  have u_dyadic: "u  dyadic_interval_step m 0 T"
    using mn(2) dyadic_interval_step_subset u_dyadic_n by fast
  have "0 < n"
    using mn(1) n_zero_nonzero by linarith
  then have "t - u < 1"
    by (smt (verit) ut(2) One_nat_def Suc_le_eq divide_le_eq_1_pos power_increasing power_one_right)
  obtain b_tu k_tu where tu_exp: "dyadic_expansion (t-u) m b_tu k_tu"
    using dyadic_expansion_ex dyadic_interval_minus[OF u_dyadic t_dyadic u  t] by blast
  then have "k_tu = 0"
    using dyadic_expansion_floor[OF tu_exp] t - u < 1 u  t by linarith
  have b_tu_0_1: "b_tu ! i  {0,1}" if "i  {0..m-1}" for i
    using dyadic_expansionD(1,2)[OF tu_exp] that
    by (metis Suc_pred' 0 < n atLeastAtMost_iff le_imp_less_Suc le_trans less_eq_Suc_le mn(2) nth_mem subsetD)
  text ‹ And hence $b_i (t - u) = b_i (s-u) = 0$ for $i < n$. ›
  have b_t_zero: "b_tu ! i = 0" if "i+1 < n" for i
  proof (rule ccontr)
    assume "b_tu ! i  0"
    then have "b_tu ! i = 1"
      by (smt (verit) add_lessD1 dyadic_expansionD(1,2) insertE mn(2) nth_mem order_less_le_trans
          singletonD subset_iff that tu_exp)
    then have "t - u  (real_of_int 0) + 1/2^(i+1)"
      apply (intro dyadic_expansion_nth_geq)
      using tu_exp k_tu = 0 apply blast
       apply (metis One_nat_def Suc_eq_plus1 Suc_le_mono atLeastAtMost_iff le_trans less_Suc_eq linorder_not_le mn(2) nat_less_le that zero_order(1))
      apply simp
      done
    moreover have "1/2^(n-1)  1/(2^(i+1) :: real)"
      apply (intro divide_left_mono)
        apply (metis that Suc_eq_plus1 Suc_leI less_diff_conv power_increasing power_one_right two_realpow_ge_one)
      by simp_all
    ultimately have "t - u  1 / 2 ^ (n - 1)"
      by linarith
    then show False
      using t - u < 2/2^n n > 0 by (auto simp: power_diff)
  qed
  define t' where "t'  λl. (u + (i = n..l. b_tu!(i-1) / 2 ^ i))"
  have "t' (n-1) = u"
    unfolding t'_def using n > 0 by simp
  have "t' m = t"
  proof -
    have b_tu_eq_0: "( i = 1..n-1. b_tu!(i-1) / 2 ^ i) = 0"
      by (subst sum_nonneg_eq_0_iff, auto simp add: sum_nonneg_eq_0_iff b_t_zero)
    have "t - u = (i = 1..m. b_tu!(i-1) / 2 ^ i)"
      using tu_exp[THEN dyadic_expansionD(3)] k_tu = 0 by linarith
    also have "... = (i = 1..n-1. b_tu!(i-1) / 2 ^ i) + (i = n..m. b_tu!(i-1) / 2 ^ i)"
    proof -
      have 1: "{1..m} = {1..n-1}  {n..m}"
        using n > 0 mn(2) by fastforce
      show ?thesis
        by (subst 1, auto simp: sum.union_disjoint)
    qed
    finally have "t-u = (i = n..m. b_tu!(i-1) / 2 ^ i)"
      using b_tu_eq_0 by algebra
    then show ?thesis
      unfolding t'_def by argo
  qed
  have t_pos: "t' l  0" if l  {n..m} for l
    unfolding t'_def apply (rule add_nonneg_nonneg)
    using dyadic_step_geq u_dyadic apply blast
    by (simp add: sum_nonneg)
  have t'_Suc: "t' (Suc l) = t' l + b_tu ! l / 2^(Suc l)" if "l {n-1..m-1}" for l
    unfolding t'_def by (simp add: b_t_zero)
  have le_add_diff: "b  c - a  a + b  c" for a b c :: real
    by argo
  have t'_leq: "t' l  t" if l  {n..m} for l
    unfolding t'_def apply (intro le_add_diff)
    apply (simp only: tu_exp[THEN dyadic_expansionD(3)] k_tu = 0 of_int_0 add_0)
    apply (rule sum_mono2)
    using 0 < n that by auto
  have t'_dyadic: "t' l  dyadic_interval_step l 0 T" if "l  {n..m}" for l
    using that
  proof (induct l rule: atLeastAtMost_induct)
    case base
    consider "b_tu ! (n - 1) = 0" | "b_tu ! (n-1) = 1"
      using dyadic_expansion_frac_range[OF tu_exp(1), of n] 0 < n mn(2) by auto
    then show ?case
      apply cases
      using 0 < n t'_def apply simp
      using u_dyadic_n apply blast
      apply (rule dyadic_interval_step_memI)
        apply (simp add: t'_def)
      using u_dyadic_n
        apply (metis add_divide_distrib dyadic_interval_step_iff of_int_1 of_int_add)
       apply (simp add: mn(2) t_pos)
      by (meson t'_leq[OF that] atLeastAtMost_iff dual_order.refl dual_order.trans dyadic_step_leq mn(2) t'_leq t_dyadic)
  next
    case (Suc l)
    then have t'_dyadic_Suc: "t' l  dyadic_interval_step (Suc l) 0 T"
      using dyadic_interval_step_mono le_SucI by blast
    from Suc have "l  {0..m-1}"
      by force
    then consider "b_tu!l = 0" | "b_tu!l = 1"
      using b_tu_0_1 by fastforce
    then obtain k :: int where k: "t' l + (b_tu ! l) / 2 ^ Suc l = k / 2 ^ Suc l"
      apply cases
      subgoal using dyadic_interval_step_iff t'_dyadic_Suc by auto
      by (metis add.commute add_divide_distrib dyadic_as_natural of_int_of_nat_eq of_nat_1 of_nat_Suc t'_dyadic_Suc)
    have "t' (Suc l)  t"
      by (meson Suc atLeastAtMost_iff le_SucI less_eq_Suc_le t'_leq)
    with Suc(1,2) show ?case
      apply (subst t'_Suc)
       apply (metis Suc_leD Suc_pred' 0 < n atLeastAtMost_iff less_Suc_eq_le mn(2) order_less_le_trans)
      apply (intro dyadic_interval_step_memI)
        apply (rule exI[where x=k])
      using k apply blast
      using dyadic_step_geq t'_dyadic_Suc apply force
      apply (subst t'_Suc[symmetric])
       apply force
      using dyadic_step_leq order_trans t_dyadic by blast
  qed
  have "dist (X (t' (n-1)) ω) (X (t' m) ω)  ( l=Suc (n-1)..m. dist (X (t' l) ω) (X (t' (l-1)) ω))"
    apply (rule triangle_ineq_sum)
    using diff_le_self dual_order.trans mn(2) by blast
  also have "... = ( l=n..m. dist (X (t' l) ω) (X (t' (l-1)) ω))"
    using Suc_diff_1 0 < n by presburger
  also have "...  ( l=n..m. 2 powr (-γ * l))"
  proof (rule sum_mono)
    fix l assume *: "l  {n..m}"
    then have "l  {n-1..m}"
      by (metis atLeastAtMost_iff less_imp_diff_less linorder_not_less order_le_less)
    from * have [simp]: "0 < l"
      using 0 < n by fastforce
    from l  {n..m} have "b_tu ! (l-1)  {0, 1}"
      apply (intro dyadic_expansion_frac_range)
       apply (rule tu_exp)
      using n > 0 by simp
    then consider (zero) "b_tu ! (l-1) = 0" | (one) "b_tu ! (l-1) = 1"
      by fast
    then show "dist (X (t' l) ω) (X (t' (l - 1)) ω)  2 powr (- γ * l)"
    proof cases
      case zero
      have "{n..l} = insert l {n..l-1}"
        using 0 < n l  {n..m} by auto
      then have "sum f {n..l} = sum f {n..l-1} + f l" for f :: "nat  real"
        by (metis (no_types, opaque_lifting) Groups.add_ac(3) Suc_le_eq Suc_pred' 0 < n atLeastAtMost_iff finite_atLeastAtMost group_cancel.rule0 linorder_not_le nle_le sum.insert zero_diff zero_less_diff)
      then have "t' l = t' (l-1)"
        unfolding t'_def using zero by simp
      then show ?thesis
        by simp
    next
      case one
      then have [simp]: "b_tu ! (l - Suc 0) = 1"
        by simp
      obtain k where k: "k  0" "k  2^l * T" "t' l = k/2^l"
        using t'_dyadic l  {n..m} dyadic_interval_step_iff by force
      have "t' (l-1)  dyadic_interval_step l 0 T"
      proof (cases "l = n")
        case True
        then have "t' (l-1) = u"
          using t' (n - 1) = u by presburger
        then show "t' (l-1)  dyadic_interval_step l 0 T"
          using True u_dyadic_n by blast
      next
        case False
        then have "l-1  {n..m}"
          by (metis "*" Suc_eq_plus1 add_leD2 atLeastAtMost_iff diff_le_self dual_order.trans
              le_antisym not_less_eq_eq ordered_cancel_comm_monoid_diff_class.le_diff_conv2)
        then show "t' (l-1)  dyadic_interval_step l 0 T"
          using t'_dyadic dyadic_interval_step_subset diff_le_self by blast
      qed
      then obtain k' where k': "k'  0" "k'  2^l * T" "t' (l-1) = k'/2^l"
        using dyadic_interval_step_iff by auto
      then have t'_k: "t' (l-1) = (k-1) / 2^l"
      proof -
        have "t' l = t' (l-1) + real (b_tu ! (l-1)) / 2 ^ l"
          using t'_Suc[of "l-1"] apply simp
          using "*" diff_le_mono by presburger
        then have "k / 2^l = t' (l-1) + 1/2^l"
          by (simp add: k(3))
        then show ?thesis
          by (simp add: diff_divide_distrib)
      qed
      then have "k  1"
        using k'(1) k'(3) by auto
      then show ?thesis
        apply (simp only: k(3) t'_k)
        apply (subst dist_commute)
        apply (intro less_imp_le)
        apply (simp only: of_int_diff of_int_1)
        apply (rule X_dyadic_incr[of k l])
        using k(2) apply presburger
        using l  {n..m} mn(1) by auto
    qed
  qed
  also have "... = ( l=n..m. (2 powr -γ) ^ l)"
    apply (intro sum.cong; simp add: field_simps)
    by (smt (verit, ccfv_SIG) powr_powr[symmetric] mult_minus_left powr_gt_zero powr_realpow)
  also have "...  2 powr (-γ * n) / (1 - 2 powr -γ)"
    apply (subst sum_gp)
    using m  n apply (simp add: field_simps)
    apply safe
    using gamma_gt_0 apply force
    apply (rule divide_right_mono)
     apply (simp only: minus_mult_left)
     apply (subst powr_powr[symmetric])
     apply (subst powr_realpow[symmetric]; simp)+
    by (metis diff_ge_0_iff_ge gamma_gt_0 less_eq_real_def
        neg_le_0_iff_le one_le_numeral powr_mono powr_nonneg_iff powr_zero_eq_one)
  finally show "dist (X u ω) (X t ω)  2 powr (- γ * real n) / (1 - 2 powr - γ)"
    using t' (n - 1) = u t' m = t by blast
qed

lemma dist_dyadic_fixed:
  assumes mn: "n0  n" "n  m"
    and s_dyadic: "s  dyadic_interval_step m 0 T"
    and t_dyadic: "t  dyadic_interval_step m 0 T"
    and st: "s  t" "t - s  1/2^n"
  shows "dist (X t ω) (X s ω)  2 * 2 powr (- γ * n) / (1 - 2 powr - γ)"
proof -
  have "n > 0"
    using mn(1) n_zero_nonzero by linarith
  define u where "u  2^n * s / 2^n"
  have "u = Max (dyadic_interval_step n 0 s)"
    unfolding u_def using  dyadic_interval_step_Max[symmetric] dyadic_step_geq[OF s_dyadic]
    by blast
  then have u_dyadic_n: "u  dyadic_interval_step n 0 T"
    using dyadic_interval_step_mem dyadic_step_geq dyadic_step_leq s_dyadic u_def by force
  text ‹ Then, $u \leq s < u + 2^{-n}$ and $u \leq t < u + 2^{1-n}$›
  have "u  s"
    unfolding u_def using floor_pow2_leq by blast
  have "s < u + 1/2^n"
    unfolding u_def apply (simp add: field_simps)
    using floor_le_iff apply linarith
    done
  then have "s - u < 2/2^n"
    using u  s by auto
  then have dist_us: "dist (X u ω) (X s ω)  2 powr (- γ * real n) / (1 - 2 powr - γ)"
    by (rule dist_dyadic_mn[OF mn s_dyadic u_dyadic_n u  s]) 
  have "u  t"
    using u  s st(1) by linarith
  have "t < u + 2/2^n"
    using s <u + 1/2^n st(2) by force
  then have "t - u < 2/2^n"
    by force
  then have "dist (X u ω) (X t ω)  2 powr (- γ * real n) / (1 - 2 powr - γ)"
    by (rule dist_dyadic_mn[OF mn t_dyadic u_dyadic_n u  t])
  then show "dist (X t ω) (X s ω)  2 * (2 powr (-γ * n)) / (1 - 2 powr - γ)"
    using dist_us by metric
qed

definition "C0  2 * 2 powr γ / (1 - 2 powr - γ)"

lemma C_zero_ge[simp]: "C0 > 0"
  by (smt (verit, ccfv_SIG) C0_def divide_pos_pos gamma_gt_0 powr_eq_one_iff powr_less_mono)

text ‹ Klenke (21.9) ›
text ‹ Let $s, t \in D$ with $|s-t| \leq \frac{1}{2^n_0}$. By choosing the minimal $n \geq n_0$ such
  that $|t-s| \geq 2^{-n}$, we obtain by @{thm dist_dyadic_fixed}:
  \[|X_t(\omega) - X_s(\omega)| \leq C_0 |t-s|^\gamma\]›

lemma dist_dyadic:
  assumes t: "t  dyadic_interval 0 T"
    and s: "s  dyadic_interval 0 T"
    and st_dist: "dist t s  1 / 2 ^ n0"
  shows  "dist (X t ω) (X s ω)  C0 * (dist t s) powr γ"
proof (cases "s = t")
  case True
  then show ?thesis by simp
next
  case False
  define n where "n  LEAST n. dist t s  1/2^n"
  have "dist t s > 0"
    using False by simp
  then have "n. dist t s  1 / 2^n"
    by (metis less_eq_real_def one_less_numeral_iff power_one_over reals_power_lt_ex semiring_norm(76))
  then have "dist t s  1/2^n"
    unfolding n_def by (meson LeastI_ex)
  then have "n  n0"
    using order_trans[OF dist t s  1/2^n st_dist]
    by (simp add: field_simps)
  have "dist t s  1/2^(n-1)"
  proof -
    have "n-1 < (LEAST n. dist t s  1/2^n)"
      using n0  n n_zero_nonzero n_def by fastforce
    then have "¬ (dist t s  1/2^(n-1))"
      by (rule not_less_Least)
    then show ?thesis
      by auto
  qed
  obtain m where m: "m  n" "s  dyadic_interval_step m 0 T" "t  dyadic_interval_step m 0 T"
    by (metis dyadic_interval_step_mono linorder_not_le mem_dyadic_interval order.asym s t)
  from n  n0 consider (eq) "n = n0" | (gt) "n > n0"
    using less_eq_real_def by linarith
  then show ?thesis
  proof cases
    case eq
    consider "t  s" | "s  t"
      by fastforce
    then have "dist (X t ω) (X s ω)  2 * 2 powr (- γ * n) / (1 - 2 powr - γ)"
      apply cases
       apply (subst dist_commute)
       apply (rule dist_dyadic_fixed[OF n  n0 m(1,3,2)])
        apply simp
      using dist_real_def eq st_dist apply force
      apply (rule dist_dyadic_fixed[OF n  n0 m])
       apply simp
      using dist_real_def eq st_dist apply force
      done
    also have "...  C0 * 2 powr (- γ * n)"
      unfolding C0_def apply (simp add: field_simps)
      apply (intro divide_right_mono mult_left_mono)
        apply (simp add: less_eq_real_def)
       apply simp
      by (smt (verit) gamma_gt_0 powr_le_cancel_iff powr_zero_eq_one)
    also have "... = C0 * (1/2^n) powr γ"
      by (smt (verit, del_insts) powr_minus_divide powr_powr powr_powr_swap powr_realpow)
    also have "...  C0 * (dist t s) powr γ"
      using 1 / 2 ^ n  dist t s eq st_dist by auto
    finally show ?thesis .
  next
    case gt
    consider "t  s" | "s  t"
      by fastforce
    then have "dist (X t ω) (X s ω)  2 * 2 powr (- γ * (n-1)) / (1 - 2 powr - γ)"
      apply cases
       apply (subst dist_commute)
       apply (rule dist_dyadic_fixed[where m=m])
            prefer 7 apply (rule dist_dyadic_fixed[where m=m])
      using gt m apply simp_all
      using dist t s  1 / 2 ^ (n - 1) dist_real_def apply force+
      done
    also have "...  C0 * 2 powr (- γ * n)"
      unfolding C0_def apply simp
      apply (intro divide_right_mono)
       apply (simp add: powr_add[symmetric])
       apply (metis One_nat_def Suc_leI dual_order.refl gt less_imp_Suc_add minus_diff_eq mult.right_neutral of_nat_1 of_nat_diff right_diff_distrib zero_less_Suc)
      by (metis gamma_gt_0 ge_iff_diff_ge_0 less_eq_real_def neg_le_0_iff_le one_le_numeral powr_mono powr_zero_eq_one zero_neq_numeral)
    also have "... = C0 * (1/2^n) powr γ"
      by (smt (verit, best) powr_minus_divide powr_powr powr_powr_swap powr_realpow)
    also have "C0 * (1/2^n) powr γ  C0 * dist t s powr γ"
      apply (rule mult_left_mono)
      using 1 / 2 ^ n  dist t s less_eq_real_def powr_mono2 apply force
      using C_zero_ge by linarith
    finally show ?thesis .
  qed
qed

(* The extra power of 2 makes the issues with dyadics disappear in holder_dyadic, since we divide
  by a power of 2 *)
definition "K  C0 * (2^nat 2^n0 * T) powr (1 - γ)"

lemma C0_le_K: "C0  K"
  unfolding K_def using nzero_ge[of n0] ge_one_powr_ge_zero by force

lemma K_pos: "0 < K"
  using C0_le_K C_zero_ge by linarith

text ‹ Klenke (21.10) ›
lemma X_dyadic_le_K':
  assumes dyadic: "s  dyadic_interval 0 T" "t  dyadic_interval 0 T" 
    and st: "s  t"
  shows "dist (X s ω) (X t ω)  K * dist s t powr γ"
proof (cases "dist s t  1 / 2^n0")
  case True
  then have "C0 * dist t s powr γ  K * dist t s powr γ"
    by (simp add: C0_le_K powr_def)
  then show ?thesis
    using dist_dyadic[OF assms(1,2) True] by (simp add: dist_commute)
next
  case False
  define n :: nat where "n  nat 2^n0 * T"
  have "dist s t / n  1/2^n0"
    apply (simp add: n_def field_simps)
    by (smt (verit, best) dyadic dist_real_def divide_le_eq_1 dyadics_geq dyadics_leq
        mem_dyadic_interval mult_mono of_nat_eq_0_iff of_nat_le_0_iff real_nat_ceiling_ge zero_le_power)
  have dist_st: "dist s t / 2^n  1/2^n0"
    apply (rule order_trans[where y="dist s t / n"])
     apply (rule divide_left_mono; simp?)
     apply (simp add: n_def zero_le_T)
    apply (fact dist s t / n  1/2^n0)
    done
  define f where "f  λi::nat. (s + (t-s) * i/2^n)"
  have f_inc: "f k = f (k - 1) + (t - s) / 2^n" if "k > 0" for k
  proof -
    have "f (Suc k) = f k + (t - s) / 2^n" for k
      by (simp add: f_def field_simps)
    then show ?thesis
      by (metis Suc_pred' that)
  qed
  have f_inc_le: "dist (f i) (f (i - 1))  1 / 2 ^ n0" for i
  proof (cases "i=0")
    case True
    then show ?thesis by simp
  next
    case False
    then show ?thesis
      using f_inc dist_real_def dist_st st by auto
  qed
  have f_ge_s: "i. i  2^n  f i  s"
    unfolding f_def using st by auto
  have f_le_t: "i. i  2^n  f i  t"
    by (smt (verit, del_insts) f_def st divide_le_eq_1 mult_less_cancel_left1 of_nat_1 of_nat_add
        of_nat_le_iff of_nat_power one_add_one times_divide_eq_right zero_less_power)
  have f_dyadic: "f i  dyadic_interval 0 T" if "i  2^n" for i
  proof (rule mem_dyadic_intervalI)
    have "f i  T"
    proof -
      have "f i  s + t - s"
        using f_le_t[OF that] by simp
      also have "...  T"
        using dyadic(2) dyadics_leq by simp
      finally show ?thesis .
    qed
    obtain m where "s  dyadic_interval_step m 0 T" "t  dyadic_interval_step m 0 T"
      by (metis dyadic dyadic_interval_step_mono mem_dyadic_interval nle_le)
    then obtain ks kt where ks: "s = real ks / 2^m" and kt: "t = real kt / 2^m"
      using dyadic_as_natural by metis
    then have "ks  kt"
      using st by (simp add: divide_le_cancel)
    from ks kt have "ks = 2^m * s" "kt = 2^m * t"
      by simp_all
    from ks kt have "f i = (ks / 2^m) + (kt / 2^m - ks / 2^m) * i / 2^n"
      unfolding f_def by auto
    also have "... = (ks * (2^n - i) + kt * i) / 2^(m+n)"
      using ks  kt apply (simp add: right_diff_distrib field_simps power_add)
      by (metis distrib_left le_add_diff_inverse mult.commute of_nat_add of_nat_numeral of_nat_power that)
    finally have "f i  dyadic_interval_step (m+n) 0 T"
      apply (intro dyadic_interval_step_memI)
        apply (rule exI[where x="int (ks * (2^n - i) + kt * i)"])
        prefer 3 apply (rule f i  T)
      by simp_all
    then show "n. f i  dyadic_interval_step n 0 T"
      by blast
  qed
  have "dist (X s ω) (X t ω)  ( i=1..2^n. dist (X (f i) ω) (X (f (i-1)) ω))"
  proof -
    have "f 0 = s"
      unfolding f_def by (simp add: field_simps)
    moreover have "f (2^n) = t"
      unfolding f_def by (simp add: field_simps)
    moreover have "dist (X (f 0) ω) (X (f (2^n)) ω)  ( i=Suc 0..2^n. dist (X (f i) ω) (X (f (i-1)) ω))"
      by (rule triangle_ineq_sum, simp)
    ultimately show ?thesis
      by simp
  qed
  also have "...  ( i=1..2^n::nat. C0 * (dist (f i) (f (i-1))) powr γ)"
    apply (rule sum_mono)
    apply (intro dist_dyadic f_dyadic)
      apply fastforce
     apply fastforce
    using f_inc_le .
  also have "...  ( i=1..2^n::nat. C0 * (dist t s / 2^n) powr γ)"
    apply (rule sum_mono)
    using f_inc by (simp add: dist_real_def)
  also have "...  2^n * C0 * (dist t s / 2^n) powr γ"
    by (subst sum_constant, force)
  also have "...  K * dist t s powr γ"
    unfolding K_def n_def apply (simp add: powr_divide field_simps)
    apply (rule mult_left_mono)
     apply (smt (verit, ccfv_threshold) powr_add powr_one zero_le_power)
    by simp
  finally show ?thesis
    by (metis dist_commute)
qed

lemma X_dyadic_le_K:
  assumes "s  dyadic_interval 0 T"
    and "t  dyadic_interval 0 T"
  shows "dist (X s ω) (X t ω)  K * dist s t powr γ"
  by (metis nle_le assms X_dyadic_le_K' dist_commute)

corollary holder_dyadic: "γ-holder_on (dyadic_interval 0 T) (λt. X t ω)"
  apply (intro holder_onI[OF gamma_0_1] exI[where x=K])
  using K_pos X_dyadic_le_K by force

lemma uniformly_continuous_dyadic: "uniformly_continuous_on (dyadic_interval 0 T) (λt. X t ω)"
  using holder_dyadic by (fact holder_uniform_continuous)

lemma Lim_exists: "L. ((λs. X s ω)  L) (at t within (dyadic_interval 0 T))"
  if "t  {0..T}"
  apply (rule uniformly_continuous_on_extension_at_closure[where x = t])
  using that dyadic_interval_dense uniformly_continuous_dyadic apply fast
  using that apply (simp add: dyadic_interval_dense)
  by blast

lemma Lim_unique: "∃!L. ((λs. X s ω)  L) (at t within (dyadic_interval 0 T))" 
  if "t  {0..T}"
  by (metis that Lim_exists dyadic_interval_islimpt tendsto_Lim trivial_limit_within zero_le_T)

definition "L  (λt. (Lim (at t within dyadic_interval 0 T) (λs. X s ω)))"

lemma X_tendsto_L:
  assumes "t  {0..T}"
  shows "((λs. X s ω)  L t) (at t within (dyadic_interval 0 T))"
proof -
  have "at t within dyadic_interval 0 T  "
    by (simp add: trivial_limit_within dyadic_interval_islimpt[OF zero_le_T assms])
  moreover obtain L' where L': "((λs. X s ω)  L') (at t within (dyadic_interval 0 T))"
    using Lim_exists[OF assms] by blast
  ultimately have "L t = L'"
    unfolding L_def by (rule tendsto_Lim)
  then show ?thesis
    using L' by blast
qed

lemma L_dist_K:
  assumes s: "s  {0..T}"
    and t: "t  {0..T}"
  shows "dist (L s) (L t)  K * dist s t powr γ"
proof (cases "s = t")
  case True
  then show ?thesis by simp
next
  case False
  let ?F = "λx. at x within dyadic_interval 0 T"
  have "(?F s ×F ?F t)  "
    by (meson dyadic_interval_islimpt prod_filter_eq_bot s t trivial_limit_within zero_le_T)
  moreover have "((λx. K * dist (fst x) (snd x) powr γ)  K * dist s t powr γ) (?F s ×F ?F t)"
    apply (rule tendsto_mult_left)
    apply (rule tendsto_powr)
    using tendsto_dist_prod apply blast
     apply simp
    using False by simp
  moreover have "((λx. dist (X (fst x) ω) (X (snd x) ω))  dist (L s) (L t)) (?F s ×F ?F t)"
    using X_tendsto_L t s tendsto_dist_prod by blast
  moreover have "F x in ?F s ×F ?F t. dist (process X (fst x) ω) (process X (snd x) ω) 
                                      K * dist (fst x) (snd x) powr γ"
    apply (rule eventually_prodI'[where P = "λx. x  dyadic_interval 0 T"
          and Q = "λx. x  dyadic_interval 0 T"])
    using eventually_at_topological apply blast
    using eventually_at_topological apply blast
    using X_dyadic_le_K by simp    
  ultimately show ?thesis
    by (rule tendsto_le)
qed

corollary L_holder: "γ-holder_on {0..T} L"
  using K_pos L_dist_K by (auto intro!: holder_onI[OF gamma_0_1] exI[where x=K])

corollary L_local_holder: "local_holder_on γ {0..T} L"
  using holder_implies_local_holder[OF L_holder] by blast

lemma X_dyadic_eq_L:
  assumes "t  dyadic_interval 0 T"
  shows "X t ω = L t"
proof -
  have "((λx. X x ω)  X t ω) (at t within dyadic_interval 0 T)"
    using continuous_within[symmetric] uniformly_continuous_dyadic uniformly_continuous_imp_continuous
      continuous_on_eq_continuous_within assms by fast
  then show ?thesis
    by (metis L_def assms dyadic_interval_islimpt dyadic_interval_subset_interval subsetD
        tendsto_Lim trivial_limit_within zero_le_T)
qed
end

definition default :: 'b where "default = (SOME x. True)"

definition X_tilde :: "real  'a  'b" where
  "X_tilde  (λt ω. if ω  N then default else (Lim (at t within dyadic_interval 0 T) (λs. X s ω)))"

lemma X_tilde_not_N_Lim:
  assumes "ω  space source - N"
  shows "X_tilde t ω = Lim (at t within dyadic_interval 0 T) (λs. X s ω)"
  using assms X_tilde_def by auto

lemma X_tilde_not_N_L:
  assumes "ω  space source - N"
  shows "X_tilde t ω = L ω t"
  using assms X_tilde_def L_def[OF assms] by auto

lemma local_holder_X_tilde: "local_holder_on γ {0..T} (λt. X_tilde t ω)"
  if "ω  space source" for ω
proof (cases "ω  N")
  case True
  then show ?thesis
    unfolding X_tilde_def using local_holder_const by fastforce
next
  case False
  then have 1: "ω  space source - N"
    using that by blast
  show ?thesis
    using L_local_holder[OF 1] X_tilde_not_N_L[OF 1]
    by (simp only: False if_False)
qed

corollary X_tilde_eq_L_AE: "AE ω in source. X_tilde t ω = L ω t"
  apply (rule AE_I[where N=N])
    apply (smt (verit, del_insts) X_tilde_def Diff_iff L_def mem_Collect_eq subsetI)
  using N_null apply blast+
  done

corollary X_tilde_eq_Lim_AE:
  "AE ω in source. X_tilde t ω = Lim (at t within dyadic_interval 0 T) (λs. X s ω)"
  apply (rule AE_I[where N=N])
    apply (smt (verit, del_insts) X_tilde_def Diff_iff L_def mem_Collect_eq subsetI)
  using N_null apply blast+
  done

lemma X_tilde_tendsto_AE: "t  {0..T}  tendsto_AE source X (X_tilde t) (at t within dyadic_interval 0 T)"
  apply (unfold tendsto_AE_def)
  apply (rule AE_I3[where N=N])
   apply (subst X_tilde_not_N_Lim, argo)
  unfolding t2_space_class.Lim_def apply (rule the1I2)
  using Lim_unique apply presburger
   apply blast
  using N_null by blast

end

context Kolmogorov_Chentsov_finite
begin

text ‹ By (21.5) @{thm conv_in_prob_finite} and (21.11) @{thm L_def}, $P[X \neq \tilde{X}] = 0$›

lemma X_tilde_measurable[measurable]:
  assumes "t  {0..T}"
  shows "X_tilde t  borel_measurable source"
proof -
  let ?Lim = "(λω. Lim (at t within dyadic_interval 0 T) (λs. process X s ω))"
  have "?Lim  borel_measurable (restrict_space source (space source - N))"
    unfolding X_tilde_def apply measurable
    using measurable_id measurable_restrict_space1 apply blast
    using assms Lim_exists space_restrict_space apply simp
    using assms dyadic_interval_islimpt trivial_limit_within zero_le_T by blast
  then have "(λω. if ω  space source - N then ?Lim ω else default)  borel_measurable source"
    by (subst measurable_restrict_space_iff[symmetric]; simp)
  then show ?thesis
    apply (subst measurable_cong[where g="(λω. if ω  space source - N then ?Lim ω else default)"])
    unfolding X_tilde_def by auto
qed

lemma X_eq_X_tilde_AE: "AE ω in source. X t ω = X_tilde t ω" if "t  {0..T}" for t
  apply (rule sigma_finite_measure.tendsto_measure_at_within_eq_AE[where f="process X" and S="dyadic_interval 0 T"])
  using proc_source.sigma_finite_measure_axioms apply blast
  using X_borel_measurable apply blast
      apply measurable
  using X_tilde_def apply simp
  using that apply simp
  using tendsto_measure_mono[OF at_le[OF dyadic_interval_subset_interval] conv_in_prob_finite] that
    apply force
  using X_borel_measurable X_tilde_measurable X_tilde_tendsto_AE measure_conv_imp_AE_at_within that apply blast
  using dyadic_interval_islimpt that trivial_limit_within zero_le_T by blast

lemma X_tilde_modification: "modification (restrict_index X {0..T})
   (prob_space.process_of source (proc_target X) {0..T} X_tilde default)"
  apply (intro modificationI compatibleI)
     apply simp_all
  apply (subst restrict_index_source)
  apply (auto simp: X_eq_X_tilde_AE)
  done
end

text ‹ We have now shown that we can construct a modification of $X$ for any interval $\{0..T\}$. We want
  to extend this result to construct a modification on the interval $\{0..\}$ - this can be constructed
  by gluing together all modifications with natural-valued T which results in a countable union of
  modifications, which itself is a modification. ›

context Kolmogorov_Chentsov
begin

lemma Kolmogorov_Chentsov_finite: "T > 0  Kolmogorov_Chentsov_finite X a b C γ T"
  by (simp add: Kolmogorov_Chentsov_axioms Kolmogorov_Chentsov_finite.intro Kolmogorov_Chentsov_finite_axioms_def)

definition "Mod  λT. SOME Y. modification (restrict_index X {0..T}) Y  
    (xspace source. local_holder_on γ {0..T} (λt. Y t x))"

lemma Mod: "modification (restrict_index X {0..T}) (Mod T)"
  "(xspace source. local_holder_on γ {0..T} (λt. (Mod T) t x)) " if "0 < T" for T
proof -
  interpret Kolmogorov_Chentsov_finite X a b C γ T
    using that by (simp add: Kolmogorov_Chentsov_finite)
  have "modification (restrict_index X {0..T}) (Mod T)  
    (xspace source. local_holder_on γ {0..T} (λt. (Mod T) t x))"
    unfolding Mod_def apply (rule someI_ex)
    apply (rule exI[where x="prob_space.process_of source (proc_target X) {0..T} X_tilde default"])    
    apply safe
     apply (fact X_tilde_modification)
    apply (subst local_holder_on_cong[OF refl refl])
    using local_holder_X_tilde X_tilde_measurable apply (auto cong: local_holder_on_cong)
    done
  then show "modification (restrict_index X {0..T}) (Mod T)"
    "(xspace source. local_holder_on γ {0..T} (λt. (Mod T) t x)) " 
    by blast+
qed

lemma compatible_Mod: "compatible (restrict_index X {0..T}) (Mod T)" if "0 < T" for T
  using Mod that modificationD(1) by blast

lemma Mod_source[simp]: "proc_source (Mod T) = source"  if "0 < T" for T
  by (metis compatible_Mod compatible_source restrict_index_source that)

lemma Mod_target: "sets (proc_target (Mod T)) = sets (proc_target X)"  if "0 < T" for T
  by (metis compatible_Mod[OF that] compatible_target restrict_index_target)

lemma Mod_index[simp]: "0 < T  proc_index (Mod T) = {0..T}"
  using compatible_Mod[THEN compatible_index] by simp

lemma indistinguishable_mod:
  "indistinguishable (restrict_index (Mod S) {0..min S T}) (restrict_index (Mod T) {0..min S T})"
  if "S > 0" "T > 0" for S T
proof -
  have *: "modification (restrict_index (Mod S) {0..min S T}) (restrict_index (Mod T) {0..min S T})"
  proof -
    have "modification (restrict_index X {0..min S T}) (restrict_index (Mod S) {0..min S T})"
      apply (cases "S  T")
      using Mod(1)[OF that(1)] apply clarsimp
       apply (metis modification_restrict_index order_refl restrict_index_index restrict_index_override)
      using Mod(1)[OF that(2)] apply clarsimp
      by (metis (mono_tags, opaque_lifting) modification (restrict_index X {0..S}) (Mod S) atLeastatMost_subset_iff modification_restrict_index nle_le restrict_index_index restrict_index_override)
    moreover have "modification (restrict_index X {0..min S T}) (restrict_index (Mod T) {0..min S T})"
      apply (cases "S  T")
      using Mod(1)[OF that(1)] apply clarsimp
       apply (metis Mod(1) atLeastatMost_subset_iff modification_restrict_index order.refl restrict_index_index restrict_index_override that(2))
      using Mod(1)[OF that(2)] apply clarsimp
      by (metis (mono_tags, opaque_lifting) atLeastatMost_subset_iff modification_restrict_index nle_le restrict_index_index restrict_index_override)
    ultimately show ?thesis
      using modification_sym modification_trans by metis
  qed
  then show ?thesis
  proof (rule modification_continuous_indistinguishable,
      goal_cases _ continuous_S continuous_T)
    show "Ta>0. proc_index (restrict_index (Mod S) {0..min S T}) = {0..Ta}"
      by (metis that min_def restrict_index_index)
  next
    case (continuous_S)
    have "x  space source. continuous_on {0..S} (λt. (Mod S) t x)"
      using Mod[OF that(1)] local_holder_imp_continuous by blast
    then have "x  space source. continuous_on {0..min S T} (λt. (Mod S) t x)"
      using continuous_on_subset by fastforce
    then show ?case
      by (auto simp: that(1))
  next
    case (continuous_T)
    have "x  space source. continuous_on {0..T} (λt. (Mod T) t x)"
      using Mod[OF that(2)] local_holder_imp_continuous by fast
    then have 2: "x  space source. continuous_on {0..min S T} (λt. (Mod T) t x)"
      using continuous_on_subset by fastforce
    then show ?case
      by (auto simp: that(2))
  qed
qed

definition "N S T  SOME N. N  null_sets source  {ω  space source. t  {0..min S T}. (Mod S) t ω  (Mod T) t ω}  N" 

lemma N:
  assumes "S > 0" "T > 0"
  shows "N S T  null_sets source  {ω  space source. t  {0..min S T}. (Mod S) t ω  (Mod T) t ω}  N S T"
proof -
  have ex: "S > 0. T > 0. N. N  null_sets source  {ω  space source. t  {0..min S T}.
   (Mod S) t ω  (Mod T) t ω}  N"
    apply (fold Bex_def)
    using indistinguishable_mod[THEN indistinguishable_null_ex] by simp
  show ?thesis
    unfolding N_def apply (rule someI_ex)
    using ex assms by blast
qed

definition N_inf where "N_inf  (S   - {0}. ( T   - {0}. N S T))"

lemma N_inf_null: "N_inf  null_sets source"
  unfolding N_inf_def
  apply (intro null_sets_UN')
    apply (rule countable_Diff)
    apply (simp add: Nats_def)+
  using N by force

lemma Mod_eq_N_inf: "(Mod S) t ω = (Mod T) t ω"
  if "ω  space source - N_inf" "t  {0..min S T}" "S   - {0}" "T   - {0}" for ω t S T
proof -
  have "ω  space source - N S T"
    using that(1,3,4) unfolding N_inf_def by blast
  moreover have "S > 0" "T > 0"
    using that(2,3,4) by auto
  ultimately have "ω  {ω  space source. t {0..min S T}. (Mod S) t ω = (Mod T) t ω}"
    using N by auto
  then show ?thesis
    using that(2) by blast
qed

definition default :: 'b where "default = (SOME x. True)"

definition "X_mod  λt ω. if ω  space source - N_inf then (Mod t+1) t ω else default"

definition "X_mod_process  prob_space.process_of source (proc_target X) {0..} X_mod default" 

lemma Mod_measurable[measurable]: "t{0..}. X_mod t  source M proc_target X"
proof (intro ballI)
  fix t :: real assume "t  {0..}"
  then have "0 < t + 1"
    by force
  then show "X_mod t  source M proc_target X"
    unfolding X_mod_def apply measurable
      apply (subst measurable_cong_sets[where M'= "proc_source (Mod t + 1)" and N' = "proc_target (Mod t + 1)"])
    using Mod_source 0 < t + 1 apply presburger
    using Mod_target 0 < t + 1 apply presburger
      apply (meson random_process)
     apply simp
    apply (metis N_inf_null Int_def null_setsD2 sets.Int_space_eq1 sets.compl_sets)
    done
qed

lemma modification_X_mod_process: "modification X X_mod_process"
proof (intro modificationI ballI)
  show "compatible X X_mod_process"
    apply (intro compatibleI)
    unfolding X_mod_process_def
      apply (subst proc_source.source_process_of)
    using Mod_measurable proc_source.prob_space_axioms apply auto
    done
  fix t assume "t  proc_index X"
  then have "t  {0..}"
    by simp
  then have "real_of_int t + 1 > 0"
    by (simp add: add.commute add_pos_nonneg)
  then have "N  null_sets source. ω  space source - N. 
      X t ω = (prob_space.process_of source (proc_target X) {0..} X_mod default) t ω"
  proof -
    have 1: "(prob_space.process_of source (proc_target X) {0..} X_mod default) t ω = (Mod (real_of_int t + 1)) t ω"
      if "ω  space source - N_inf" for ω
      apply (subst proc_source.process_process_of)
        apply measurable
      unfolding X_mod_def using that t  {0..} apply simp
      done
    have "N  null_sets source. ω  space source - N. X t ω = (Mod (real_of_int t + 1)) t ω"
    proof -
      obtain N where "{x  space source. (restrict_index X {0..real_of_int t + 1}) t x  (Mod (real_of_int t + 1)) t x}  N 
    N  null_sets (proc_source (restrict_index X {0..(real_of_int t + 1)}))"
        using Mod(1)[OF real_of_int t + 1 > 0, THEN modification_null_set, of t]
        using t  {0..} by fastforce
      then show ?thesis
        by (smt (verit, ccfv_threshold) DiffE mem_Collect_eq restrict_index_process restrict_index_source subset_eq)
    qed
    then obtain N where "N  null_sets source" "ω  space source - N. X t ω = (Mod (real_of_int t + 1)) t ω"
      by blast
    then show ?thesis
      apply (intro bexI[where x="N  N_inf"])
       apply (metis 1 DiffE DiffI UnCI)
      using N_inf_null by blast
  qed
  then show "AE x in source. X t x = X_mod_process t x"
    by (smt (verit, del_insts) X_mod_process_def DiffI eventually_ae_filter mem_Collect_eq subsetI)
qed

lemma local_holder_X_mod: "local_holder_on γ {0..} (λt. X_mod t ω)" for ω
proof (cases "ω  space source - N_inf")
  case False
  then show ?thesis
    apply (simp only: X_mod_def)
    apply (metis local_holder_const gamma_0_1)
    done
next
  case True
  then have ω: "ω  space source" "ω  N_inf"
    by simp_all
  then show ?thesis
  proof (intro local_holder_ballI[OF gamma_0_1] ballI)
    fix t::real assume "t  {0..}"
    then have "real_of_int t + 1 > 0"
      using floor_le_iff by force
    have "t < real_of_int t + 1"
      by simp
    then have "local_holder_on γ {0..real_of_int t + 1} (λs. Mod (real_of_int t + 1) s ω)"
      using Mod(2) ω(1) real_of_int t + 1 > 0 by blast
    then obtain ε C where eC: "ε > 0" "C  0" "r s. r  ball t ε  {0..real_of_int t + 1} 
       s  ball t ε  {0..real_of_int t + 1} 
       dist (Mod (real_of_int t + 1) r ω) (Mod (real_of_int t + 1) s ω)  C * dist r s powr γ"
      apply -
      apply (erule local_holder_onE)
        apply (rule gamma_0_1)
      using t  {0..} t < real_of_int t + 1 apply fastforce
      apply blast
      done
    define ε' where "ε' = min ε (if frac t = 0 then 1/2 else 1 - frac t)"
    have e': "ε'  ε  ε' > 0  ball t ε'  {0..}  {0..real_of_int t + 1}"
      unfolding ε'_def apply (simp add: eC(1))
      apply safe
        apply (simp_all add: eC(1) dist_real_def frac_lt_1 frac_floor)
       apply argo+
      done
    {
      fix r s
      assume r:  "r  ball t ε'  {0..}"
      assume s:  "s  ball t ε'  {0..}"

      then have rs_ball: "r  ball t ε  {0..real_of_int t + 1}"
        "s  ball t ε  {0..real_of_int t + 1}"
        using e' r s by auto
      then have "r  {0..min (real_of_int t + 1) (real_of_int r + 1)}"
        by auto
      then have "(Mod (real_of_int t + 1)) r ω = X_mod r ω"
        unfolding X_mod_def apply (simp only: True if_True)
        apply (intro Mod_eq_N_inf[OF True])
          apply simp
        using t  {0..} by auto
           (metis (no_types, opaque_lifting) floor_in_Nats Nats_1 Nats_add Nats_cases 
            of_int_of_nat_eq of_nat_in_Nats, linarith)+
      moreover have "(Mod (real_of_int t + 1)) s ω = X_mod s ω"
        unfolding X_mod_def apply (simp only: True if_True)
        apply (intro Mod_eq_N_inf[OF True])
        using s  ball t ε  {0..real_of_int t + 1} apply simp
        using t  {0..} apply safe
           apply (metis (no_types, opaque_lifting) floor_in_Nats Nats_1 Nats_add Nats_cases of_int_of_nat_eq of_nat_in_Nats)
          apply linarith
         apply (smt (verit) Int_iff Nats_1 Nats_add Nats_altdef1 atLeast_iff mem_Collect_eq s zero_le_floor)
        apply (metis Int_iff atLeast_iff floor_correct linorder_not_less one_add_floor s)
        done
      ultimately have "dist (X_mod r ω) (X_mod s ω)  C * dist r s powr γ"
        using eC(3)[OF rs_ball] by simp
    }
    then show "ε>0. C0. rball t ε  {0..}. sball t ε  {0..}. dist (X_mod r ω) (X_mod s ω)  C * dist r s powr γ"
      using e' eC(2) by blast
  qed
qed

lemma local_holder_X_mod_process: "local_holder_on γ {0..} (λt. X_mod_process t ω)" for ω
  unfolding X_mod_process_def
  by (smt (verit, best) Mod_measurable UNIV_I local_holder_X_mod local_holder_on_cong
      proc_source.process_process_of space_borel target_borel)

theorem continuous_modification:
  "X'. modification X X'  (ω. local_holder_on γ {0..} (λt. X' t ω))"
  apply (rule exI[where x=X_mod_process])
  using local_holder_X_mod_process modification_X_mod_process by auto
end

theorem Kolmogorov_Chentsov:
  fixes X :: "(real, 'a, 'b :: polish_space) stochastic_process"
    and a b C γ :: real
  assumes index[simp]: "proc_index X = {0..}"
    and target_borel[simp]: "proc_target X = borel"
    and gt_0: "a > 0" "b > 0" "C > 0"
    and b_leq_a: "b  a"
    and gamma: "γ  {0<..<b/a}"
    and expectation: "s t. s  0; t  0 
          (+ x. dist (X t x) (X s x) powr a proc_source X)  C * dist t s powr (1+b)"
  shows "X'. modification X X'  (ω. local_holder_on γ {0..} (λt. X' t ω))"
  using Kolmogorov_Chentsov.continuous_modification Kolmogorov_Chentsov.intro[OF assms]
  by blast
end