/- Copyright (c) 2026 Edwin Fernando. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Edwin Fernando -/ import Mathlib.MeasureTheory.Constructions.UnitInterval import Mathlib.MeasureTheory.Measure.ProbabilityMeasure import Mathlib.Probability.ProductMeasure /-! # Collection of Defintions used throughout the project -/ namespace HC open unitInterval MeasurableSpace variable {α β : Type*} {msα₁ msα₂ : MeasurableSpace α} {msβ₁ msβ₂ : MeasurableSpace β} -- scoped[HilbertCube] infixr:25 " ×ₘ " => MeasurableSpace.prod scoped infixr:60 " ×ₘ " => MeasurableSpace.prod -- standard borel measurable spaces abbrev Inf_borel : MeasurableSpace (ℕ → I) := inferInstance abbrev N_borel (N : ℕ) : MeasurableSpace (Fin N → I) := inferInstance -- the measurabe space with only univ and empty abbrev Inf_nil : MeasurableSpace (ℕ → I) := ⊥ abbrev N_nil (N : ℕ) : MeasurableSpace (Fin N → I) := ⊥ abbrev I_nil : MeasurableSpace I := ⊥ abbrev I_borel : MeasurableSpace I := inferInstance def splitBi (n : ℕ) : (ℕ → I) ≃ᵐ (Fin n → I) × (ℕ → I) := (MeasurableEquiv.piCongrLeft (fun _ => I) (finSumNatEquiv n)).symm.trans (MeasurableEquiv.sumPiEquivProdPi (fun _ => I)) /-- Constructs a MeasurableSpace on a Hilbert cube given a MeasurableSpace on the first N dimensions and another space on the rest of the infinite dimensions. -/ abbrev unSplitBi {n : ℕ} (ms : MeasurableSpace ((Fin n → I) × (ℕ → I))) : MeasurableSpace (ℕ → I) := ms.comap (splitBi n) def splitOne : (ℕ → I) ≃ᵐ I × (ℕ → I) := (MeasurableEquiv.piCongrLeft (fun _ => I) (Equiv.natEquivNatSumPUnit.trans (Equiv.sumComm ℕ Unit))).trans ((MeasurableEquiv.sumPiEquivProdPi (fun _ => I)).trans ((MeasurableEquiv.funUnique Unit I).prodCongr (MeasurableEquiv.refl _))) abbrev unSplitOne (ms : MeasurableSpace (I × (ℕ → I))) : MeasurableSpace (ℕ → I) := ms.comap splitOne def splitTri (n : ℕ) : (ℕ → I) ≃ᵐ (Fin n → I) × I × (ℕ → I) := (splitBi n).trans ((MeasurableEquiv.refl _).prodCongr splitOne) abbrev unSplitTri {n : ℕ} (ms : MeasurableSpace ((Fin n → I) × I × (ℕ → I))) : MeasurableSpace (ℕ → I) := ms.comap (splitTri n) /-- The σ-algebra is only "interesting" in the first `n` coordinates for some finite `n`. In the rest of the coordinates, its the `univ` set. -/ def FiniteFootprint (n : ℕ) (ms : MeasurableSpace (ℕ → I)) : Prop := ∃ ms' : MeasurableSpace (Fin n → I), ms = unSplitBi (ms' ×ₘ Inf_nil) /-- `unSplitBi (ms_pre ×ₘ Inf_nil)` is the comap of `ms_pre` through `fst ∘ splitBi n`. -/ lemma unSplitBi_eq_comap_fst (n : ℕ) (ms_pre : MeasurableSpace (Fin n → I)) : unSplitBi (ms_pre ×ₘ Inf_nil) = ms_pre.comap (Prod.fst ∘ splitBi n) := by simp only [unSplitBi, Inf_nil, MeasurableSpace.prod, MeasurableSpace.comap_bot, sup_bot_eq, MeasurableSpace.comap_comp] lemma finite_footprint_of_ge {n n' : ℕ} {ms : MeasurableSpace (ℕ → I)} (hn : n ≤ n') (ff : FiniteFootprint n ms) : FiniteFootprint n' ms := by obtain ⟨ms_n, h_ms_n⟩ := ff use ms_n.comap (fun (a : Fin n' → I) (i : Fin n) => a (Fin.castLE hn i)) convert h_ms_n using 1 convert unSplitBi_eq_comap_fst n' _ convert unSplitBi_eq_comap_fst n ms_n exact comap_comp lemma commute (le_α : msα₁ ≤ msα₂) (le_β : msβ₁ ≤ msβ₂) : (MeasurableSpace.prod msα₁ msβ₂) ⊔ (MeasurableSpace.prod msα₂ msβ₁) = MeasurableSpace.prod msα₂ msβ₂ := by unfold MeasurableSpace.prod rw [sup_sup_sup_comm, sup_eq_right.mpr (MeasurableSpace.comap_mono le_α), sup_eq_left.mpr (MeasurableSpace.comap_mono le_β)] private lemma commute_over_tri {N : ℕ} (N_ms : MeasurableSpace (Fin N → I)) : unSplitTri ((N_nil N) ×ₘ I_borel ×ₘ Inf_nil) ⊔ unSplitTri (N_ms ×ₘ I_nil ×ₘ Inf_nil) = unSplitTri (N_ms ×ₘ I_borel ×ₘ Inf_nil) := by have le_β : I_nil ×ₘ Inf_nil ≤ I_borel ×ₘ Inf_nil := sup_le_sup_right (comap_mono bot_le) _ rw [← comap_sup, commute bot_le le_β] private lemma eq_N_ms {N : ℕ} (N_ms : MeasurableSpace (Fin N → I)) : unSplitBi (N_ms ×ₘ Inf_nil) = unSplitTri (N_ms ×ₘ I_nil ×ₘ Inf_nil) := by simp only [prod, comap_bot, bot_le, sup_of_le_left, comap_comp, le_refl] congr 1 /-- Used in the construction for wp_meas, where a single dimension gets added between at the separation index separatiing the finite part with interesting MeasureSpace and the infinite part with boring MeasurableSpace. -/ lemma commute_with_add_dim {N : ℕ} (N_ms : MeasurableSpace (Fin N → I)) : unSplitTri ((N_nil N) ×ₘ I_borel ×ₘ Inf_nil) ⊔ unSplitBi (N_ms ×ₘ Inf_nil) = unSplitTri (N_ms ×ₘ I_borel ×ₘ Inf_nil) := by rw [eq_N_ms N_ms] exact commute_over_tri N_ms abbrev N_nil_I_borel (N : ℕ) := unSplitTri ((N_nil N) ×ₘ I_borel ×ₘ Inf_nil) abbrev N_borel_I_borel (N : ℕ) := unSplitTri ((N_borel N) ×ₘ I_borel ×ₘ Inf_nil) /-- this helper relates `unSplitTri` at `N` to `unSplitBi` at `N+1` by absorbing the middle `I`-coordinate into the finite (first) part. -/ lemma unSplitTri_eq_unSplitBi_succ {N : ℕ} (ms_N : MeasurableSpace (Fin N → I)) (ms_I : MeasurableSpace I) : unSplitTri (ms_N ×ₘ ms_I ×ₘ Inf_nil) = @unSplitBi (N + 1) ((MeasurableSpace.comap (· ∘ Fin.castSucc) ms_N ⊔ MeasurableSpace.comap (fun f => f (Fin.last N)) ms_I) ×ₘ Inf_nil) := by simp +decide only [unSplitTri, prod, comap_bot, bot_le, sup_of_le_left, comap_comp, comap_sup, unSplitBi]; congr! 2 /-- `FiniteFootprint` for an arbitrary sub-σ-algebra on the first `N` coordinates combined with `I_borel` on coordinate `N`. -/ lemma ff_unSplitTri_I_borel {n : ℕ} (ms : MeasurableSpace (Fin n → I)) : ∃ n', FiniteFootprint n' (unSplitTri (ms ×ₘ I_borel ×ₘ Inf_nil)) := ⟨n + 1, _, unSplitTri_eq_unSplitBi_succ ms I_borel⟩ lemma ff_N_nil_I_borel {N : ℕ} : ∃ n, FiniteFootprint n (N_nil_I_borel N) := ff_unSplitTri_I_borel (N_nil N) lemma ff_N_borel_I_borel {N : ℕ} : ∃ n, FiniteFootprint n (N_borel_I_borel N) := ff_unSplitTri_I_borel (N_borel N) lemma N_nil_I_borel_le_Inf_borel (N : ℕ) : N_nil_I_borel N ≤ Inf_borel := by refine MeasurableSpace.comap_le_iff_le_map.mpr ?_ simp only [prod, comap_bot, bot_le, sup_of_le_left, comap_comp, sup_of_le_right, MeasurableSpace.map, MeasurableEquiv.measurableSet_preimage] exact MeasurableSpace.comap_le_iff_le_map.mpr (measurable_snd.fst) lemma N_borel_I_borel_le_Inf_borel (N : ℕ) : N_borel_I_borel N ≤ Inf_borel := by unfold N_borel_I_borel simp only [prod, N_borel, Inf_nil, comap_bot, bot_le, sup_of_le_left, comap_comp, comap_sup, sup_le_iff] constructor <;> intro s hs <;> rcases hs with ⟨t, ht, rfl⟩ · exact measurable_pi_lambda _ (fun _ => measurable_pi_apply _) ht · apply_rules [MeasurableSet.preimage, ht] fun_prop /-- The combined σ-algebra on first `N` coords + Borel on coord `N` is ≤ `Inf_borel`. -/ lemma unSplitTri_I_borel_le_Inf_borel {N : ℕ} (ms : MeasurableSpace (Fin N → I)) (hms : ms ≤ N_borel N) : unSplitTri (ms ×ₘ I_borel ×ₘ Inf_nil) ≤ Inf_borel := by refine trans ?_ ( N_borel_I_borel_le_Inf_borel N ) apply_rules [ MeasurableSpace.comap_mono, sup_le_sup_right ] @[fun_prop] lemma coordProj_measurable (n : ℕ) : @Measurable (ℕ → I) I (N_nil_I_borel n) _ (fun ω ↦ ω n) := (Measurable.comp (measurable_snd.fst)) (comap_measurable _) /-- The first component of `splitBi n ω` at index `i : Fin n` equals `ω ↑i`. -/ @[simp] lemma splitBi_fst_apply (n : ℕ) (ω : ℕ → I) (i : Fin n) : (splitBi n ω).1 i = ω i := rfl end HC open MeasureTheory MeasureTheory.Measure unitInterval open ProbabilityTheory (Kernel) variable {α β γ : Type*} [MeasurableSpace α] [MeasurableSpace β] [MeasurableSpace γ] structure MeasurableFun (α β : Type*) [MeasurableSpace α] [MeasurableSpace β] where /-- underlying function -/ toFun : α → β meas: Measurable toFun @[fun_prop] lemma measurable_MeasurableFun (f : MeasurableFun α β) : Measurable f.toFun := f.meas notation α " -m→ " β => MeasurableFun α β abbrev measurableFun_fst : (α × β) -m→ α := ⟨_ , measurable_fst⟩ abbrev measurableFun_snd : (α × β) -m→ β := ⟨_ , measurable_snd⟩ abbrev MeasurableFun.fst (f : α -m→ β × γ) : α -m→ β := ⟨_ , Measurable.fst f.2⟩ abbrev MeasurableFun.snd (f : α -m→ β × γ) : α -m→ γ := ⟨_ , Measurable.snd f.2⟩ instance instFunLikeMeasurableFun {α β : Type*} [MeasurableSpace α] [MeasurableSpace β] : FunLike (α -m→ β) α β where coe f := f.toFun coe_injective' f g h := by cases f; cases g; congr abbrev HC := ℕ → Set.Icc (0:ℝ) 1 instance : Inhabited HC where default := fun _ ↦ 0 /-- The Lebesgue measure on the Hilbert cube: the infinite product of uniform measures on the unit interval. -/ noncomputable abbrev lebHC : @ProbabilityMeasure HC HC.Inf_borel := ⟨Measure.infinitePiNat (fun _ => (MeasureTheory.volume : Measure unitInterval)), inferInstance⟩ noncomputable abbrev lebI : Measure I := volume /-- The semantic (native lean) uniform distribution in the interval [0,1]. This is the pushforward of Lebesgue measure on `I = Set.Icc 0 1` via the subtype coercion `↑ : I → ℝ`. -/ noncomputable def unif01_sem : Measure ℝ := Measure.map Subtype.val (MeasureSpace.volume (α := Set.Icc (0 : ℝ) 1)) instance : IsProbabilityMeasure unif01_sem := isProbabilityMeasure_map measurable_subtype_coe.aemeasurable -- this should be refactored into a type class, or use the `fun_prop` style, where -- lemmas constructing the `ff` property are annotated with `fun_prop` /-- A measurable function from `HC` with finite footprint. -/ structure RV (β : Type*) [msβ : MeasurableSpace β] extends @MeasurableFun HC β MeasurableSpace.pi _ where /-- Finite footprint -/ ff : ∃ n, HC.FiniteFootprint n (msβ.comap toFun) namespace RV variable {α β : Type*} [MeasurableSpace α] [MeasurableSpace β] instance instFunLikeRV : FunLike (RV β) HC β where coe D := D.toFun coe_injective' f g h := by cases f; cases g; congr exact DFunLike.coe_injective h instance instCoeRV : Coe (RV β) (HC -m→ β) where coe D := D.toMeasurableFun instance : Mul (RV ℝ) where mul M N := ⟨⟨λ ω ↦ M ω * N ω, sorry⟩, sorry⟩ -- abbrev mul (M N : RV ℝ) : RV ℝ := ⟨⟨λ ω ↦ M ω * N ω, sorry⟩, sorry⟩ abbrev ite (E : RV Bool) (M N : RV α) : RV α := ⟨⟨λ ω ↦ if E ω then M ω else N ω, sorry⟩, sorry⟩ abbrev prod [MeasurableSpace α] [MeasurableSpace β] (f : RV α) (g : RV β) : RV (α × β) := ⟨⟨fun (r : HC) ↦ ((f r : α), (g r : β)), Measurable.prod f.meas g.meas⟩, by obtain ⟨n₁, h₁⟩ := f.ff obtain ⟨n₂, h₂⟩ := g.ff use max n₁ n₂ simp only sorry ⟩ notation x " ;; " xs => RV.prod x xs abbrev comp [MeasurableSpace β] [MeasurableSpace γ] (g : β -m→ γ) (f : RV β) : RV γ := ⟨⟨g ∘ f, Measurable.comp g.meas f.meas⟩, sorry⟩ notation g " ∘ᵣ " f => RV.comp g f def coordProj (n : ℕ) : RV I := ⟨⟨fun ω ↦ ω n, by fun_prop⟩, sorry⟩ abbrev fProd {α β γ : Type*} (f : α → β) (g : α → γ) (x : α) : β × γ := (f x, g x) notation " ⟨ " f ", " g " ⟩ᶠ " => fProd f g -- instance foo : Unique (Fin 0 → φ) := inferInstance abbrev ff_const [msβ : MeasurableSpace β] (constVal : β) : ∃ n, HC.FiniteFootprint n (msβ.comap (λ _a : HC ↦ constVal)) := by use 0, ⊥ rw [MeasurableSpace.comap_const] unfold HC.unSplitBi rw [MeasurableSpace.comap_prodMk] simp /-- The constant function is an RV. This is useful for representing the dentotation of programs like `unif01` or `flip` where the `constVal` is the advertised measure, and the ignored parameters are the random variable context. -/ abbrev const (constVal : β) [MeasurableSpace β] : RV β := ⟨⟨λ _a : HC ↦ constVal, measurable_const⟩, ff_const constVal⟩ end RV