From 46251e29eebeb85b27cd39ffeb74485cc52afb8d Mon Sep 17 00:00:00 2001 From: Remy Degenne Date: Thu, 29 Oct 2026 18:36:01 +0100 Subject: [PATCH] AI review --- LMLTutorial/Pages/BasicProbability.lean | 5 +- LMLTutorial/Pages/DefiningAlgorithm.lean | 21 +- LMLTutorial/Pages/Installation.lean | 8 + LMLTutorial/Pages/MarkovKernels.lean | 6 +- LMLTutorial/Pages/Martingales.lean | 28 +- LeanMachineLearning.lean | 35 +- .../Analysis/Complex/Exponential.lean | 29 + .../Analysis/Convex/Bregman/Basic.lean | 5 +- .../ForMathlib/Analysis/Convex/Integral.lean | 40 ++ .../Analysis/Convex/Subgradient/Basic.lean | 4 +- .../Analysis/Convex/Subgradient/Deriv.lean | 47 +- .../ForMathlib/Basic/Unique.lean | 21 + .../KullbackLeibler/ChainRule.lean | 59 +- .../KullbackLeibler/CompProd.lean | 75 ++- .../KullbackLeibler/Convex.lean | 1 + .../KullbackLeibler/DataProcessing.lean | 60 +- .../KullbackLeibler/MapSequence.lean | 29 +- .../KullbackLeibler/Restrict.lean | 16 +- .../MeasureTheory/Group/Arithmetic.lean | 38 ++ .../ForMathlib/MeasureTheory/Measurable.lean | 63 -- .../MeasureTheory/MeasurableSpace/Basic.lean | 29 + .../MeasurableSpace/Constructions.lean | 48 ++ .../MeasurableSpace/Embedding.lean | 6 +- .../MeasurableSpace/Instances.lean | 32 + .../MeasureTheory/MeasurableSpace/Sigma.lean | 62 +- .../MeasureTheory/Measure/AEMeasurable.lean | 33 + .../Measure/AbsolutelyContinuous.lean | 3 +- .../Measure/Decomposition/Lebesgue.lean | 54 ++ .../MeasureTheory/Measure/Dirac.lean | 30 + .../MeasureTheory/Measure/FiniteMeasure.lean | 68 ++ .../Measure/ProbabilityMeasure.lean | 28 + .../MeasureTheory/Measure/WithDensity.lean | 48 ++ .../MeasureTheory/Order/MeasurableArg.lean | 39 +- .../MeasureTheory/OuterMeasure/Basic.lean | 4 +- .../Order/Interval/Finset/Basic.lean | 23 + .../Interval/{Finset.lean => Finset/Nat.lean} | 12 +- .../Probability/ConditionalProbability.lean | 38 +- .../Probability/HasCondDistrib.lean | 216 +++---- .../ForMathlib/Probability/HasLaw.lean | 160 +++-- .../ForMathlib/Probability/IdentDistrib.lean | 81 +++ .../{IndepFun.lean => Basic.lean} | 124 ++-- .../Probability/Independence/CondDistrib.lean | 592 ------------------ .../Independence/CondIndepFun.lean | 103 --- .../Probability/Independence/Conditional.lean | 267 ++++++++ .../{IndepInfinitePi.lean => InfinitePi.lean} | 41 +- .../Independence/Kernel/IndepFun.lean | 42 ++ .../ForMathlib/Probability/Integrable.lean | 29 - .../ForMathlib/Probability/Kernel/Basic.lean | 10 +- .../Kernel/Composition/IntegralCompProd.lean | 60 +- .../Kernel/Composition/Lemmas.lean | 25 +- .../Kernel/Composition/MeasureCompProd.lean | 56 +- .../Kernel/Composition/WithDensity.lean | 50 ++ .../Probability/Kernel/CondDistrib.lean | 264 ++++++++ .../Kernel/IonescuTulcea/Traj.lean | 24 +- .../{KernelSub.lean => RadonNikodym.lean} | 63 +- .../ForMathlib/Probability/Kernel/Sigma.lean | 6 +- .../Probability/Moments/SubExponential.lean | 16 +- .../Probability/Moments/SubGaussian.lean | 12 +- .../Probability/Process/HittingTime.lean | 2 + .../ForMathlib/Probability/WithDensity.lean | 79 --- .../Topology/Instances/ENNReal/Lemmas.lean | 28 - .../Online/Bandit/Algorithms/ETC.lean | 46 +- .../Algorithms/Regret/BayesRegretTS.lean | 209 ++++++- .../Online/Bandit/Algorithms/Regret/ETC.lean | 36 +- .../Online/Bandit/Algorithms/Regret/UCB.lean | 88 ++- .../Online/Bandit/Algorithms/TS.lean | 35 +- .../Online/Bandit/Algorithms/UCB.lean | 42 +- .../Online/Bandit/ArrayProbSpace.lean | 139 ++-- .../Online/Bandit/BayesRegret.lean | 28 +- .../{SumRewards.lean => Concentration.lean} | 473 ++++---------- LeanMachineLearning/Online/Bandit/Regret.lean | 43 +- .../Online/Bandit/RewardByCountMeasure.lean | 119 ++-- .../SequentialLearning/ActionIndicator.lean | 16 +- .../SequentialLearning/Algorithm.lean | 100 ++- .../SequentialLearning/AlgorithmDensity.lean | 52 +- .../AlgorithmDensityBayes.lean | 48 +- .../SequentialLearning/Algorithms/Markov.lean | 134 ++-- .../Algorithms/RandomSampling/Basic.lean | 26 +- .../Algorithms/RandomSampling/Tendsto.lean | 164 ++--- .../Algorithms/RoundRobin.lean | 39 +- .../Algorithms/Uniform.lean | 16 +- .../BayesStationaryEnv.lean | 154 ++--- .../SequentialLearning/Comap.lean | 8 +- .../SequentialLearning/Deterministic.lean | 112 ++-- .../DivergenceDecomposition.lean | 87 +-- .../SequentialLearning/EvaluationEnv.lean | 83 ++- .../FeedbackMartingale.lean | 90 +-- .../SequentialLearning/FiniteActions.lean | 214 +++---- .../SequentialLearning/IdentificationAlg.lean | 19 +- .../IonescuTulceaSpace.lean | 89 ++- .../SequentialLearning/Means.lean | 84 ++- .../SequentialLearning/README.md | 34 +- .../SequentialLearning/StationaryEnv.lean | 108 ++-- .../SequentialLearning/StoppedHistory.lean | 34 +- .../SequentialLearning/SumRewards.lean | 127 +++- 95 files changed, 3649 insertions(+), 2944 deletions(-) create mode 100644 LeanMachineLearning/ForMathlib/Analysis/Complex/Exponential.lean create mode 100644 LeanMachineLearning/ForMathlib/Analysis/Convex/Integral.lean create mode 100644 LeanMachineLearning/ForMathlib/Basic/Unique.lean create mode 100644 LeanMachineLearning/ForMathlib/MeasureTheory/Group/Arithmetic.lean delete mode 100644 LeanMachineLearning/ForMathlib/MeasureTheory/Measurable.lean create mode 100644 LeanMachineLearning/ForMathlib/MeasureTheory/MeasurableSpace/Basic.lean create mode 100644 LeanMachineLearning/ForMathlib/MeasureTheory/MeasurableSpace/Constructions.lean create mode 100644 LeanMachineLearning/ForMathlib/MeasureTheory/MeasurableSpace/Instances.lean create mode 100644 LeanMachineLearning/ForMathlib/MeasureTheory/Measure/AEMeasurable.lean create mode 100644 LeanMachineLearning/ForMathlib/MeasureTheory/Measure/Decomposition/Lebesgue.lean create mode 100644 LeanMachineLearning/ForMathlib/MeasureTheory/Measure/Dirac.lean create mode 100644 LeanMachineLearning/ForMathlib/MeasureTheory/Measure/FiniteMeasure.lean create mode 100644 LeanMachineLearning/ForMathlib/MeasureTheory/Measure/ProbabilityMeasure.lean create mode 100644 LeanMachineLearning/ForMathlib/MeasureTheory/Measure/WithDensity.lean create mode 100644 LeanMachineLearning/ForMathlib/Order/Interval/Finset/Basic.lean rename LeanMachineLearning/ForMathlib/Order/Interval/{Finset.lean => Finset/Nat.lean} (53%) create mode 100644 LeanMachineLearning/ForMathlib/Probability/IdentDistrib.lean rename LeanMachineLearning/ForMathlib/Probability/Independence/{IndepFun.lean => Basic.lean} (72%) delete mode 100644 LeanMachineLearning/ForMathlib/Probability/Independence/CondDistrib.lean delete mode 100644 LeanMachineLearning/ForMathlib/Probability/Independence/CondIndepFun.lean create mode 100644 LeanMachineLearning/ForMathlib/Probability/Independence/Conditional.lean rename LeanMachineLearning/ForMathlib/Probability/Independence/{IndepInfinitePi.lean => InfinitePi.lean} (53%) create mode 100644 LeanMachineLearning/ForMathlib/Probability/Independence/Kernel/IndepFun.lean delete mode 100644 LeanMachineLearning/ForMathlib/Probability/Integrable.lean create mode 100644 LeanMachineLearning/ForMathlib/Probability/Kernel/Composition/WithDensity.lean create mode 100644 LeanMachineLearning/ForMathlib/Probability/Kernel/CondDistrib.lean rename LeanMachineLearning/ForMathlib/Probability/Kernel/{KernelSub.lean => RadonNikodym.lean} (72%) delete mode 100644 LeanMachineLearning/ForMathlib/Probability/WithDensity.lean delete mode 100644 LeanMachineLearning/ForMathlib/Topology/Instances/ENNReal/Lemmas.lean rename LeanMachineLearning/Online/Bandit/{SumRewards.lean => Concentration.lean} (53%) diff --git a/LMLTutorial/Pages/BasicProbability.lean b/LMLTutorial/Pages/BasicProbability.lean index dc9d62b4..0d00b372 100644 --- a/LMLTutorial/Pages/BasicProbability.lean +++ b/LMLTutorial/Pages/BasicProbability.lean @@ -98,7 +98,8 @@ If we define a measure `P` on `Ω`, we can talk about the law or distribution of The law of `X` is a measure on `E`, with value `P (X ⁻¹' s)` on any measurable set `s` of `E`. This is how we define the map of the measure `P` by `X`, `Measure.map X P` or more succinctly `P.map X`. There is no specific notation for that law. -To say that `X` is Gaussian with mean 0 and variance 1, write `P.map X = gaussianReal 0 1`. +To say that `X` is Gaussian with mean 0 and variance 1, write `HasLaw X (gaussianReal 0 1) P`. +`HasLaw X μ P` states that `X` is almost everywhere measurable and that `P.map X = μ`; it is the preferred way to state the law of a random variable. The expectation of `X` is the integral of that function against the measure `P`, written `∫ ω, X ω ∂P`. The notation `P[X]` is shorthand for that expectation. In a `MeasureSpace`, we can further use the notation `𝔼[X]`. @@ -119,7 +120,7 @@ Any countable type with measurable singletons is a `DiscreteMeasurableSpace`, fo A way to define a probability measure on a discrete space `Ω` is to use the type `PMF Ω`, which stands for probability mass function. `PMF Ω` is the subtype of functions `Ω → ℝ≥0∞` that sum to 1. One can get a `Measure Ω` from `p : PMF Ω` with `p.toMeasure`. -When writing a theorem about probability on finite spaces, it preferable to write it for a `Measure` in a `DiscreteMeasurableSpace` than for a `PMF` for better integration with the library. +When writing a theorem about probability on finite spaces, it is preferable to write it for a `Measure` in a `DiscreteMeasurableSpace` than for a `PMF` for better integration with the library. # Additional typeclasses on measurable spaces diff --git a/LMLTutorial/Pages/DefiningAlgorithm.lean b/LMLTutorial/Pages/DefiningAlgorithm.lean index 5fb570ed..31a07249 100644 --- a/LMLTutorial/Pages/DefiningAlgorithm.lean +++ b/LMLTutorial/Pages/DefiningAlgorithm.lean @@ -65,7 +65,7 @@ That kernel is called `Algorithm.policyZero`. Many settings have no observations at all: the algorithm sees only the past rounds. Those are described by taking `𝓞 = Unit`, and we write `noObs Ω` for the corresponding (constant) observation process. -If the algorithms actions are not random, we can use the `Algorithm.deterministic` definition to build an algorithm from the data of a measurable function for the action at each time, as a function of the history before that time and of the current observation. +If the algorithm's actions are not random, we can use the `Algorithm.deterministic` definition to build an algorithm from the data of a measurable function for the action at each time, as a function of the history before that time and of the current observation. The first action is the value of that function at time `0` on the empty history. {docstring Algorithm.deterministic} @@ -91,7 +91,7 @@ If furthermore those sequences do not change with time, we can use the `Environm {docstring Environment.stationary} -When there is no observation (`𝓞 = Unit`), the feedback depends only on the last action. `Environment.banditSeq` builds such an environment from a sequence of kernels `ν : ℕ → Kernel 𝓐 𝓨`, and `Environment.bandit` from a single kernel `ν : Kernel 𝓐 𝓨` used at every time. +When there is no observation (`𝓞 = Unit`) and the feedback depends only on the current action (and possibly on the time), we get bandit environments. `Environment.banditSeq` builds such an environment from a sequence of kernels `ν : ℕ → Kernel 𝓐 𝓨`, and `Environment.bandit` from a single kernel `ν : Kernel 𝓐 𝓨` used at every time. {docstring Environment.bandit} @@ -106,8 +106,10 @@ This is done by the `IsAlgEnvSeq` structure. This structure takes as input three sequences of random variables (three stochastic processes), `O`, `A` and `Y`, which represent the observations, actions and feedback generated by the interaction of the algorithm with the environment. It states that those sequences are measurable and that they have the correct conditional distributions given by the algorithm and environment. The measurable space `Ω` and the measure `P` are not imposed: they can be chosen as we want, as long as the conditions of `IsAlgEnvSeq` are satisfied. -This definition requires `𝓐` and `𝓨` to be nonempty standard Borel spaces, because Mathlib's theory about conditional distributions requires those assumptions. -All spaces of interest in machine learning are standard Borel, so this is not a restriction. +The conditional distributions are expressed with `HasCondDistrib`: `HasCondDistrib Y X κ P` states that the joint law of `(X, Y)` under `P` is the law of `X` composed with the kernel `κ`. +This definition makes no assumption on the measurable spaces. +Some results about algorithm-environment sequences, for example those using Mathlib's conditional distribution `condDistrib` or conditional independence, require the spaces to be nonempty standard Borel spaces. +All spaces of interest in machine learning are standard Borel, so this is not a restriction in practice. Given any algorithm and environment, there always exists a sequence of actions and feedback that satisfies `IsAlgEnvSeq` by the Ionescu-Tulcea theorem. However other constructions of such sequences are possible, and it is easier to work with generic sequences satisfying `IsAlgEnvSeq` than with a specific construction. @@ -148,7 +150,7 @@ The first action of the algorithm is `UCB.nextArm K c 0` applied to the empty hi ## A theorem about UCB We can now state a theorem about the regret of UCB in a stochastic bandit environment (which we won't prove here). -Let's first define the regret, which for stochastic bandits is the difference between the mean rewar that the algorithm would have obtained if it played always the best action, and the sum of mean rewards of the actions played. +Let's first define the regret, which for stochastic bandits is the difference between the sum of the mean rewards that the algorithm would have obtained if it had always played the best action, and the sum of the mean rewards of the actions played. {docstring Bandits.regret} @@ -161,7 +163,7 @@ We can now state the regret bound for UCB. The arguments of the theorem are the following: - `h` states that the sequence of actions and rewards we are considering is generated by the interaction of UCB with parameter `c * σ2` with the stationary environment defined by `ν`. - `hν` states that the reward distribution of each arm is subgaussian with variance proxy `σ2`. -- `hσ2` and `hc` state that the parameters `σ2` and `c` are positive. +- `hσ2` and `hc` state that the parameters `σ2` and `c` are positive (`σ2` is a nonnegative real number, so `σ2 ≠ 0` means that it is positive). - `n` is the time horizon. The theorem gives an upper bound on the expected regret of UCB at time `n`. @@ -170,15 +172,16 @@ The theorem gives an upper bound on the expected regret of UCB at time `n`. # Building vs analyzing algorithms -When building an algorithm, we describe it with functions from the history and the current observation `(Hist 𝓞 𝓐 R n × 𝓞)` to the action space `𝓐`. +When building an algorithm, we describe it with functions from the history and the current observation `(Hist 𝓞 𝓐 𝓨 n × 𝓞)` to the action space `𝓐`. Thus, to construct UCB, we used the following empirical mean function. {docstring empMean'} -When analyzing an algorithm, we work with sequences of actions and rewards `A : ℕ → Ω → 𝓐` and `R' : ℕ → Ω → R` that satisfy `IsAlgEnvSeq`. +When analyzing an algorithm, we work with sequences of actions and rewards `A : ℕ → Ω → 𝓐` and `R : ℕ → Ω → ℝ` that satisfy `IsAlgEnvSeq`. For the analysis, the empirical mean is defined as a stochastic process on the same probability space `Ω`. {docstring empMean} -`empMean A R' a` is a stochastic process with type `ℕ → Ω → ℝ` that gives the empirical mean of action `a` at each time. +`empMean A R a` is a stochastic process with type `ℕ → Ω → ℝ` that gives the empirical mean of action `a` at each time. +The two definitions agree along any sequence: `empMean A R a n ω = empMean' n (history O A R n ω) a` (lemma `empMean_eq_empMean'`), which is how properties of the algorithm, stated with `empMean'`, are transferred to the analysis, stated with `empMean`. diff --git a/LMLTutorial/Pages/Installation.lean b/LMLTutorial/Pages/Installation.lean index 2b5a0787..a2c852ca 100644 --- a/LMLTutorial/Pages/Installation.lean +++ b/LMLTutorial/Pages/Installation.lean @@ -60,6 +60,14 @@ name = "LeanMachineLearning" git = "https://github.com/LeanMachineLearning/LML" ``` +Your project must use the same version of Lean as the library: copy the `lean-toolchain` file of the library into your project. +Then run +``` +lake update LeanMachineLearning +lake exe cache get +``` +to download the library and its dependencies, and to get the precompiled Mathlib cache. + # Testing the installation Create a new Lean file in your project and add the following code: diff --git a/LMLTutorial/Pages/MarkovKernels.lean b/LMLTutorial/Pages/MarkovKernels.lean index 5c339508..cda5ddcc 100644 --- a/LMLTutorial/Pages/MarkovKernels.lean +++ b/LMLTutorial/Pages/MarkovKernels.lean @@ -72,7 +72,7 @@ However, the measurability is important in non-discrete spaces. Kernels are fully specified by their action on measurable functions. -That is, if two kernels `κ η : Kernel 𝓧 𝓨` are such that for every measurable function `f : 𝓨 → ℝ≥0∞` and every `x : 𝓧`, `∫ y, f y ∂(κ x) = ∫ y, f y ∂(η x)`, then `κ = η`. +That is, if two kernels `κ η : Kernel 𝓧 𝓨` are such that for every measurable function `f : 𝓨 → ℝ≥0∞` and every `x : 𝓧`, `∫⁻ y, f y ∂(κ x) = ∫⁻ y, f y ∂(η x)`, then `κ = η`. ```lean example (κ η : Kernel 𝓧 𝓨) : κ = η ↔ ∀ x f, Measurable f → ∫⁻ y, f y ∂(κ x) = ∫⁻ y, f y ∂(η x) := @@ -82,7 +82,7 @@ Another way to show that two kernels are equal is to show that their values `κ # Classes of kernels -A kernel `κ : 𝓧 ⟶ 𝓨` is a Markov kernel if `κ x` is a probability measure for every `x : 𝓧`. +A kernel `κ : Kernel 𝓧 𝓨` is a Markov kernel if `κ x` is a probability measure for every `x : 𝓧`. If the supremum of `κ x univ` over `x : 𝓧` is finite, then `κ` is said to be a finite kernel. Finally, Mathlib also contains the class of s-finite kernels, which are kernels that can be expressed as a countable sum of finite kernels. Those three properties are denoted by typeclasses {InlineLean.module}`[IsMarkovKernel κ]`, `[IsFiniteKernel κ]` and `[IsSFiniteKernel κ]` respectively. @@ -106,7 +106,7 @@ Among the deterministic kernels, a few play a special role. The identity kernel `Kernel.id : Kernel 𝓧 𝓧` is the deterministic kernel associated with the identity function: it maps `x` to the Dirac measure at `x`. The copy kernel `Kernel.copy : Kernel 𝓧 (𝓧 × 𝓧)` maps `x` to the Dirac measure at `(x, x)`. The discard kernel `Kernel.discard : Kernel 𝓧 Unit` maps `x` to the unique probability measure on the one-point space `Unit`. -Another useful (not deterministic) kernel is the constant kernel `Kernel.const μ : Kernel Ω 𝓧` which maps every point of `Ω` to the same probability measure `μ` on `𝓧`. +Another useful (not deterministic) kernel is the constant kernel `Kernel.const Ω μ : Kernel Ω 𝓧` which maps every point of `Ω` to the same measure `μ` on `𝓧`. It is a Markov kernel if `μ` is a probability measure. # Composition diff --git a/LMLTutorial/Pages/Martingales.lean b/LMLTutorial/Pages/Martingales.lean index 3c4cb708..c7c93e58 100644 --- a/LMLTutorial/Pages/Martingales.lean +++ b/LMLTutorial/Pages/Martingales.lean @@ -38,7 +38,7 @@ variable {Ω : Type*} {mΩ : MeasurableSpace Ω} # Stochastic processes, filtrations, and martingales -We define a measure space {lean}`Ω`, with a probability mesure {lean}`(P : Measure Ω)`. +We define a measurable space {lean}`Ω`, with a probability measure {lean}`(P : Measure Ω)`. ```lean variable {Ω : Type*} {mΩ : MeasurableSpace Ω} @@ -86,29 +86,14 @@ example {Y : ℕ → Ω → ℝ} (hX : Submartingale Y 𝓕 P) {i j : ℕ} (hij ``` *Almost everywhere martingale convergence theorem*: An L¹-bounded submartingale converges -almost everywhere to a `⨆ n, ℱ n`-measurable function. +almost everywhere to a `⨆ n, 𝓕 n`-measurable function, its limit process `𝓕.limitProcess Y P`. +This is the Mathlib lemma `Submartingale.ae_tendsto_limitProcess`. ```lean example {Y : ℕ → Ω → ℝ} (hY : Submartingale Y 𝓕 P) {R : ℝ≥0} (hbdd : ∀ n, eLpNorm (Y n) 1 P ≤ R) : - ∀ᵐ ω ∂P, Tendsto (Y · ω) atTop (𝓝 (𝓕.limitProcess Y P ω)) := by - classical - suffices ∃ g, StronglyMeasurable[⨆ n, 𝓕 n] g ∧ ∀ᵐ ω ∂P, Tendsto (Y · ω) atTop (𝓝 (g ω)) by - exact Filtration.HasLimitProcess.ae_tendsto_limitProcess this - set g' : Ω → ℝ := fun ω ↦ if h : ∃ c, Tendsto (Y · ω) atTop (𝓝 c) then h.choose else 0 - have hle : ⨆ n, 𝓕 n ≤ mΩ := sSup_le fun m ⟨n, hn⟩ ↦ hn ▸ 𝓕.le _ - have hg' : ∀ᵐ ω ∂P.trim hle, Tendsto (Y · ω) atTop (𝓝 (g' ω)) := by - filter_upwards [hY.exists_ae_trim_tendsto_of_bdd hbdd] with ω hω - simp_rw [g', dif_pos hω] - exact hω.choose_spec - have hg'm : AEStronglyMeasurable[⨆ n, 𝓕 n] g' (P.trim hle) := - (@aemeasurable_of_tendsto_metrizable_ae' _ _ (⨆ n, 𝓕 n) _ _ _ _ _ _ _ - (fun n ↦ ((hY.stronglyMeasurable n).measurable.mono (le_sSup ⟨n, rfl⟩ : 𝓕 n ≤ ⨆ n, 𝓕 n) - le_rfl).aemeasurable) hg').aestronglyMeasurable - obtain ⟨g, hgm, hae⟩ := hg'm - have hg : ∀ᵐ ω ∂P.trim hle, Tendsto (Y · ω) atTop (𝓝 (g ω)) := by - filter_upwards [hae, hg'] with ω hω hg'ω using hω ▸ hg'ω - exact ⟨g, hgm, measure_eq_zero_of_trim_eq_zero hle hg⟩ + ∀ᵐ ω ∂P, Tendsto (Y · ω) atTop (𝓝 (𝓕.limitProcess Y P ω)) := + hY.ae_tendsto_limitProcess hbdd ``` # Stopping times @@ -124,7 +109,8 @@ example (i : ℕ) : MeasurableSet[𝓕 i] {ω | τ ω ≤ i} := hτ.measurableSe *The optional stopping theorem* (fair game theorem): an adapted integrable process `Y` is a submartingale if and only if for all bounded stopping times `τ` and `π` such that `τ ≤ π`, the -stopped value of `Y` at `τ` has expectation smaller than its stopped value at `π`. +stopped value of `Y` at `τ` has expectation smaller than or equal to that of its stopped value at +`π`. ```lean example {Y : ℕ → Ω → ℝ} (hadp : StronglyAdapted 𝓕 Y) (hint : ∀ i, Integrable (Y i) P) : diff --git a/LeanMachineLearning.lean b/LeanMachineLearning.lean index 992ca486..668d1294 100644 --- a/LeanMachineLearning.lean +++ b/LeanMachineLearning.lean @@ -1,44 +1,57 @@ module -- shake: keep-all --deprecated_module: ignore +public import LeanMachineLearning.ForMathlib.Analysis.Complex.Exponential public import LeanMachineLearning.ForMathlib.Analysis.Convex.Bregman.Basic +public import LeanMachineLearning.ForMathlib.Analysis.Convex.Integral public import LeanMachineLearning.ForMathlib.Analysis.Convex.Subgradient.Basic public import LeanMachineLearning.ForMathlib.Analysis.Convex.Subgradient.Deriv +public import LeanMachineLearning.ForMathlib.Basic.Unique public import LeanMachineLearning.ForMathlib.InformationTheory.KullbackLeibler.ChainRule public import LeanMachineLearning.ForMathlib.InformationTheory.KullbackLeibler.CompProd public import LeanMachineLearning.ForMathlib.InformationTheory.KullbackLeibler.Convex public import LeanMachineLearning.ForMathlib.InformationTheory.KullbackLeibler.DataProcessing public import LeanMachineLearning.ForMathlib.InformationTheory.KullbackLeibler.MapSequence public import LeanMachineLearning.ForMathlib.InformationTheory.KullbackLeibler.Restrict -public import LeanMachineLearning.ForMathlib.MeasureTheory.Measurable +public import LeanMachineLearning.ForMathlib.MeasureTheory.Group.Arithmetic +public import LeanMachineLearning.ForMathlib.MeasureTheory.MeasurableSpace.Basic +public import LeanMachineLearning.ForMathlib.MeasureTheory.MeasurableSpace.Constructions public import LeanMachineLearning.ForMathlib.MeasureTheory.MeasurableSpace.Embedding +public import LeanMachineLearning.ForMathlib.MeasureTheory.MeasurableSpace.Instances public import LeanMachineLearning.ForMathlib.MeasureTheory.MeasurableSpace.Sigma +public import LeanMachineLearning.ForMathlib.MeasureTheory.Measure.AEMeasurable public import LeanMachineLearning.ForMathlib.MeasureTheory.Measure.AbsolutelyContinuous +public import LeanMachineLearning.ForMathlib.MeasureTheory.Measure.Decomposition.Lebesgue +public import LeanMachineLearning.ForMathlib.MeasureTheory.Measure.Dirac +public import LeanMachineLearning.ForMathlib.MeasureTheory.Measure.FiniteMeasure +public import LeanMachineLearning.ForMathlib.MeasureTheory.Measure.ProbabilityMeasure +public import LeanMachineLearning.ForMathlib.MeasureTheory.Measure.WithDensity public import LeanMachineLearning.ForMathlib.MeasureTheory.Order.Lattice public import LeanMachineLearning.ForMathlib.MeasureTheory.Order.MeasurableArg public import LeanMachineLearning.ForMathlib.MeasureTheory.OuterMeasure.Basic -public import LeanMachineLearning.ForMathlib.Order.Interval.Finset +public import LeanMachineLearning.ForMathlib.Order.Interval.Finset.Basic +public import LeanMachineLearning.ForMathlib.Order.Interval.Finset.Nat public import LeanMachineLearning.ForMathlib.Probability.ConditionalProbability public import LeanMachineLearning.ForMathlib.Probability.HasCondDistrib public import LeanMachineLearning.ForMathlib.Probability.HasLaw -public import LeanMachineLearning.ForMathlib.Probability.Independence.CondDistrib -public import LeanMachineLearning.ForMathlib.Probability.Independence.CondIndepFun -public import LeanMachineLearning.ForMathlib.Probability.Independence.IndepFun -public import LeanMachineLearning.ForMathlib.Probability.Independence.IndepInfinitePi -public import LeanMachineLearning.ForMathlib.Probability.Integrable +public import LeanMachineLearning.ForMathlib.Probability.IdentDistrib +public import LeanMachineLearning.ForMathlib.Probability.Independence.Basic +public import LeanMachineLearning.ForMathlib.Probability.Independence.Conditional +public import LeanMachineLearning.ForMathlib.Probability.Independence.InfinitePi +public import LeanMachineLearning.ForMathlib.Probability.Independence.Kernel.IndepFun public import LeanMachineLearning.ForMathlib.Probability.Kernel.Basic public import LeanMachineLearning.ForMathlib.Probability.Kernel.Composition.IntegralCompProd public import LeanMachineLearning.ForMathlib.Probability.Kernel.Composition.Lemmas public import LeanMachineLearning.ForMathlib.Probability.Kernel.Composition.MapComap public import LeanMachineLearning.ForMathlib.Probability.Kernel.Composition.MeasureCompProd +public import LeanMachineLearning.ForMathlib.Probability.Kernel.Composition.WithDensity +public import LeanMachineLearning.ForMathlib.Probability.Kernel.CondDistrib public import LeanMachineLearning.ForMathlib.Probability.Kernel.IonescuTulcea.Traj -public import LeanMachineLearning.ForMathlib.Probability.Kernel.KernelSub public import LeanMachineLearning.ForMathlib.Probability.Kernel.MeasurableSpace +public import LeanMachineLearning.ForMathlib.Probability.Kernel.RadonNikodym public import LeanMachineLearning.ForMathlib.Probability.Kernel.Sigma public import LeanMachineLearning.ForMathlib.Probability.Moments.SubExponential public import LeanMachineLearning.ForMathlib.Probability.Moments.SubGaussian public import LeanMachineLearning.ForMathlib.Probability.Process.HittingTime -public import LeanMachineLearning.ForMathlib.Probability.WithDensity -public import LeanMachineLearning.ForMathlib.Topology.Instances.ENNReal.Lemmas public import LeanMachineLearning.Online.Bandit.Algorithms.ETC public import LeanMachineLearning.Online.Bandit.Algorithms.Regret.BayesRegretTS public import LeanMachineLearning.Online.Bandit.Algorithms.Regret.ETC @@ -47,9 +60,9 @@ public import LeanMachineLearning.Online.Bandit.Algorithms.TS public import LeanMachineLearning.Online.Bandit.Algorithms.UCB public import LeanMachineLearning.Online.Bandit.ArrayProbSpace public import LeanMachineLearning.Online.Bandit.BayesRegret +public import LeanMachineLearning.Online.Bandit.Concentration public import LeanMachineLearning.Online.Bandit.Regret public import LeanMachineLearning.Online.Bandit.RewardByCountMeasure -public import LeanMachineLearning.Online.Bandit.SumRewards public import LeanMachineLearning.SequentialLearning.ActionIndicator public import LeanMachineLearning.SequentialLearning.Algorithm public import LeanMachineLearning.SequentialLearning.AlgorithmDensity diff --git a/LeanMachineLearning/ForMathlib/Analysis/Complex/Exponential.lean b/LeanMachineLearning/ForMathlib/Analysis/Complex/Exponential.lean new file mode 100644 index 00000000..89de8c70 --- /dev/null +++ b/LeanMachineLearning/ForMathlib/Analysis/Complex/Exponential.lean @@ -0,0 +1,29 @@ +/- +Copyright (c) 2026 Rémy Degenne. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Rémy Degenne +-/ +module + +public import Mathlib.Analysis.Complex.Exponential + +/-! +# Bounds on the real exponential + +## Main statements + +* `Real.exp_le_one_add_add_of_abs_le_one`: for `|x| ≤ 1`, `exp x ≤ 1 + x + 3 / 4 * x ^ 2`. +-/ + +@[expose] public section + +namespace Real + +/-- Second-order bound on the exponential on `[-1, 1]`, from `Real.exp_bound`. -/ +lemma exp_le_one_add_add_of_abs_le_one {x : ℝ} (hx : |x| ≤ 1) : + exp x ≤ 1 + x + 3 / 4 * x ^ 2 := by + have h := Real.exp_bound hx (n := 2) two_pos + norm_num [Finset.sum_range_succ, Nat.factorial] at h + linarith [(abs_le.1 h).2] + +end Real diff --git a/LeanMachineLearning/ForMathlib/Analysis/Convex/Bregman/Basic.lean b/LeanMachineLearning/ForMathlib/Analysis/Convex/Bregman/Basic.lean index f73a2349..34ecbbf9 100644 --- a/LeanMachineLearning/ForMathlib/Analysis/Convex/Bregman/Basic.lean +++ b/LeanMachineLearning/ForMathlib/Analysis/Convex/Bregman/Basic.lean @@ -157,8 +157,9 @@ section Order variable {F' : Type*} [AddCommGroup F'] [Module R F'] [TopologicalSpace F'] [Preorder F'] [AddRightMono F'] -lemma bregDiv_le_of_le_of_eq {f₁ f₂ : E → F'} {x y : E} {J_y : E →L[R] F'} - (h_le : f₁ x ≤ f₂ x) (h_eq : f₁ y = f₂ y) : +/-- If `f₁ ≤ f₂` at `x` and `f₁ = f₂` at `y`, then `D_[f₁](x, y, J) ≤ D_[f₂](x, y, J)`. -/ +lemma bregDiv_le_of_le_of_eq {f₁ f₂ : E → F'} {x y : E} + (h_le : f₁ x ≤ f₂ x) (h_eq : f₁ y = f₂ y) (J_y : E →L[R] F') : D_[f₁](x, y, J_y) ≤ D_[f₂](x, y, J_y) := by simp [bregDiv, h_eq, h_le] diff --git a/LeanMachineLearning/ForMathlib/Analysis/Convex/Integral.lean b/LeanMachineLearning/ForMathlib/Analysis/Convex/Integral.lean new file mode 100644 index 00000000..5b77b345 --- /dev/null +++ b/LeanMachineLearning/ForMathlib/Analysis/Convex/Integral.lean @@ -0,0 +1,40 @@ +/- +Copyright (c) 2026 Rémy Degenne. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Rémy Degenne +-/ +module + +public import Mathlib.Analysis.Convex.Integral + +/-! +# Jensen's inequality for the norm to a power + +## Main statements + +* `norm_integral_rpow_le_integral_norm_rpow`: for a probability measure `μ` and `1 ≤ p < ∞`, + `‖∫ x, f x ∂μ‖ ^ p ≤ ∫ x, ‖f x‖ ^ p ∂μ`. +-/ + +@[expose] public section + +open MeasureTheory +open scoped ENNReal + +/-- **Jensen's inequality** for the convex function `x ↦ ‖x‖ ^ p`, `1 ≤ p`. -/ +lemma norm_integral_rpow_le_integral_norm_rpow + {α E : Type*} {mα : MeasurableSpace α} {μ : Measure α} [IsProbabilityMeasure μ] + [NormedAddCommGroup E] [NormedSpace ℝ E] {f : α → E} {p : ℝ≥0∞} + (hp1 : 1 ≤ p) (hp_top : p ≠ ∞) (hf : MemLp f p μ) : + ‖∫ x, f x ∂μ‖ ^ p.toReal ≤ ∫ x, ‖f x‖ ^ p.toReal ∂μ := by + have hp0 : p ≠ 0 := by positivity + have hp1' : 1 ≤ p.toReal := by simpa using ENNReal.toReal_mono hp_top hp1 + calc ‖∫ x, f x ∂μ‖ ^ p.toReal + _ ≤ (∫ x, ‖f x‖ ∂μ) ^ p.toReal := by + gcongr + exact norm_integral_le_integral_norm _ + _ ≤ ∫ x, ‖f x‖ ^ p.toReal ∂μ := + ConvexOn.map_integral_le (convexOn_rpow hp1') + (Real.continuous_rpow_const (by positivity)).continuousOn isClosed_Ici + (ae_of_all _ fun x ↦ norm_nonneg _) (hf.integrable hp1).norm + ((integrable_norm_rpow_iff hf.aestronglyMeasurable hp0 hp_top).mpr hf) diff --git a/LeanMachineLearning/ForMathlib/Analysis/Convex/Subgradient/Basic.lean b/LeanMachineLearning/ForMathlib/Analysis/Convex/Subgradient/Basic.lean index 578da360..7b2a69c5 100644 --- a/LeanMachineLearning/ForMathlib/Analysis/Convex/Subgradient/Basic.lean +++ b/LeanMachineLearning/ForMathlib/Analysis/Convex/Subgradient/Basic.lean @@ -22,7 +22,7 @@ while supporting constrained convex analysis. * `HasSubgradientWithinAt f g s x`: `g : E →L[R] F` is a subgradient of `f` at `x` on `s`. * `subdifferentialWithin R f s x`: The subdifferential set `∂[R, s, x](f)`. -## Main results +## Main statements * Monotonicity in the domain: `HasSubgradientWithinAt.mono`. * Chain rules: `HasSubgradientWithinAt.comp_affine` and `HasSubgradientWithinAt.comp`. @@ -161,7 +161,7 @@ lemma HasSubgradientWithinAt.of_le_of_eq [AddRightMono F] {f₁ f₂ : E → F} (h_sub : HasSubgradientWithinAt f₁ g s x) (h_le : ∀ y ∈ s, f₁ y ≤ f₂ y) (h_eq : f₁ x = f₂ x) : HasSubgradientWithinAt f₂ g s x := fun y hy ↦ le_trans (h_sub y hy) - (bregDiv_le_of_le_of_eq (h_le y hy) h_eq) + (bregDiv_le_of_le_of_eq (h_le y hy) h_eq g) section ModuleBasic diff --git a/LeanMachineLearning/ForMathlib/Analysis/Convex/Subgradient/Deriv.lean b/LeanMachineLearning/ForMathlib/Analysis/Convex/Subgradient/Deriv.lean index 8510abad..476e3375 100644 --- a/LeanMachineLearning/ForMathlib/Analysis/Convex/Subgradient/Deriv.lean +++ b/LeanMachineLearning/ForMathlib/Analysis/Convex/Subgradient/Deriv.lean @@ -14,14 +14,14 @@ public import Mathlib.Analysis.Calculus.LineDeriv.Basic This file establishes the connection between Fréchet derivatives (`HasFDerivWithinAt`, `HasFDerivAt`) and subgradients (`HasSubgradientWithinAt f g s x`) for convex functions. -## Main results +## Main statements * `HasFDerivWithinAt.hasSubgradientWithinAt`: A Fréchet derivative within `s` of a function convex on `s` is a subgradient on `s`. `HasFDerivAt.hasSubgradientWithinAt` is the special case of a derivative at a point. * `HasFDerivAt.eq_of_hasSubgradientWithinAt`: Uniqueness of the subgradient at an interior differentiable point. -* `HasFDerivAt.subdifferentialWithin_add`: Subdifferential sum rule when one component is +* `HasFDerivWithinAt.subdifferentialWithin_add`: Subdifferential sum rule when one component is Fréchet differentiable. -/ @@ -47,6 +47,17 @@ lemma HasFDerivWithinAt.tendsto_bregDiv_slope_zero have ht0 : t ≠ 0 := ht.2 simp [bregDiv, slope, smul_sub, ht0] +/-- Along a segment `[x, z]` in a convex set `s`, the linearization error of a function Fréchet +differentiable within `s` at `x`, scaled by `t⁻¹`, converges to `0` as the step size `t → 0⁺`. -/ +lemma HasFDerivWithinAt.tendsto_bregDiv_slope_zero_of_convex + (hderiv : HasFDerivWithinAt f g s x) (hs : Convex ℝ s) (hx : x ∈ s) {z : E} (hz : z ∈ s) : + Tendsto (fun t : ℝ ↦ t⁻¹ • D_[f](x + t • (z - x), x, g)) (𝓝[>] 0) (𝓝 0) := by + have h_sub : Set.Ioc (0 : ℝ) 1 ⊆ (fun t : ℝ ↦ x + t • (z - x)) ⁻¹' s \ {0} := + fun t ht ↦ ⟨hs.add_smul_sub_mem hx hz ⟨ht.1.le, ht.2⟩, ht.1.ne'⟩ + refine (hderiv.tendsto_bregDiv_slope_zero (z - x)).mono_left ?_ + rw [← nhdsWithin_Ioc_eq_nhdsGT zero_lt_one] + exact nhdsWithin_mono _ h_sub + /-- As the step size `t → 0⁺`, the linearization error of a Fréchet differentiable function scaled by `t⁻¹` converges to `0`. -/ lemma HasFDerivAt.tendsto_bregDiv_slope_zero @@ -78,12 +89,7 @@ lemma HasFDerivWithinAt.hasSubgradientWithinAt (hderiv : HasFDerivWithinAt f g s x) (hf : ConvexOn ℝ s f) (hx : x ∈ s) : HasSubgradientWithinAt f g s x := by intro z hz - have h_sub : Set.Ioc (0 : ℝ) 1 ⊆ (fun t : ℝ ↦ x + t • (z - x)) ⁻¹' s \ {0} := - fun t ht ↦ ⟨hf.1.add_smul_sub_mem hx hz ⟨ht.1.le, ht.2⟩, ht.1.ne'⟩ - have h_le : 𝓝[>] (0 : ℝ) ≤ 𝓝[(fun t : ℝ ↦ x + t • (z - x)) ⁻¹' s \ {0}] 0 := by - rw [← nhdsWithin_Ioc_eq_nhdsGT zero_lt_one] - exact nhdsWithin_mono _ h_sub - refine le_of_tendsto ((hderiv.tendsto_bregDiv_slope_zero (z - x)).mono_left h_le) ?_ + refine le_of_tendsto (hderiv.tendsto_bregDiv_slope_zero_of_convex hf.1 hx hz) ?_ filter_upwards [self_mem_nhdsWithin, nhdsWithin_le_nhds (eventually_le_nhds zero_lt_one)] with t (ht0 : 0 < t) ht1 using hf.bregDiv_slope_le hx hz g ht0 ht1 @@ -133,15 +139,17 @@ lemma subdifferentialWithin_const_eq (c : F) (hs : s ∈ 𝓝 x) : exact ⟨fun hsub ↦ (hasFDerivAt_const c x).eq_of_hasSubgradientWithinAt hs hsub, fun h_eq ↦ h_eq ▸ hasSubgradientWithinAt_const c⟩ -/-- Subdifferential sum rule when `f₁` is convex and Fréchet differentiable at `x` -and `f₂` is convex on `s`: `g` is a subgradient of `f₁ + f₂` at `x` if and only if +/-- Subdifferential sum rule when `f₁` is convex on `s` and Fréchet differentiable within `s` at +`x` and `f₂` is convex on `s`: `g` is a subgradient of `f₁ + f₂` at `x` if and only if `g - g₁` is a subgradient of `f₂` at `x`. -/ -lemma HasFDerivAt.hasSubgradientWithinAt_add_iff {f₁ f₂ : E → F} {g₁ g : E →L[ℝ] F} - (hderiv₁ : HasFDerivAt f₁ g₁ x) (hf₁ : ConvexOn ℝ s f₁) (hf₂ : ConvexOn ℝ s f₂) (hx : x ∈ s) : +lemma HasFDerivWithinAt.hasSubgradientWithinAt_add_iff {f₁ f₂ : E → F} {g₁ g : E →L[ℝ] F} + (hderiv₁ : HasFDerivWithinAt f₁ g₁ s x) (hf₁ : ConvexOn ℝ s f₁) (hf₂ : ConvexOn ℝ s f₂) + (hx : x ∈ s) : HasSubgradientWithinAt (f₁ + f₂) g s x ↔ HasSubgradientWithinAt f₂ (g - g₁) s x := by constructor · intro hg z hz - refine le_of_tendsto (by simpa using (hderiv₁.tendsto_bregDiv_slope_zero (z - x)).neg) ?_ + refine le_of_tendsto + (by simpa using (hderiv₁.tendsto_bregDiv_slope_zero_of_convex hf₂.1 hx hz).neg) ?_ filter_upwards [self_mem_nhdsWithin, nhdsWithin_le_nhds (eventually_le_nhds zero_lt_one)] with t (ht0 : 0 < t) ht1 have h_nonneg := smul_nonneg (inv_nonneg.mpr ht0.le) @@ -152,17 +160,18 @@ lemma HasFDerivAt.hasSubgradientWithinAt_add_iff {f₁ f₂ : E → F} {g₁ g : simpa using (hderiv₁.hasSubgradientWithinAt hf₁ hx).add h₂ /-- Subdifferential sum rule in set form: `∂[ℝ, s, x](f₁ + f₂) = {g₁} + ∂[ℝ, s, x](f₂)`. -/ -lemma HasFDerivAt.subdifferentialWithin_add {f₁ f₂ : E → F} {g₁ : E →L[ℝ] F} - (hderiv₁ : HasFDerivAt f₁ g₁ x) (hf₁ : ConvexOn ℝ s f₁) (hf₂ : ConvexOn ℝ s f₂) (hx : x ∈ s) : +lemma HasFDerivWithinAt.subdifferentialWithin_add {f₁ f₂ : E → F} {g₁ : E →L[ℝ] F} + (hderiv₁ : HasFDerivWithinAt f₁ g₁ s x) (hf₁ : ConvexOn ℝ s f₁) (hf₂ : ConvexOn ℝ s f₂) + (hx : x ∈ s) : ∂[ℝ, s, x](f₁ + f₂) = {g₁} + ∂[ℝ, s, x](f₂) := by ext g simp [mem_subdifferentialWithin, Set.singleton_add, hderiv₁.hasSubgradientWithinAt_add_iff hf₁ hf₂ hx, add_comm g₁, sub_eq_add_neg] -/-- When `f` is convex and Fréchet differentiable at `x ∈ s`, its subdifferential -is `g + ∂[ℝ, s, x](0)` (the derivative plus the normal cone to `s` at `x`). -/ -lemma HasFDerivAt.subdifferentialWithin_eq_add_zero - (hderiv : HasFDerivAt f g x) (hf : ConvexOn ℝ s f) (hx : x ∈ s) : +/-- When `f` is convex on `s` and Fréchet differentiable within `s` at `x ∈ s`, its +subdifferential is `g + ∂[ℝ, s, x](0)` (the derivative plus the normal cone to `s` at `x`). -/ +lemma HasFDerivWithinAt.subdifferentialWithin_eq_add_zero + (hderiv : HasFDerivWithinAt f g s x) (hf : ConvexOn ℝ s f) (hx : x ∈ s) : ∂[ℝ, s, x](f) = {g} + ∂[ℝ, s, x](fun _ : E ↦ (0 : F)) := by rw [← add_zero f] exact hderiv.subdifferentialWithin_add hf (convexOn_const (0 : F) hf.1) hx diff --git a/LeanMachineLearning/ForMathlib/Basic/Unique.lean b/LeanMachineLearning/ForMathlib/Basic/Unique.lean new file mode 100644 index 00000000..fd193a4f --- /dev/null +++ b/LeanMachineLearning/ForMathlib/Basic/Unique.lean @@ -0,0 +1,21 @@ +/- +Copyright (c) 2025 Rémy Degenne. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Rémy Degenne, Paulo Rauber +-/ +module + +public import Mathlib.Basic.Unique +public import Mathlib.Data.Prod.Basic + +/-! +# `Unique` instance for products + +A product of two types with a unique element has a unique element. +-/ + +@[expose] public section + +instance Prod.instUnique {α β : Type*} [Unique α] [Unique β] : Unique (α × β) where + default := (default, default) + uniq p := by simp [Prod.ext_iff, Unique.eq_default] diff --git a/LeanMachineLearning/ForMathlib/InformationTheory/KullbackLeibler/ChainRule.lean b/LeanMachineLearning/ForMathlib/InformationTheory/KullbackLeibler/ChainRule.lean index 7b9f054c..63212eb2 100644 --- a/LeanMachineLearning/ForMathlib/InformationTheory/KullbackLeibler/ChainRule.lean +++ b/LeanMachineLearning/ForMathlib/InformationTheory/KullbackLeibler/ChainRule.lean @@ -19,16 +19,13 @@ import Mathlib.Probability.Kernel.Composition.AbsolutelyContinuous The chain rule `klDiv_compProd_eq_add` expresses the conditional divergence as `klDiv (μ ⊗ₘ κ) (μ ⊗ₘ η)`. When the target space of the kernels is countably generated (or the source is countable), the function `a ↦ klDiv (κ a) (η a)` is measurable -(`measurable_klDiv_kernel`) and the conditional divergence is its integral: +(`measurable_klDiv_kernel`) and the conditional divergence is its integral. + +## Main statements * `klDiv_compProd_right_eq_lintegral`: `klDiv (μ ⊗ₘ κ) (μ ⊗ₘ η) = ∫⁻ a, klDiv (κ a) (η a) ∂μ`. * `klDiv_compProd_eq_add_lintegral`: `klDiv (μ ⊗ₘ κ) (ν ⊗ₘ η) = klDiv μ ν + ∫⁻ a, klDiv (κ a) (η a) ∂μ`. - -We also record the data processing inequality for the two projections -(`klDiv_le_compProd`, `klDiv_comp_le_compProd`) and the invariance of the divergence under -measurable embeddings (`klDiv_map_measurableEmbedding`) and measurable equivalences -(`klDiv_map_measurableEquiv`). -/ @[expose] public section @@ -40,47 +37,9 @@ namespace InformationTheory variable {α β γ : Type*} {mα : MeasurableSpace α} {mβ : MeasurableSpace β} {mγ : MeasurableSpace γ} -/-- The Kullback–Leibler divergence is invariant under measurable embeddings. -/ -lemma klDiv_map_measurableEmbedding (μ ν : Measure α) [IsFiniteMeasure μ] [IsFiniteMeasure ν] - {f : α → β} (hf : MeasurableEmbedding f) : - klDiv (μ.map f) (ν.map f) = klDiv μ ν := by - refine le_antisymm (klDiv_map_le μ ν hf.measurable) ?_ - rcases isEmpty_or_nonempty α with hα | hα - · simp [μ.eq_zero_of_isEmpty, ν.eq_zero_of_isEmpty] - have h := klDiv_map_le (μ.map f) (ν.map f) hf.measurable_invFun - rwa [Measure.map_map hf.measurable_invFun hf.measurable, - Measure.map_map hf.measurable_invFun hf.measurable, hf.leftInverse_invFun.comp_eq_id, - Measure.map_id, Measure.map_id] at h - -/-- The Kullback–Leibler divergence is invariant under measurable equivalences. -/ -lemma klDiv_map_measurableEquiv (μ ν : Measure α) [IsFiniteMeasure μ] [IsFiniteMeasure ν] - (e : α ≃ᵐ β) : - klDiv (μ.map e) (ν.map e) = klDiv μ ν := - klDiv_map_measurableEmbedding μ ν e.measurableEmbedding - -/-- **Data processing inequality** for the first projection: for Markov kernels `κ` and `η`, -`μ` and `ν` are the images of `μ ⊗ₘ κ` and `ν ⊗ₘ η` under `Prod.fst`, hence -`klDiv μ ν ≤ klDiv (μ ⊗ₘ κ) (ν ⊗ₘ η)`. -/ -lemma klDiv_le_compProd (μ ν : Measure α) [IsFiniteMeasure μ] [IsFiniteMeasure ν] - (κ η : Kernel α β) [IsMarkovKernel κ] [IsMarkovKernel η] : - klDiv μ ν ≤ klDiv (μ ⊗ₘ κ) (ν ⊗ₘ η) := by - conv_lhs => rw [← Measure.fst_compProd μ κ, ← Measure.fst_compProd ν η] - rw [Measure.fst, Measure.fst] - exact klDiv_map_le _ _ measurable_fst - -/-- **Data processing inequality** for the second projection: `κ ∘ₘ μ` and `η ∘ₘ ν` are the images -of `μ ⊗ₘ κ` and `ν ⊗ₘ η` under `Prod.snd`, hence -`klDiv (κ ∘ₘ μ) (η ∘ₘ ν) ≤ klDiv (μ ⊗ₘ κ) (ν ⊗ₘ η)`. -/ -lemma klDiv_comp_le_compProd (μ ν : Measure α) [IsFiniteMeasure μ] [IsFiniteMeasure ν] - (κ η : Kernel α β) [IsFiniteKernel κ] [IsFiniteKernel η] : - klDiv (κ ∘ₘ μ) (η ∘ₘ ν) ≤ klDiv (μ ⊗ₘ κ) (ν ⊗ₘ η) := by - rw [← Measure.snd_compProd μ κ, ← Measure.snd_compProd ν η, Measure.snd, Measure.snd] - exact klDiv_map_le _ _ measurable_snd - section kernel -variable [MeasurableSpace.CountableOrCountablyGenerated α β] {κ η : Kernel α β} [IsFiniteKernel κ] - [IsFiniteKernel η] +variable [MeasurableSpace.CountableOrCountablyGenerated α β] /-- For finite kernels with countably generated target, `a ↦ klDiv (κ a) (η a)` is measurable. -/ lemma measurable_klDiv_kernel (κ η : Kernel α β) [IsFiniteKernel κ] [IsFiniteKernel η] : @@ -145,12 +104,18 @@ lemma klDiv_compProd_eq_add_lintegral (μ ν : Measure α) [IsFiniteMeasure μ] omit [MeasurableSpace.CountableOrCountablyGenerated α β] in /-- `klDiv_compProd_left` for a kernel which is only a probability measure on a measurable set of full measure for both `μ` and `ν`. -/ -lemma klDiv_compProd_left_of_ae [Nonempty β] (μ ν : Measure α) [IsFiniteMeasure μ] +lemma klDiv_compProd_left_of_ae (μ ν : Measure α) [IsFiniteMeasure μ] [IsFiniteMeasure ν] (κ : Kernel α β) [IsSFiniteKernel κ] {S : Set α} (hS : MeasurableSet S) (hκ : ∀ a ∈ S, IsProbabilityMeasure (κ a)) (hμ : ∀ᵐ a ∂μ, a ∈ S) (hν : ∀ᵐ a ∂ν, a ∈ S) : klDiv (μ ⊗ₘ κ) (ν ⊗ₘ κ) = klDiv μ ν := by classical - obtain ⟨b⟩ := ‹Nonempty β› + rcases isEmpty_or_nonempty β with hβ | ⟨⟨b⟩⟩ + · -- if `β` is empty, then `S` is empty, hence `μ = ν = 0` + have hS_empty (a : α) (ha : a ∈ S) : False := + have := hκ a ha; IsProbabilityMeasure.ne_zero (κ a) (κ a).eq_zero_of_isEmpty + have hμ0 : μ = 0 := ae_eq_bot.1 (Filter.eventually_false_iff_eq_bot.1 (hμ.mono hS_empty)) + have hν0 : ν = 0 := ae_eq_bot.1 (Filter.eventually_false_iff_eq_bot.1 (hν.mono hS_empty)) + simp [hμ0, hν0] let κ' : Kernel α β := Kernel.piecewise hS κ (Kernel.const α (Measure.dirac b)) have hκ' : IsMarkovKernel κ' := ⟨fun a ↦ by by_cases ha : a ∈ S diff --git a/LeanMachineLearning/ForMathlib/InformationTheory/KullbackLeibler/CompProd.lean b/LeanMachineLearning/ForMathlib/InformationTheory/KullbackLeibler/CompProd.lean index bb592403..8d53eeaa 100644 --- a/LeanMachineLearning/ForMathlib/InformationTheory/KullbackLeibler/CompProd.lean +++ b/LeanMachineLearning/ForMathlib/InformationTheory/KullbackLeibler/CompProd.lean @@ -5,9 +5,26 @@ Authors: Rémy Degenne -/ module +public import LeanMachineLearning.ForMathlib.InformationTheory.KullbackLeibler.DataProcessing +public import LeanMachineLearning.ForMathlib.MeasureTheory.Measure.WithDensity +public import LeanMachineLearning.ForMathlib.Probability.Kernel.Composition.Lemmas public import Mathlib.InformationTheory.KullbackLeibler.Basic -/-! # Lemmas about the Kullback-Leibler divergence of the images of two measures by a measurable map +/-! # The Kullback–Leibler divergence of composition-products with kernels factoring through a map + +If two kernels `κ.comap f` and `η.comap f` depend on the conditioning variable only through a +measurable statistic `f`, then the divergence of their composition-products with `μ` equals the +divergence of the composition-products of `κ` and `η` with the image measure `μ.map f`. + +## Main statements + +* `klDiv_map_of_eq_withDensity_comp`: if `μ` has a density `f ∘ g` with respect to `ν`, then + `klDiv (μ.map g) (ν.map g) = klDiv μ ν`, that is, `g` is a sufficient statistic. +* `klDiv_compProd_comap`: + `klDiv (μ ⊗ₘ κ.comap f hf) (μ ⊗ₘ η.comap f hf) = klDiv (μ.map f ⊗ₘ κ) (μ.map f ⊗ₘ η)`. +* `klDiv_compProd_compProd_prodMkLeft_eq_klDiv_comp_compProd`: + `klDiv (μ ⊗ₘ (π ⊗ₖ κ.prodMkLeft α)) (μ ⊗ₘ (π ⊗ₖ η.prodMkLeft α)) + = klDiv ((π ∘ₘ μ) ⊗ₘ κ) ((π ∘ₘ μ) ⊗ₘ η)`. -/ @[expose] public section @@ -20,30 +37,14 @@ namespace InformationTheory variable {α β γ : Type*} {mα : MeasurableSpace α} {mβ : MeasurableSpace β} {mγ : MeasurableSpace γ} {μ ν : Measure α} [IsFiniteMeasure μ] [IsFiniteMeasure ν] -/-- Transporting `μ ⊗ₘ η.comap f` along `f` in the first coordinate gives `μ.map f ⊗ₘ η`. -/ -lemma _root_.MeasureTheory.Measure.map_compProd_comap (μ : Measure α) [SFinite μ] - (η : Kernel β γ) [IsSFiniteKernel η] {f : α → β} (hf : Measurable f) : - (μ ⊗ₘ η.comap f hf).map (fun p : α × γ ↦ (f p.1, p.2)) = μ.map f ⊗ₘ η := by - ext s hs - rw [Measure.map_apply (by fun_prop) hs, Measure.compProd_apply (hs.preimage (by fun_prop)), - Measure.compProd_apply hs, lintegral_map (Kernel.measurable_kernel_prodMk_left hs) hf] - rfl - -omit [IsFiniteMeasure ν] in -lemma _root_.MeasureTheory.Measure.map_withDensity_comp - {f : β → ℝ≥0∞} (hf : Measurable f) {g : α → β} (hg : Measurable g) : - (ν.withDensity (f ∘ g)).map g = (ν.map g).withDensity f := by - ext s hs - rw [Measure.map_apply hg hs, withDensity_apply _ (hg hs), withDensity_apply _ hs, - ← lintegral_indicator hs, ← lintegral_indicator (hg hs), lintegral_map (hf.indicator hs) hg] - rfl - +/-- If `ν.withDensity (f ∘ g)` is finite, the divergence of the images by `g` of +`ν.withDensity (f ∘ g)` and `ν` is the divergence of those measures. -/ lemma klDiv_withDensity_comp_map {f : β → ℝ≥0∞} (hf : Measurable f) {g : α → β} (hg : Measurable g) [IsFiniteMeasure (ν.withDensity (f ∘ g))] : klDiv ((ν.withDensity (f ∘ g)).map g) (ν.map g) = klDiv (ν.withDensity (f ∘ g)) ν := by have hac : ν.withDensity (f ∘ g) ≪ ν := withDensity_absolutelyContinuous ν (f ∘ g) have h_rnDeriv : ((ν.withDensity (f ∘ g)).map g).rnDeriv (ν.map g) =ᵐ[ν.map g] f := by - rw [Measure.map_withDensity_comp hf hg] + rw [map_withDensity_comp hg hf] exact Measure.rnDeriv_withDensity _ hf have hmeas : Measurable fun x : β ↦ ENNReal.ofReal (klFun (((ν.withDensity (f ∘ g)).map g).rnDeriv (ν.map g) x).toReal) := @@ -110,4 +111,38 @@ lemma klDiv_compProd_comap (μ : Measure α) [IsFiniteMeasure μ] (κ η : Kerne rw [← Measure.map_compProd_comap μ κ hf, ← Measure.map_compProd_comap μ η hf, klDiv_map_of_eq_withDensity_comp hD hg key] +section + +variable {δ : Type*} {mδ : MeasurableSpace δ} + +/-- The divergence of one step of a policy/reward decomposition, in composition-product form: +the policy `π` is shared and the reward kernels `κ`, `η` (which ignore the history) differ, so +the divergence is the conditional divergence of the reward kernels given the played action, +whose law is `π ∘ₘ μ`. -/ +lemma klDiv_compProd_compProd_prodMkLeft_eq_klDiv_comp_compProd (μ : Measure α) + [IsFiniteMeasure μ] (π : Kernel α β) [IsFiniteKernel π] (κ η : Kernel β γ) [IsFiniteKernel κ] + [IsFiniteKernel η] : + klDiv (μ ⊗ₘ (π ⊗ₖ κ.prodMkLeft α)) (μ ⊗ₘ (π ⊗ₖ η.prodMkLeft α)) = + klDiv ((π ∘ₘ μ) ⊗ₘ κ) ((π ∘ₘ μ) ⊗ₘ η) := by + rw [← klDiv_map_measurableEquiv _ _ MeasurableEquiv.prodAssoc.symm, Measure.compProd_assoc, + Measure.compProd_assoc, ← Measure.snd_compProd, Measure.snd] + exact klDiv_compProd_comap _ _ _ measurable_snd + +/-- The divergence of one step of an observation/policy/reward decomposition, in +composition-product form: the observation kernel `o` and the policy `π` are shared and the reward +kernels `κ`, `η` (which ignore the history and the observation) differ, so the divergence is the +conditional divergence of the reward kernels given the played action, whose law is +`π ∘ₘ (μ ⊗ₘ o)`. -/ +lemma klDiv_compProd_compProd_compProd_prodMkLeft_eq_klDiv_comp_compProd (μ : Measure α) + [IsFiniteMeasure μ] (o : Kernel α β) [IsFiniteKernel o] (π : Kernel (α × β) γ) + [IsFiniteKernel π] (κ η : Kernel γ δ) [IsFiniteKernel κ] [IsFiniteKernel η] : + klDiv (μ ⊗ₘ (o ⊗ₖ (π ⊗ₖ κ.prodMkLeft (α × β)))) + (μ ⊗ₘ (o ⊗ₖ (π ⊗ₖ η.prodMkLeft (α × β)))) = + klDiv ((π ∘ₘ (μ ⊗ₘ o)) ⊗ₘ κ) ((π ∘ₘ (μ ⊗ₘ o)) ⊗ₘ η) := by + rw [← klDiv_map_measurableEquiv _ _ MeasurableEquiv.prodAssoc.symm, Measure.compProd_assoc, + Measure.compProd_assoc] + exact klDiv_compProd_compProd_prodMkLeft_eq_klDiv_comp_compProd _ _ _ _ + +end + end InformationTheory diff --git a/LeanMachineLearning/ForMathlib/InformationTheory/KullbackLeibler/Convex.lean b/LeanMachineLearning/ForMathlib/InformationTheory/KullbackLeibler/Convex.lean index 9e4c4e60..271e591b 100644 --- a/LeanMachineLearning/ForMathlib/InformationTheory/KullbackLeibler/Convex.lean +++ b/LeanMachineLearning/ForMathlib/InformationTheory/KullbackLeibler/Convex.lean @@ -8,6 +8,7 @@ module public import Mathlib.InformationTheory.KullbackLeibler.Basic import LeanMachineLearning.ForMathlib.InformationTheory.KullbackLeibler.ChainRule +import LeanMachineLearning.ForMathlib.InformationTheory.KullbackLeibler.DataProcessing /-! # Convexity of the Kullback–Leibler divergence for mixtures diff --git a/LeanMachineLearning/ForMathlib/InformationTheory/KullbackLeibler/DataProcessing.lean b/LeanMachineLearning/ForMathlib/InformationTheory/KullbackLeibler/DataProcessing.lean index 80d5a9a5..b3de4794 100644 --- a/LeanMachineLearning/ForMathlib/InformationTheory/KullbackLeibler/DataProcessing.lean +++ b/LeanMachineLearning/ForMathlib/InformationTheory/KullbackLeibler/DataProcessing.lean @@ -10,6 +10,19 @@ public import Mathlib.InformationTheory.KullbackLeibler.DataProcessing import Mathlib.MeasureTheory.Function.ConditionalExpectation.RadonNikodym /-! # Lemmas related to the data-processing inequality for the Kullback–Leibler divergence + +The divergence of the images of `μ ≪ ν` by a measurable map `g` is the integral of `klFun` of the +conditional expectation of the density `∂μ/∂ν` given `g` +(`klDiv_map_eq_lintegral_klFun_condExp`), a `lintegral` version of Mathlib's `klDiv_map_of_ac`. + +## Main statements + +* `klDiv_map_eq_lintegral_klFun_condExp`: the divergence of the images by a measurable map, as + the integral of `klFun` of the conditional expectation of the density. +* `klDiv_map_measurableEmbedding`, `klDiv_map_measurableEquiv`: the divergence is invariant under + measurable embeddings and measurable equivalences. +* `klDiv_le_compProd`, `klDiv_comp_le_compProd`: data processing inequalities for the two + projections of `μ ⊗ₘ κ` and `ν ⊗ₘ η`. -/ @[expose] public section @@ -20,7 +33,10 @@ open scoped ENNReal NNReal namespace InformationTheory variable {α β : Type*} {mα : MeasurableSpace α} {mβ : MeasurableSpace β} - {μ ν : Measure α} [IsFiniteMeasure μ] [IsFiniteMeasure ν] + +section CondExp + +variable {μ ν : Measure α} [IsFiniteMeasure μ] [IsFiniteMeasure ν] /-- The divergence of the images of `μ ≪ ν` by a measurable map `g`, as the integral of `klFun` of the conditional expectation of the density `∂μ/∂ν` given `g`. @@ -38,5 +54,47 @@ lemma klDiv_map_eq_lintegral_klFun_condExp (hμν : μ ≪ ν) {g : α → β} ( filter_upwards [toReal_rnDeriv_map hμν hg] with x hx rw [hx] +end CondExp + +section Map + +/-- The Kullback–Leibler divergence is invariant under measurable embeddings. -/ +lemma klDiv_map_measurableEmbedding (μ ν : Measure α) [IsFiniteMeasure μ] [IsFiniteMeasure ν] + {f : α → β} (hf : MeasurableEmbedding f) : + klDiv (μ.map f) (ν.map f) = klDiv μ ν := by + refine le_antisymm (klDiv_map_le μ ν hf.measurable) ?_ + rcases isEmpty_or_nonempty α with hα | hα + · simp [μ.eq_zero_of_isEmpty, ν.eq_zero_of_isEmpty] + have h := klDiv_map_le (μ.map f) (ν.map f) hf.measurable_invFun + rwa [Measure.map_map hf.measurable_invFun hf.measurable, + Measure.map_map hf.measurable_invFun hf.measurable, hf.leftInverse_invFun.comp_eq_id, + Measure.map_id, Measure.map_id] at h + +/-- The Kullback–Leibler divergence is invariant under measurable equivalences. -/ +lemma klDiv_map_measurableEquiv (μ ν : Measure α) [IsFiniteMeasure μ] [IsFiniteMeasure ν] + (e : α ≃ᵐ β) : + klDiv (μ.map e) (ν.map e) = klDiv μ ν := + klDiv_map_measurableEmbedding μ ν e.measurableEmbedding + +/-- **Data processing inequality** for the first projection: for Markov kernels `κ` and `η`, +`μ` and `ν` are the images of `μ ⊗ₘ κ` and `ν ⊗ₘ η` under `Prod.fst`, hence +`klDiv μ ν ≤ klDiv (μ ⊗ₘ κ) (ν ⊗ₘ η)`. -/ +lemma klDiv_le_compProd (μ ν : Measure α) [IsFiniteMeasure μ] [IsFiniteMeasure ν] + (κ η : Kernel α β) [IsMarkovKernel κ] [IsMarkovKernel η] : + klDiv μ ν ≤ klDiv (μ ⊗ₘ κ) (ν ⊗ₘ η) := by + conv_lhs => rw [← Measure.fst_compProd μ κ, ← Measure.fst_compProd ν η] + rw [Measure.fst, Measure.fst] + exact klDiv_map_le _ _ measurable_fst + +/-- **Data processing inequality** for the second projection: `κ ∘ₘ μ` and `η ∘ₘ ν` are the images +of `μ ⊗ₘ κ` and `ν ⊗ₘ η` under `Prod.snd`, hence +`klDiv (κ ∘ₘ μ) (η ∘ₘ ν) ≤ klDiv (μ ⊗ₘ κ) (ν ⊗ₘ η)`. -/ +lemma klDiv_comp_le_compProd (μ ν : Measure α) [IsFiniteMeasure μ] [IsFiniteMeasure ν] + (κ η : Kernel α β) [IsFiniteKernel κ] [IsFiniteKernel η] : + klDiv (κ ∘ₘ μ) (η ∘ₘ ν) ≤ klDiv (μ ⊗ₘ κ) (ν ⊗ₘ η) := by + rw [← Measure.snd_compProd μ κ, ← Measure.snd_compProd ν η, Measure.snd, Measure.snd] + exact klDiv_map_le _ _ measurable_snd + +end Map end InformationTheory diff --git a/LeanMachineLearning/ForMathlib/InformationTheory/KullbackLeibler/MapSequence.lean b/LeanMachineLearning/ForMathlib/InformationTheory/KullbackLeibler/MapSequence.lean index e4168ae2..95411aee 100644 --- a/LeanMachineLearning/ForMathlib/InformationTheory/KullbackLeibler/MapSequence.lean +++ b/LeanMachineLearning/ForMathlib/InformationTheory/KullbackLeibler/MapSequence.lean @@ -17,7 +17,13 @@ Let `μ, ν` be finite measures on `α` and `g n : α → β n` be measurable ma `comap (g n)` increase to the σ-algebra of `α` (for instance the projections of a sequence space on its first `n` coordinates). Then the divergence of `μ` and `ν` is the supremum of the divergences of their images by the `g n`: -`klDiv μ ν = ⨆ n, klDiv (μ.map (g n)) (ν.map (g n))` (`klDiv_eq_iSup_map`). +`klDiv μ ν = ⨆ n, klDiv (μ.map (g n)) (ν.map (g n))`. + +## Main statements + +* `klDiv_eq_iSup_map`: the divergence along a generating sequence of maps. + +## Implementation notes The inequality `≥` is the data-processing inequality. For `≤`, if `μ ≪ ν` the divergences of the images are the integrals of `klFun` of the conditional expectations of the density `∂μ/∂ν` @@ -27,9 +33,6 @@ continuous with respect to `ν`, a set `A` with `ν A = 0 < μ A` is approximate `comap (g n)`-measurable sets `B n` (again by Lévy's upward theorem, applied to the indicator of `A` under `μ + ν`), and the lower bound `μ B * log (μ B / ν B) + ν B - μ B ≤ klDiv` on `B n` shows that the divergences of the images tend to infinity. - -The sequence space case is `MeasurableSpace.iSup_comap_restrictFin`: the σ-algebras of the -projections on the first `n` coordinates generate the product σ-algebra of `ℕ → E`. -/ @[expose] public section @@ -177,21 +180,3 @@ lemma klDiv_eq_iSup_map {β : ℕ → Type*} [mβ : ∀ n, MeasurableSpace (β n measureReal_nonneg (μ := ν) (s := B n)] end InformationTheory - -namespace MeasurableSpace - -/-- The σ-algebras of the projections of `ℕ → E` on the first `n` coordinates generate the -product σ-algebra. -/ -lemma iSup_comap_restrictFin {E : Type*} [mE : MeasurableSpace E] : - ⨆ n : ℕ, MeasurableSpace.comap (fun f : ℕ → E ↦ fun i : Fin n ↦ f i) - MeasurableSpace.pi = MeasurableSpace.pi := by - refine le_antisymm - (iSup_le fun n ↦ (Measurable.of_eval fun _ ↦ measurable_pi_apply _).comap_le) - (iSup_le fun i ↦ le_iSup_of_le (i + 1) ?_) - have : (fun f : ℕ → E ↦ f i) = - (fun h : Fin (i + 1) → E ↦ h ⟨i, i.lt_succ_self⟩) ∘ - fun f : ℕ → E ↦ fun j : Fin (i + 1) ↦ f j := rfl - rw [this, ← MeasurableSpace.comap_comp] - exact MeasurableSpace.comap_mono (measurable_pi_apply _).comap_le - -end MeasurableSpace diff --git a/LeanMachineLearning/ForMathlib/InformationTheory/KullbackLeibler/Restrict.lean b/LeanMachineLearning/ForMathlib/InformationTheory/KullbackLeibler/Restrict.lean index 35abb6a2..1da60cd8 100644 --- a/LeanMachineLearning/ForMathlib/InformationTheory/KullbackLeibler/Restrict.lean +++ b/LeanMachineLearning/ForMathlib/InformationTheory/KullbackLeibler/Restrict.lean @@ -5,6 +5,7 @@ Authors: Rémy Degenne -/ module +public import LeanMachineLearning.ForMathlib.MeasureTheory.Measure.Decomposition.Lebesgue public import Mathlib.InformationTheory.KullbackLeibler.Basic /-! @@ -31,21 +32,6 @@ divergences of the restrictions to an increasing sequence of measurable sets cov open MeasureTheory open scoped ENNReal -namespace MeasureTheory.Measure - -variable {α : Type*} {mα : MeasurableSpace α} {μ ν : Measure α} - -/-- The Radon–Nikodym derivative of `μ.restrict s` with respect to `ν.restrict s` is the -Radon–Nikodym derivative of `μ` with respect to `ν`, `ν.restrict s`-almost everywhere. -/ -lemma rnDeriv_restrict_restrict (μ ν : Measure α) [μ.HaveLebesgueDecomposition ν] [SigmaFinite ν] - {s : Set α} (hs : MeasurableSet s) : - (μ.restrict s).rnDeriv (ν.restrict s) =ᵐ[ν.restrict s] μ.rnDeriv ν := by - refine (eq_rnDeriv (s := (μ.singularPart ν).restrict s) (measurable_rnDeriv μ ν) - (((mutuallySingular_singularPart μ ν).restrict s).mono le_rfl restrict_le_self) ?_).symm - rw [← restrict_withDensity hs, ← restrict_add, ← haveLebesgueDecomposition_add μ ν] - -end MeasureTheory.Measure - namespace InformationTheory variable {α : Type*} {mα : MeasurableSpace α} {μ ν : Measure α} [IsFiniteMeasure μ] diff --git a/LeanMachineLearning/ForMathlib/MeasureTheory/Group/Arithmetic.lean b/LeanMachineLearning/ForMathlib/MeasureTheory/Group/Arithmetic.lean new file mode 100644 index 00000000..ac5959bf --- /dev/null +++ b/LeanMachineLearning/ForMathlib/MeasureTheory/Group/Arithmetic.lean @@ -0,0 +1,38 @@ +/- +Copyright (c) 2025 Rémy Degenne. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Rémy Degenne +-/ +module + +public import Mathlib.MeasureTheory.Group.Arithmetic + +/-! +# Measurability of sums with a variable number of terms + +## Main statements + +* `measurable_sum_range`, `measurable_sum_Icc`: `a ↦ ∑ i ∈ range (g a), f i a` and + `a ↦ ∑ i ∈ Icc 1 (g a), f i a` are measurable when `g : α → ℕ` and all the `f i` are. +-/ + +@[expose] public section + +open Finset + +variable {α M : Type*} {mα : MeasurableSpace α} [AddCommMonoid M] [MeasurableSpace M] + [MeasurableAdd₂ M] + +/-- `a ↦ ∑ i ∈ range (g a), f i a` is measurable when `g : α → ℕ` and all the `f i` are. -/ +lemma measurable_sum_range {f : ℕ → α → M} {g : α → ℕ} (hf : ∀ i, Measurable (f i)) + (hg : Measurable g) : + Measurable (fun a ↦ ∑ i ∈ range (g a), f i a) := + (measurable_from_prod_countable_left (f := fun p : α × ℕ ↦ ∑ i ∈ range p.2, f i p.1) + fun n ↦ Finset.measurable_sum (range n) fun i _ ↦ hf i).comp (measurable_id.prodMk hg) + +/-- `a ↦ ∑ i ∈ Icc 1 (g a), f i a` is measurable when `g : α → ℕ` and all the `f i` are. -/ +lemma measurable_sum_Icc {f : ℕ → α → M} {g : α → ℕ} (hf : ∀ i, Measurable (f i)) + (hg : Measurable g) : + Measurable (fun a ↦ ∑ i ∈ Icc 1 (g a), f i a) := + (measurable_from_prod_countable_left (f := fun p : α × ℕ ↦ ∑ i ∈ Icc 1 p.2, f i p.1) + fun n ↦ Finset.measurable_sum (Icc 1 n) fun i _ ↦ hf i).comp (measurable_id.prodMk hg) diff --git a/LeanMachineLearning/ForMathlib/MeasureTheory/Measurable.lean b/LeanMachineLearning/ForMathlib/MeasureTheory/Measurable.lean deleted file mode 100644 index 70a2f36e..00000000 --- a/LeanMachineLearning/ForMathlib/MeasureTheory/Measurable.lean +++ /dev/null @@ -1,63 +0,0 @@ -/- -Copyright (c) 2025 Rémy Degenne. All rights reserved. -Released under Apache 2.0 license as described in the file LICENSE. -Authors: Rémy Degenne --/ -module - -public import Mathlib.Analysis.Normed.Ring.Basic -public import Mathlib.MeasureTheory.Constructions.BorelSpace.Basic - -/-! -# Measurability lemmas --/ - -@[expose] public section - -open Finset - -namespace MeasureTheory - -variable {α β γ : Type*} {mα : MeasurableSpace α} {mβ : MeasurableSpace β} {mγ : MeasurableSpace γ} - {μ : Measure α} - -lemma measurable_comp_comap (f : α → β) {g : β → γ} (hg : Measurable g) : - Measurable[mβ.comap f] (g ∘ f) := by - rw [measurable_iff_comap_le, ← MeasurableSpace.comap_comp] - exact MeasurableSpace.comap_mono hg.comap_le - -@[fun_prop] -lemma Measurable.coe_nat_enat {f : α → ℕ} (hf : Measurable f) : - Measurable (fun a ↦ (f a : ℕ∞)) := Measurable.comp (by fun_prop) hf - -@[fun_prop] -lemma Measurable.toNat {f : α → ℕ∞} (hf : Measurable f) : Measurable (fun a ↦ (f a).toNat) := - Measurable.comp (by fun_prop) hf - -lemma measurable_sum_range_of_le {f : ℕ → α → ℝ} {g : α → ℕ} {n : ℕ} - (hg_le : ∀ a, g a ≤ n) (hf : ∀ i, Measurable (f i)) (hg : Measurable g) : - Measurable (fun a ↦ ∑ i ∈ range (g a), f i a) := by - have h_eq : (fun a ↦ ∑ i ∈ range (g a), f i a) - = fun a ↦ ∑ i ∈ range (n + 1), if g a = i then ∑ j ∈ range i, f j a else 0 := by - ext ω - rw [sum_ite_eq_of_mem] - grind - rw [h_eq] - refine measurable_sum _ fun n hn ↦ ?_ - refine Measurable.ite ?_ (by fun_prop) (by fun_prop) - exact (measurableSet_singleton _).preimage (by fun_prop) - -lemma measurable_sum_Icc_of_le {f : ℕ → α → ℝ} {g : α → ℕ} {n : ℕ} - (hg_le : ∀ a, g a ≤ n) (hf : ∀ i, Measurable (f i)) (hg : Measurable g) : - Measurable (fun a ↦ ∑ i ∈ Icc 1 (g a), f i a) := by - have h_eq : (fun a ↦ ∑ i ∈ Icc 1 (g a), f i a) - = fun a ↦ ∑ i ∈ range (n + 1), if g a = i then ∑ j ∈ Icc 1 i, f j a else 0 := by - ext ω - rw [sum_ite_eq_of_mem] - grind - rw [h_eq] - refine measurable_sum _ fun n hn ↦ ?_ - refine Measurable.ite ?_ (by fun_prop) (by fun_prop) - exact (measurableSet_singleton _).preimage (by fun_prop) - -end MeasureTheory diff --git a/LeanMachineLearning/ForMathlib/MeasureTheory/MeasurableSpace/Basic.lean b/LeanMachineLearning/ForMathlib/MeasureTheory/MeasurableSpace/Basic.lean new file mode 100644 index 00000000..435d0665 --- /dev/null +++ b/LeanMachineLearning/ForMathlib/MeasureTheory/MeasurableSpace/Basic.lean @@ -0,0 +1,29 @@ +/- +Copyright (c) 2025 Rémy Degenne. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Rémy Degenne +-/ +module + +public import Mathlib.MeasureTheory.MeasurableSpace.Basic + +/-! +# Measurability with respect to a comap σ-algebra + +## Main statements + +* `measurable_comp_comap`: `g ∘ f` is measurable with respect to `mβ.comap f` if `g` is + measurable. +-/ + +@[expose] public section + +open MeasureTheory + +variable {α β γ : Type*} {mβ : MeasurableSpace β} {mγ : MeasurableSpace γ} + +/-- `g ∘ f` is measurable with respect to the σ-algebra on `α` induced by `f`, as soon as `g` is +measurable. -/ +lemma measurable_comp_comap (f : α → β) {g : β → γ} (hg : Measurable g) : + Measurable[mβ.comap f] (g ∘ f) := + hg.comp (comap_measurable f) diff --git a/LeanMachineLearning/ForMathlib/MeasureTheory/MeasurableSpace/Constructions.lean b/LeanMachineLearning/ForMathlib/MeasureTheory/MeasurableSpace/Constructions.lean new file mode 100644 index 00000000..023eaefa --- /dev/null +++ b/LeanMachineLearning/ForMathlib/MeasureTheory/MeasurableSpace/Constructions.lean @@ -0,0 +1,48 @@ +/- +Copyright (c) 2025 Rémy Degenne. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Rémy Degenne, Paulo Rauber +-/ +module + +public import Mathlib.MeasureTheory.MeasurableSpace.Constructions + +/-! +# Lemmas about the product σ-algebra on a function space + +## Main statements + +* `MeasurableSpace.comap_pi`: the comap of the product σ-algebra by a map `g` is the supremum of + the comaps of the σ-algebras of the coordinates by the coordinates of `g`. +* `MeasurableSpace.iSup_comap_restrictFin`: the σ-algebras of the projections of `ℕ → E` on the + first `n` coordinates generate the product σ-algebra. +-/ + +@[expose] public section + +open Function + +namespace MeasurableSpace + +variable {δ : Type*} {X : δ → Type*} [m : ∀ a, MeasurableSpace (X a)] {α : Type*} + +/-- The comap of the product σ-algebra by `g` is the supremum of the comaps of the σ-algebras of +the coordinates by the coordinates of `g`. -/ +lemma comap_pi {g : α → ∀ a, X a} : pi.comap g = ⨆ a, (m a).comap (fun x ↦ g x a) := by + simp_rw [pi, comap_iSup, comap_comp, comp_def] + +/-- The σ-algebras of the projections of `ℕ → E` on the first `n` coordinates generate the +product σ-algebra. -/ +lemma iSup_comap_restrictFin {E : Type*} [mE : MeasurableSpace E] : + ⨆ n : ℕ, MeasurableSpace.comap (fun f : ℕ → E ↦ fun i : Fin n ↦ f i) + MeasurableSpace.pi = MeasurableSpace.pi := by + refine le_antisymm + (iSup_le fun n ↦ (Measurable.of_eval fun _ ↦ measurable_pi_apply _).comap_le) + (iSup_le fun i ↦ le_iSup_of_le (i + 1) ?_) + have : (fun f : ℕ → E ↦ f i) = + (fun h : Fin (i + 1) → E ↦ h ⟨i, i.lt_succ_self⟩) ∘ + fun f : ℕ → E ↦ fun j : Fin (i + 1) ↦ f j := rfl + rw [this, ← MeasurableSpace.comap_comp] + exact MeasurableSpace.comap_mono (measurable_pi_apply _).comap_le + +end MeasurableSpace diff --git a/LeanMachineLearning/ForMathlib/MeasureTheory/MeasurableSpace/Embedding.lean b/LeanMachineLearning/ForMathlib/MeasureTheory/MeasurableSpace/Embedding.lean index df72cede..ac17a363 100644 --- a/LeanMachineLearning/ForMathlib/MeasureTheory/MeasurableSpace/Embedding.lean +++ b/LeanMachineLearning/ForMathlib/MeasureTheory/MeasurableSpace/Embedding.lean @@ -15,6 +15,8 @@ public import Mathlib.Probability.Kernel.IonescuTulcea.Maps Measurable equivalences between product and pi types, used to manipulate histories of sequential learning algorithms (elements of `Fin n → 𝓐 × 𝓨` or `Iic n → 𝓐 × 𝓨`). +## Main definitions + * `MeasurableEquiv.uniqueProd`, `MeasurableEquiv.prodUnique`: drop a component that lives in a type with a unique element. * `MeasurableEquiv.IicSuccProd`: `(Π i : Iic (n + 1), X i) ≃ᵐ (Π i : Iic n, X i) × X (n + 1)`. @@ -38,8 +40,6 @@ lemma measurableEmbedding_prodMk_left_of_measurableSet {α β : Type*} [Measurab ext p simp [Prod.ext_iff, eq_comm, and_left_comm] -lemma coe_default_Iic_zero : ((default : Iic 0) : ℕ) = 0 := rfl - namespace MeasurableEquiv section Unique @@ -97,7 +97,7 @@ def IicSuccProd (X : ℕ → Type*) [∀ n, MeasurableSpace (X n)] (n : ℕ) : (IicProdIoc (Nat.le_succ n)).symm.trans (prodCongr (refl _) (piSingleton n).symm) -lemma symm_IicSuccProd (n : ℕ) : +lemma IicSuccProd_symm (n : ℕ) : (IicSuccProd X n).symm = (prodCongr (refl _) (piSingleton n)).trans (IicProdIoc (Nat.le_succ n)) := rfl diff --git a/LeanMachineLearning/ForMathlib/MeasureTheory/MeasurableSpace/Instances.lean b/LeanMachineLearning/ForMathlib/MeasureTheory/MeasurableSpace/Instances.lean new file mode 100644 index 00000000..4666063e --- /dev/null +++ b/LeanMachineLearning/ForMathlib/MeasureTheory/MeasurableSpace/Instances.lean @@ -0,0 +1,32 @@ +/- +Copyright (c) 2025 Rémy Degenne. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Rémy Degenne +-/ +module + +public import Mathlib.Data.ENat.Basic +public import Mathlib.MeasureTheory.MeasurableSpace.Instances + +/-! +# Measurability of functions with values in `ℕ∞` + +## Main statements + +* `Measurable.coe_nat_enat`: the coercion to `ℕ∞` of a measurable function is measurable. +* `Measurable.enat_toNat`: `ENat.toNat` of a measurable function is measurable. +-/ + +@[expose] public section + +variable {α : Type*} {mα : MeasurableSpace α} + +/-- The coercion `ℕ → ℕ∞` of a measurable function is measurable. -/ +@[fun_prop] +lemma Measurable.coe_nat_enat {f : α → ℕ} (hf : Measurable f) : + Measurable (fun a ↦ (f a : ℕ∞)) := Measurable.comp (by fun_prop) hf + +/-- `ENat.toNat` of a measurable function is measurable. -/ +@[fun_prop] +lemma Measurable.enat_toNat {f : α → ℕ∞} (hf : Measurable f) : Measurable (fun a ↦ (f a).toNat) := + Measurable.comp (by fun_prop) hf diff --git a/LeanMachineLearning/ForMathlib/MeasureTheory/MeasurableSpace/Sigma.lean b/LeanMachineLearning/ForMathlib/MeasureTheory/MeasurableSpace/Sigma.lean index 1d7c6587..8f455f34 100644 --- a/LeanMachineLearning/ForMathlib/MeasureTheory/MeasurableSpace/Sigma.lean +++ b/LeanMachineLearning/ForMathlib/MeasureTheory/MeasurableSpace/Sigma.lean @@ -11,8 +11,19 @@ public import Mathlib.MeasureTheory.Measure.Map /-! # Measurability of functions on a sigma type -A function on `Σ a, β a` is measurable as soon as each of its restrictions `f ∘ Sigma.mk a` is. -We also record measurability facts about the first projection of `Σ n : ℕ, β n`. +We develop the API of the σ-algebra `Sigma.instMeasurableSpace` on `Σ a, β a`, the finest one +making all the injections `Sigma.mk a` measurable. + +## Main statements + +* `measurableSet_sigma_iff`: a set is measurable iff all its traces on the fibers are. +* `measurable_sigma_iff`: a function on `Σ a, β a` is measurable iff all its restrictions + `f ∘ Sigma.mk a` are. +* `measurableEmbedding_sigmaMk`: `Sigma.mk a` is a measurable embedding. +* `Measurable.sigmaMk`: `x ↦ ⟨n x, f (n x) x⟩` is measurable when the index ranges over a countable + type. + +We also record measurability facts about the first projection of `Σ n : ℕ, X n`. -/ @[expose] public section @@ -21,53 +32,44 @@ open MeasurableSpace MeasureTheory variable {α γ : Type*} {β : α → Type*} [∀ a, MeasurableSpace (β a)] [MeasurableSpace γ] -@[fun_prop] -lemma measurable_sigma_mk (a : α) : Measurable (Sigma.mk a : β a → Σ a, β a) := - fun _ hs ↦ measurableSet_iInf.1 hs a - -/-- A function on a sigma type is measurable if all its restrictions to the fibers are. -/ -lemma measurable_sigma_of_measurable_comp_mk {f : (Σ a, β a) → γ} - (h : ∀ a, Measurable (f ∘ Sigma.mk a)) : Measurable f := - fun _ hs ↦ measurableSet_iInf.2 fun a ↦ (h a) hs - /-- A set in a sigma type is measurable iff its trace on every fiber is. -/ lemma measurableSet_sigma_iff {s : Set (Σ a, β a)} : MeasurableSet s ↔ ∀ a, MeasurableSet (Sigma.mk a ⁻¹' s) := measurableSet_iInf +/-- The injection `Sigma.mk a` of a fiber into a sigma type is measurable. -/ +@[fun_prop] +lemma measurable_sigmaMk (a : α) : Measurable (Sigma.mk a : β a → Σ a, β a) := + fun _ hs ↦ measurableSet_sigma_iff.1 hs a + +/-- A function on a sigma type is measurable if all its restrictions to the fibers are. -/ +lemma measurable_sigma {f : (Σ a, β a) → γ} (h : ∀ a, Measurable (f ∘ Sigma.mk a)) : + Measurable f := + fun _ hs ↦ measurableSet_sigma_iff.2 fun a ↦ (h a) hs + +/-- A function on a sigma type is measurable iff all its restrictions to the fibers are. -/ lemma measurable_sigma_iff {f : (Σ a, β a) → γ} : Measurable f ↔ ∀ a, Measurable (f ∘ Sigma.mk a) := - ⟨fun hf a ↦ hf.comp (measurable_sigma_mk a), measurable_sigma_of_measurable_comp_mk⟩ + ⟨fun hf a ↦ hf.comp (measurable_sigmaMk a), measurable_sigma⟩ /-- The first projection of a sigma type is measurable (it is constant on every fiber). -/ lemma measurable_sigma_fst [MeasurableSpace α] : Measurable (Sigma.fst : (Σ a, β a) → α) := - measurable_sigma_of_measurable_comp_mk fun _ ↦ measurable_const + measurable_sigma fun _ ↦ measurable_const /-- `x ↦ ⟨n x, f (n x) x⟩` is measurable when the index `n x` ranges over a countable type with measurable singletons and each `f i` is measurable. -/ @[fun_prop] lemma Measurable.sigmaMk [Countable α] [MeasurableSpace α] [MeasurableSingletonClass α] {n : γ → α} (hn : Measurable n) {f : (a : α) → γ → β a} (hf : ∀ a, Measurable (f a)) : - Measurable fun x ↦ (⟨n x, f (n x) x⟩ : Σ a, β a) := by - intro s hs - have : (fun x ↦ (⟨n x, f (n x) x⟩ : Σ a, β a)) ⁻¹' s = - ⋃ a, n ⁻¹' {a} ∩ f a ⁻¹' (Sigma.mk a ⁻¹' s) := by - ext x - simp only [Set.mem_preimage, Set.mem_iUnion, Set.mem_inter_iff, Set.mem_singleton_iff] - constructor - · intro h - exact ⟨n x, rfl, h⟩ - · rintro ⟨a, rfl, h⟩ - exact h - rw [this] - exact MeasurableSet.iUnion fun a ↦ - (hn (measurableSet_singleton a)).inter (hf a (measurableSet_sigma_iff.1 hs a)) + Measurable fun x ↦ (⟨n x, f (n x) x⟩ : Σ a, β a) := + (measurable_from_prod_countable_left (f := fun p : γ × α ↦ (⟨p.2, f p.2 p.1⟩ : Σ a, β a)) + fun a ↦ (measurable_sigmaMk a).comp (hf a)).comp (measurable_id.prodMk hn) /-- `Sigma.mk a` is a measurable embedding. -/ -lemma measurableEmbedding_sigma_mk (a : α) : +lemma measurableEmbedding_sigmaMk (a : α) : MeasurableEmbedding (Sigma.mk a : β a → Σ a, β a) where injective := sigma_mk_injective - measurable := measurable_sigma_mk a + measurable := measurable_sigmaMk a measurableSet_image' s hs := by rw [measurableSet_sigma_iff] intro b @@ -93,7 +95,7 @@ lemma measurableSet_sigma_fst_lt (M : ℕ) : MeasurableSet {x : Σ n, X n | x.1 of `Σ n : ℕ, X n` with first component at most `M`. -/ lemma MeasureTheory.Measure.map_sigmaMk_succ_apply_fst_le (μ : Measure (X (M + 1))) : (μ.map (Sigma.mk (M + 1))) {x : Σ n, X n | x.1 ≤ M} = 0 := by - rw [Measure.map_apply (measurable_sigma_mk (M + 1)) (measurableSet_sigma_fst_le M)] + rw [Measure.map_apply (measurable_sigmaMk (M + 1)) (measurableSet_sigma_fst_le M)] have : Sigma.mk (M + 1) ⁻¹' {x : Σ n, X n | x.1 ≤ M} = ∅ := by ext x simp diff --git a/LeanMachineLearning/ForMathlib/MeasureTheory/Measure/AEMeasurable.lean b/LeanMachineLearning/ForMathlib/MeasureTheory/Measure/AEMeasurable.lean new file mode 100644 index 00000000..0dfba53f --- /dev/null +++ b/LeanMachineLearning/ForMathlib/MeasureTheory/Measure/AEMeasurable.lean @@ -0,0 +1,33 @@ +/- +Copyright (c) 2025 Rémy Degenne. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Rémy Degenne +-/ +module + +public import Mathlib.MeasureTheory.Measure.AEMeasurable + +/-! +# Lemmas about almost everywhere measurable functions + +## Main statements + +* `ae_eq_of_map_prodMk_eq`: if the joint laws of `(X, Y)` and `(X, f ∘ X)` are equal, then + `Y = f ∘ X` almost everywhere. +-/ + +@[expose] public section + +namespace MeasureTheory + +variable {α : Type*} {mα : MeasurableSpace α} {μ : Measure α} + +lemma ae_eq_of_map_prodMk_eq {β Ω : Type*} {_ : MeasurableSpace β} {_ : MeasurableSpace Ω} + [MeasurableEq Ω] {X : α → β} {Y : α → Ω} {f : β → Ω} (hf : Measurable f) (hX : AEMeasurable X μ) + (hY : AEMeasurable Y μ) (h : μ.map (fun ω ↦ (X ω, Y ω)) = μ.map (fun ω ↦ (X ω, f (X ω)))) : + Y =ᵐ[μ] f ∘ X := by + have hp : ∀ᵐ p ∂μ.map (fun ω ↦ (X ω, f (X ω))), p.2 = f p.1 := + (ae_map_iff (by fun_prop) (measurableSet_eq_fun (by fun_prop) (by fun_prop))).2 (by simp) + exact ae_of_ae_map (by fun_prop) (h ▸ hp) + +end MeasureTheory diff --git a/LeanMachineLearning/ForMathlib/MeasureTheory/Measure/AbsolutelyContinuous.lean b/LeanMachineLearning/ForMathlib/MeasureTheory/Measure/AbsolutelyContinuous.lean index 2a6cfaa5..d157b036 100644 --- a/LeanMachineLearning/ForMathlib/MeasureTheory/Measure/AbsolutelyContinuous.lean +++ b/LeanMachineLearning/ForMathlib/MeasureTheory/Measure/AbsolutelyContinuous.lean @@ -9,7 +9,7 @@ public import Mathlib.MeasureTheory.Measure.AbsolutelyContinuous public import LeanMachineLearning.ForMathlib.MeasureTheory.OuterMeasure.Basic /-! -# Lemma about measures that assign non-zero probability to every singleton. +# Absolute continuity with respect to a measure charging every singleton -/ @[expose] public section @@ -22,6 +22,7 @@ variable {mα : MeasurableSpace α} {μ ν : Measure α} namespace Measure +/-- Every measure is absolutely continuous with respect to a measure that charges all singletons. -/ lemma absolutelyContinuous_of_measure_singleton_ne_zero (h : ∀ a, ν {a} ≠ 0) : μ ≪ ν := fun s hs ↦ by simp [(measure_null_iff_eq_empty_of_measure_singleton_ne_zero h).1 hs] diff --git a/LeanMachineLearning/ForMathlib/MeasureTheory/Measure/Decomposition/Lebesgue.lean b/LeanMachineLearning/ForMathlib/MeasureTheory/Measure/Decomposition/Lebesgue.lean new file mode 100644 index 00000000..f302cc93 --- /dev/null +++ b/LeanMachineLearning/ForMathlib/MeasureTheory/Measure/Decomposition/Lebesgue.lean @@ -0,0 +1,54 @@ +/- +Copyright (c) 2025 Rémy Degenne. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Rémy Degenne +-/ +module + +public import Mathlib.MeasureTheory.Measure.Decomposition.Lebesgue +public import Mathlib.MeasureTheory.Measure.SubFinite + +/-! +# Lemmas about the Lebesgue decomposition + +## Main statements + +* `Measure.rnDeriv_restrict_restrict`: the Radon-Nikodym derivative of `μ.restrict s` with + respect to `ν.restrict s` is `μ.rnDeriv ν`, `ν.restrict s`-almost everywhere. +* `Measure.sub_apply_eq_rnDeriv_add_singularPart`: for finite measures, + `(μ - ν) s = ν.withDensity (μ.rnDeriv ν - 1) s + μ.singularPart ν s`. +-/ + +@[expose] public section + +open scoped ENNReal + +namespace MeasureTheory.Measure + +variable {α : Type*} {mα : MeasurableSpace α} {μ ν : Measure α} + +/-- The Radon–Nikodym derivative of `μ.restrict s` with respect to `ν.restrict s` is the +Radon–Nikodym derivative of `μ` with respect to `ν`, `ν.restrict s`-almost everywhere. -/ +lemma rnDeriv_restrict_restrict (μ ν : Measure α) [μ.HaveLebesgueDecomposition ν] [SigmaFinite ν] + {s : Set α} (hs : MeasurableSet s) : + (μ.restrict s).rnDeriv (ν.restrict s) =ᵐ[ν.restrict s] μ.rnDeriv ν := by + refine (eq_rnDeriv (s := (μ.singularPart ν).restrict s) (measurable_rnDeriv μ ν) + (((mutuallySingular_singularPart μ ν).restrict s).mono le_rfl restrict_le_self) ?_).symm + rw [← restrict_withDensity hs, ← restrict_add, ← haveLebesgueDecomposition_add μ ν] + +lemma sub_apply_eq_rnDeriv_add_singularPart [IsFiniteMeasure μ] [IsFiniteMeasure ν] (s : Set α) : + (μ - ν) s = ν.withDensity (fun a ↦ μ.rnDeriv ν a - 1) s + μ.singularPart ν s := by + have hμ : μ = ν.withDensity (fun a ↦ μ.rnDeriv ν a) + μ.singularPart ν := by + rw [rnDeriv_add_singularPart] + have hν : ν = ν.withDensity 1 := by rw [withDensity_one] + conv_lhs => rw [hν, hμ, add_comm _ (μ.singularPart ν)] + rw [← add_sub_of_mutuallySingular] + swap + · simp only [withDensity_one] + exact mutuallySingular_singularPart μ ν + simp only [coe_add, Pi.add_apply] + have : IsFiniteMeasure (ν.withDensity 1) := by simp only [withDensity_one]; infer_instance + rw [add_comm, ← withDensity_sub (by fun_prop) (by fun_prop)] + congr + +end MeasureTheory.Measure diff --git a/LeanMachineLearning/ForMathlib/MeasureTheory/Measure/Dirac.lean b/LeanMachineLearning/ForMathlib/MeasureTheory/Measure/Dirac.lean new file mode 100644 index 00000000..21547b4b --- /dev/null +++ b/LeanMachineLearning/ForMathlib/MeasureTheory/Measure/Dirac.lean @@ -0,0 +1,30 @@ +/- +Copyright (c) 2025 Rémy Degenne. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Rémy Degenne, Paulo Rauber +-/ +module + +public import Mathlib.MeasureTheory.Measure.Dirac.Basic + +/-! +# Dirac measures on a subsingleton + +On a subsingleton, every probability measure is a Dirac mass. +-/ + +@[expose] public section + +namespace MeasureTheory.Measure + +/-- On a subsingleton, every probability measure is a Dirac mass. -/ +lemma eq_dirac_of_subsingleton {α : Type*} {mα : MeasurableSpace α} + [Subsingleton α] (μ : Measure α) [IsProbabilityMeasure μ] (x : α) : + μ = Measure.dirac x := by + ext s hs + rcases Set.eq_empty_or_nonempty s with rfl | ⟨y, hy⟩ + · simp + · rw [Set.eq_univ_of_forall (s := s) fun z ↦ by rwa [Subsingleton.elim z y]] + simp + +end MeasureTheory.Measure diff --git a/LeanMachineLearning/ForMathlib/MeasureTheory/Measure/FiniteMeasure.lean b/LeanMachineLearning/ForMathlib/MeasureTheory/Measure/FiniteMeasure.lean new file mode 100644 index 00000000..e76974b2 --- /dev/null +++ b/LeanMachineLearning/ForMathlib/MeasureTheory/Measure/FiniteMeasure.lean @@ -0,0 +1,68 @@ +/- +Copyright (c) 2025 Rémy Degenne. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Rémy Degenne +-/ +module + +public import Mathlib.MeasureTheory.Measure.FiniteMeasure +public import Mathlib.MeasureTheory.Measure.SubFinite + +/-! +# Order structure on finite measures + +We equip `FiniteMeasure α` with the partial order and the truncated subtraction of the underlying +measures, which makes it a canonically ordered additive monoid with ordered subtraction. + +## Main statements + +* `FiniteMeasure.ext_iff_coe`, `FiniteMeasure.le_iff_coe`: equality and order of finite measures + are those of the underlying measures. +* `FiniteMeasure.toMeasure_sub`: the subtraction of finite measures is that of the underlying + measures. +-/ + +@[expose] public section + +namespace MeasureTheory + +variable {α : Type*} {mα : MeasurableSpace α} + +lemma FiniteMeasure.ext_iff_coe {μ ν : FiniteMeasure α} : + μ = ν ↔ (μ : Measure α) = ν := Subtype.ext_iff + +instance FiniteMeasure.instPartialOrder : PartialOrder (FiniteMeasure α) := + PartialOrder.lift _ FiniteMeasure.toMeasure_injective + +lemma FiniteMeasure.le_iff_coe {μ ν : FiniteMeasure α} : + μ ≤ ν ↔ (μ : Measure α) ≤ (ν : Measure α) := Iff.rfl + +noncomputable +instance FiniteMeasure.instSub : Sub (FiniteMeasure α) := + ⟨fun μ ν ↦ ⟨μ.toMeasure - ν.toMeasure, inferInstance⟩⟩ + +lemma FiniteMeasure.sub_def (μ ν : FiniteMeasure α) : + μ - ν = ⟨μ.toMeasure - ν.toMeasure, inferInstance⟩ := + rfl + +@[simp, norm_cast] +lemma FiniteMeasure.toMeasure_sub (μ ν : FiniteMeasure α) : ↑(μ - ν) = (↑μ - ↑ν : Measure α) := + rfl + +instance FiniteMeasure.instCanonicallyOrderedAdd : CanonicallyOrderedAdd (FiniteMeasure α) where + le_add_self μ ν := fun s ↦ by simp + exists_add_of_le {μ ν} hμν := by + refine ⟨ν - μ, ?_⟩ + rw [FiniteMeasure.ext_iff_coe] + simp only [FiniteMeasure.toMeasure_add, FiniteMeasure.toMeasure_sub] + rw [add_comm, Measure.sub_add_cancel_of_le hμν] + le_self_add μ ν := by + simp only [FiniteMeasure.le_iff_coe, FiniteMeasure.toMeasure_add] + exact Measure.le_add_right le_rfl + +instance FiniteMeasure.instOrderedSub : OrderedSub (FiniteMeasure α) where + tsub_le_iff_right μ ν ξ := by + simp only [FiniteMeasure.le_iff_coe, FiniteMeasure.toMeasure_sub, FiniteMeasure.toMeasure_add] + exact Measure.sub_le_iff_le_add + +end MeasureTheory diff --git a/LeanMachineLearning/ForMathlib/MeasureTheory/Measure/ProbabilityMeasure.lean b/LeanMachineLearning/ForMathlib/MeasureTheory/Measure/ProbabilityMeasure.lean new file mode 100644 index 00000000..dd4bf657 --- /dev/null +++ b/LeanMachineLearning/ForMathlib/MeasureTheory/Measure/ProbabilityMeasure.lean @@ -0,0 +1,28 @@ +/- +Copyright (c) 2025 Rémy Degenne. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Rémy Degenne +-/ +module + +public import Mathlib.MeasureTheory.Measure.ProbabilityMeasure + +/-! +# Lemmas about probability measures + +## Main statements + +* `ProbabilityMeasure.ext_iff_coe`: two probability measures are equal iff the underlying + measures are. +-/ + +@[expose] public section + +namespace MeasureTheory + +variable {α : Type*} {mα : MeasurableSpace α} + +lemma ProbabilityMeasure.ext_iff_coe {μ ν : ProbabilityMeasure α} : + μ = ν ↔ (μ : Measure α) = ν := Subtype.ext_iff + +end MeasureTheory diff --git a/LeanMachineLearning/ForMathlib/MeasureTheory/Measure/WithDensity.lean b/LeanMachineLearning/ForMathlib/MeasureTheory/Measure/WithDensity.lean new file mode 100644 index 00000000..9ea1c31b --- /dev/null +++ b/LeanMachineLearning/ForMathlib/MeasureTheory/Measure/WithDensity.lean @@ -0,0 +1,48 @@ +/- +Copyright (c) 2026 Paulo Rauber. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Paulo Rauber +-/ +module + +public import Mathlib.MeasureTheory.Measure.WithDensity + +/-! +# Image of a measure with density + +## Main statements + +* `map_withDensity_comp`: the image by `g` of `μ.withDensity (f ∘ g)` is + `(μ.map g).withDensity f`. +* `map_equiv_withDensity`: the image of a measure with density by a measurable equivalence. +-/ + +@[expose] public section + +open scoped ENNReal + +namespace MeasureTheory + +variable {α β γ : Type*} {mα : MeasurableSpace α} {mβ : MeasurableSpace β} {mγ : MeasurableSpace γ} + {μ : Measure α} + +lemma map_withDensity_comp {g : α → γ} {f : γ → ℝ≥0∞} (hg : Measurable g) (hf : Measurable f) : + (μ.withDensity (f ∘ g)).map g = (μ.map g).withDensity f := by + ext s hs + rw [Measure.map_apply hg hs, withDensity_apply _ (hg hs), withDensity_apply _ hs, + setLIntegral_map hs hf hg] + rfl + +lemma map_equiv_withDensity {e : α ≃ᵐ β} {f : α → ℝ≥0∞} (hf : Measurable f) : + (μ.withDensity f).map e = (μ.map e).withDensity (f ∘ e.symm) := by + simp_rw [← map_withDensity_comp e.measurable (hf.comp e.symm.measurable), + Function.comp_assoc, MeasurableEquiv.symm_comp_self] + rfl + +lemma map_swap_withDensity_comp_snd {μ : Measure (α × β)} {f : β → ℝ≥0∞} (hf : Measurable f) : + (μ.withDensity (fun ab ↦ f ab.2)).map Prod.swap = + (μ.map Prod.swap).withDensity (fun ba ↦ f ba.1) := by + rw [← map_withDensity_comp measurable_swap (by fun_prop)] + rfl + +end MeasureTheory diff --git a/LeanMachineLearning/ForMathlib/MeasureTheory/Order/MeasurableArg.lean b/LeanMachineLearning/ForMathlib/MeasureTheory/Order/MeasurableArg.lean index 9ba97560..5832e107 100644 --- a/LeanMachineLearning/ForMathlib/MeasureTheory/Order/MeasurableArg.lean +++ b/LeanMachineLearning/ForMathlib/MeasureTheory/Order/MeasurableArg.lean @@ -10,10 +10,23 @@ public import Mathlib.CategoryTheory.Countable public import Mathlib.MeasureTheory.Constructions.Polish.Basic public import Mathlib.Order.CompletePartialOrder -/-! # Argmax and argmin functions on finite sets +/-! # Maximum, minimum, argmax and argmin of a function on a finite type -We prove in particular that those functions are measurable. +For `f : ι → α` with `ι` a nonempty finite type and `α` a linear order, we define the maximum +`Function.max f` and the minimum `Function.min f` of `f`, as well as an index `argmax f` (resp. +`argmin f`) at which `f` attains its maximum (resp. minimum). +## Main definitions + +* `Function.max f`, `Function.min f`: the maximum and minimum values of `f`. +* `argmax f`, `argmin f`: an index at which `f` attains its maximum, resp. minimum. + +## Main statements + +* `isMaxOn_argmax`, `isMinOn_argmin`: `f` attains its maximum at `argmax f` and its minimum at + `argmin f`. +* `measurable_max`, `measurable_min`, `measurable_argmax`, `measurable_argmin`: the maximum, + minimum, argmax and argmin are measurable functions of `f`. -/ @[expose] public section @@ -28,7 +41,8 @@ namespace Function @[to_dual /-- The minimum value of a tuple. -/] abbrev max : α := univ.sup' univ_nonempty f -@[to_dual min_le] +/-- Every value of `f` is at most its maximum. -/ +@[to_dual min_le /-- The minimum of `f` is at most every value of `f`. -/] lemma le_max (x : ι) : f x ≤ max f := le_sup' _ (by simp) end Function @@ -47,14 +61,18 @@ noncomputable def argmax := (exists_argmax f).choose @[to_dual] lemma argmax_spec : f (argmax f) = f.max := (exists_argmax f).choose_spec -@[to_dual] -lemma isMaxOn_argmax (x : ι) : f x ≤ f (argmax f) := by - rw [argmax_spec f] - exact f.le_max x +/-- `f` attains its maximum at `argmax f`. -/ +lemma isMaxOn_argmax : IsMaxOn f Set.univ (argmax f) := + isMaxOn_univ_iff.2 fun x ↦ argmax_spec f ▸ f.le_max x + +/-- `f` attains its minimum at `argmin f`. -/ +lemma isMinOn_argmin : IsMinOn f Set.univ (argmin f) := + isMinOn_univ_iff.2 fun x ↦ argmin_spec f ▸ f.min_le x variable [MeasurableSpace α] -@[to_dual (attr := fun_prop)] +/-- The maximum of a tuple is a measurable function of the tuple. -/ +@[to_dual (attr := fun_prop) /-- The minimum of a tuple is a measurable function of the tuple. -/] lemma measurable_max [MeasurableSup₂ α] : Measurable (fun (t : ι → α) => t.max) := by suffices (fun f : ι → α ↦ f.max) = (univ.sup' univ_nonempty fun i f => f i) by rw [this] @@ -62,7 +80,8 @@ lemma measurable_max [MeasurableSup₂ α] : Measurable (fun (t : ι → α) => ext simp [Function.max] -@[to_dual (attr := fun_prop)] +/-- The argmax of a tuple is a measurable function of the tuple. -/ +@[to_dual (attr := fun_prop) /-- The argmin of a tuple is a measurable function of the tuple. -/] lemma measurable_argmax [MeasurableSpace ι] [MeasurableEq α] [MeasurableSup₂ α] : Measurable fun f : ι → α ↦ argmax f := by refine measurable_to_countable' fun i ↦ ?_ @@ -90,4 +109,4 @@ lemma neg_max_eq_min_neg [AddGroup α] [AddLeftMono α] [AddRightMono α] : -f.m · simp; grind · simp only [inf'_le_iff, mem_univ, Pi.neg_apply, neg_le_neg_iff, sup'_le_iff, forall_const, true_and] - exact ⟨argmax f, isMaxOn_argmax f⟩ + exact ⟨argmax f, isMaxOn_univ_iff.1 (isMaxOn_argmax f)⟩ diff --git a/LeanMachineLearning/ForMathlib/MeasureTheory/OuterMeasure/Basic.lean b/LeanMachineLearning/ForMathlib/MeasureTheory/OuterMeasure/Basic.lean index 6cb4f21a..5cd071b5 100644 --- a/LeanMachineLearning/ForMathlib/MeasureTheory/OuterMeasure/Basic.lean +++ b/LeanMachineLearning/ForMathlib/MeasureTheory/OuterMeasure/Basic.lean @@ -8,8 +8,7 @@ module public import Mathlib.MeasureTheory.OuterMeasure.Basic /-! -# Lemma about measures that assign non-zero probability to every singleton. - +# Null sets of a measure charging every singleton -/ @[expose] public section @@ -23,6 +22,7 @@ section OuterMeasureClass variable {α F : Type*} [FunLike F (Set α) ℝ≥0∞] [OuterMeasureClass F α] {μ : F} {s : Set α} +/-- For a measure that charges every singleton, the only null set is the empty set. -/ lemma measure_null_iff_eq_empty_of_measure_singleton_ne_zero (h : ∀ a, μ {a} ≠ 0) : μ s = 0 ↔ s = ∅ := by refine ⟨fun hs ↦ ?_, fun he ↦ by simp [he]⟩ diff --git a/LeanMachineLearning/ForMathlib/Order/Interval/Finset/Basic.lean b/LeanMachineLearning/ForMathlib/Order/Interval/Finset/Basic.lean new file mode 100644 index 00000000..ec725910 --- /dev/null +++ b/LeanMachineLearning/ForMathlib/Order/Interval/Finset/Basic.lean @@ -0,0 +1,23 @@ +/- +Copyright (c) 2026 Gaëtan Serré. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Gaëtan Serré +-/ +module + +public import Mathlib.Order.Interval.Finset.Basic + +/-! +# Lemmas about finite intervals + +We record that the interval `Finset.Iic a`, seen as a type, is nonempty. +-/ + +@[expose] public section + +namespace Finset + +instance {α : Type*} [Preorder α] [LocallyFiniteOrderBot α] {a : α} : Nonempty (Iic a) := + nonempty_Iic.to_subtype + +end Finset diff --git a/LeanMachineLearning/ForMathlib/Order/Interval/Finset.lean b/LeanMachineLearning/ForMathlib/Order/Interval/Finset/Nat.lean similarity index 53% rename from LeanMachineLearning/ForMathlib/Order/Interval/Finset.lean rename to LeanMachineLearning/ForMathlib/Order/Interval/Finset/Nat.lean index 9134b80b..535b9317 100644 --- a/LeanMachineLearning/ForMathlib/Order/Interval/Finset.lean +++ b/LeanMachineLearning/ForMathlib/Order/Interval/Finset/Nat.lean @@ -8,13 +8,13 @@ module public import Mathlib.Order.Interval.Finset.Nat /-! -# Lemmas about finite intervals. --/ +# Lemmas about finite intervals of natural numbers -@[expose] public section +## Main statements -namespace Finset +* `coe_default_Iic_zero`: the default element of `Finset.Iic 0` is `0`. +-/ -instance {n : ℕ} : Nonempty (Iic n) := ⟨0, insert_eq_self.mp rfl⟩ +@[expose] public section -end Finset +lemma coe_default_Iic_zero : ((default : Finset.Iic 0) : ℕ) = 0 := rfl diff --git a/LeanMachineLearning/ForMathlib/Probability/ConditionalProbability.lean b/LeanMachineLearning/ForMathlib/Probability/ConditionalProbability.lean index 684cf434..80d7c2f5 100644 --- a/LeanMachineLearning/ForMathlib/Probability/ConditionalProbability.lean +++ b/LeanMachineLearning/ForMathlib/Probability/ConditionalProbability.lean @@ -9,21 +9,55 @@ public import Mathlib.MeasureTheory.Measure.Prod public import Mathlib.Probability.ConditionalProbability /-! # Lemmas about conditional probability + +## Main statements + +* `MeasureTheory.Measure.sum_meas_smul_cond_fiber`: the **law of total probability** for a random + variable taking countably many values. -/ @[expose] public section -open MeasureTheory +open MeasureTheory ProbabilityTheory +open scoped ENNReal + +namespace MeasureTheory.Measure + +variable {Ω α : Type*} {mΩ : MeasurableSpace Ω} [Countable α] {mα : MeasurableSpace α} + [MeasurableSingletonClass α] + +/-- The **law of total probability** for a random variable taking countably many values: a finite +measure `μ` is the sum of its conditional measures `μ[|X ⁻¹' {x}]` on the fibers of `X`, weighted +by the measures of the fibers. See `ProbabilityTheory.sum_meas_smul_cond_fiber` for the version +with a finite sum. -/ +lemma sum_meas_smul_cond_fiber {X : Ω → α} (hX : Measurable X) (μ : Measure Ω) + [IsFiniteMeasure μ] : + Measure.sum (fun x ↦ μ (X ⁻¹' {x}) • μ[|X ⁻¹' {x}]) = μ := by + ext s hs + simp_rw [Measure.sum_apply _ hs, Measure.smul_apply, smul_eq_mul, mul_comm (μ _), + cond_mul_eq_inter (hX (.singleton _))] + rw [← measure_iUnion (fun i j hij ↦ ((Set.disjoint_singleton.2 hij).preimage X).mono + Set.inter_subset_left Set.inter_subset_left) fun i ↦ (hX (.singleton i)).inter hs, + ← Set.iUnion_inter, ← Set.preimage_iUnion, Set.iUnion_singleton_eq_range, Set.range_id', + Set.preimage_univ, Set.univ_inter] + +end MeasureTheory.Measure namespace ProbabilityTheory variable {α β : Type*} {mα : MeasurableSpace α} {mβ : MeasurableSpace β} +lemma lintegral_cond {μ : Measure α} (s : Set α) (f : α → ℝ≥0∞) : + ∫⁻ x, f x ∂μ[|s] = (μ s)⁻¹ * ∫⁻ x in s, f x ∂μ := by + simp [cond, lintegral_smul_measure] + /-- Conditioning a product measure on an event of the first coordinate amounts to conditioning the first measure. -/ -lemma cond_prod_univ {μ : Measure α} [SFinite μ] {ν : Measure β} [IsProbabilityMeasure ν] +lemma cond_prod_univ {μ : Measure α} [SFinite μ] {ν : Measure β} [IsZeroOrProbabilityMeasure ν] (s : Set α) : (μ.prod ν)[|s ×ˢ Set.univ] = (μ[|s]).prod ν := by + rcases eq_zero_or_isProbabilityMeasure ν with rfl | _ + · simp simp only [cond, Measure.prod_prod, measure_univ, mul_one, Measure.prod_smul_left, ← Measure.prod_restrict, Measure.restrict_univ] diff --git a/LeanMachineLearning/ForMathlib/Probability/HasCondDistrib.lean b/LeanMachineLearning/ForMathlib/Probability/HasCondDistrib.lean index 93e9c492..4ef69b4c 100644 --- a/LeanMachineLearning/ForMathlib/Probability/HasCondDistrib.lean +++ b/LeanMachineLearning/ForMathlib/Probability/HasCondDistrib.lean @@ -6,11 +6,30 @@ Authors: Rémy Degenne, Paulo Rauber module public import LeanMachineLearning.ForMathlib.MeasureTheory.MeasurableSpace.Embedding -public import LeanMachineLearning.ForMathlib.Probability.Independence.CondDistrib +public import LeanMachineLearning.ForMathlib.Probability.HasLaw +public import LeanMachineLearning.ForMathlib.Probability.Kernel.CondDistrib +public import LeanMachineLearning.ForMathlib.Probability.Kernel.Basic +public import LeanMachineLearning.ForMathlib.Probability.Kernel.Composition.MeasureCompProd public import Mathlib.Probability.HasCondDistrib /-! -# A predicate for having a specified conditional distribution +# Lemmas about `HasCondDistrib` + +`HasCondDistrib Y X κ μ` states that the conditional distribution of `Y` given `X` under `μ` is +the kernel `κ`. This file complements the API of Mathlib's `Mathlib.Probability.HasCondDistrib`. + +## Main statements + +* `HasCondDistrib.compProd`: chain rule, building the conditional distribution of a pair. +* `hasCondDistrib_measurableEmbedding_comp_right_iff`: conditioning on `f ∘ X` for a measurable + embedding `f` is the same as conditioning on `X`. +* `HasCondDistrib.hasLaw_cond`, `HasCondDistrib.indepFun_cond`: if the conditional distribution + of `Y` given `X` is constant on a set `s`, then `Y` has that law under `μ` conditioned on + `X ∈ s`, and is independent of `X` under that conditioned measure. +* `HasCondDistrib.condDistrib_ae_eq`, `hasCondDistrib_of_condDistrib_ae_eq`: relation with + `condDistrib`. +* `HasCondDistrib.condExp_comp_ae_eq`: the conditional expectation of `g ∘ Y` given `X` is the + integral of `g` against the conditional distribution. -/ @[expose] public section @@ -25,87 +44,39 @@ variable {α β γ Ω Ω' : Type*} {mΩ' : MeasurableSpace Ω'} {μ : Measure α} {X : α → β} {Y : α → Ω} {κ : Kernel β Ω} -lemma hasCondDistrib_fst_prod {Y : α → Ω} {X : α → β} {κ : Kernel β Ω} - {μ : Measure α} {ν : Measure γ} [IsProbabilityMeasure ν] +/-- If `Y` has conditional distribution `κ` given `X` under `μ` and `f` has law `μ` under `P`, +then `Y ∘ f` has conditional distribution `κ` given `X ∘ f` under `P`. -/ +lemma HasCondDistrib.comp_hasLaw {P : Measure Ω'} {f : Ω' → α} (h : HasCondDistrib Y X κ μ) + (hf : HasLaw f μ P) : + HasCondDistrib (Y ∘ f) (X ∘ f) κ P := by + refine ⟨(h.comp hf).aemeasurable, ?_⟩ + rw [← AEMeasurable.map_map_of_aemeasurable (hf.map_eq ▸ h.aemeasurable_fst) hf.aemeasurable, + hf.map_eq] + exact (h.comp hf).map_eq + +lemma hasCondDistrib_fst_prod {ν : Measure γ} [IsProbabilityMeasure ν] (h : HasCondDistrib Y X κ μ) : - HasCondDistrib (fun ω ↦ Y ω.1) (fun ω ↦ X ω.1) κ (μ.prod ν) where - aemeasurable := by fun_prop - map_eq := by - have h_rhs : Measure.map (fun ω ↦ X ω.1) (μ.prod ν) ⊗ₘ κ = (μ.map X) ⊗ₘ κ := by - conv_rhs => rw [← Measure.fst_prod (μ := μ) (ν := ν), Measure.fst] - rw [AEMeasurable.map_map_of_aemeasurable _ (by fun_prop)] - · rfl - · have := h.aemeasurable_fst - simpa - rw [h_rhs, ← h.map_eq] - conv_rhs => rw [← Measure.fst_prod (μ := μ) (ν := ν), Measure.fst] - rw [AEMeasurable.map_map_of_aemeasurable _ (by fun_prop)] - · rfl - · have := h.aemeasurable - simpa - -lemma HasCondDistrib.prod_right [IsFiniteMeasure μ] [IsFiniteKernel κ] (h : HasCondDistrib Y X κ μ) + HasCondDistrib (fun ω ↦ Y ω.1) (fun ω ↦ X ω.1) κ (μ.prod ν) := + h.comp_hasLaw (hasLaw_fst_prod μ ν) + +lemma HasCondDistrib.prod_right [SFinite μ] [IsSFiniteKernel κ] (h : HasCondDistrib Y X κ μ) {f : β → γ} (hf : Measurable f) : - HasCondDistrib Y (fun a ↦ (X a, f (X a))) (κ.prodMkRight _) μ := by - refine ⟨by fun_prop, ?_⟩ - have h_eq := h.map_eq - calc μ.map (fun x ↦ ((X x, f (X x)), Y x)) - _ = (μ.map (fun ω ↦ (X ω, Y ω))).map (fun p ↦ ((p.1, f p.1), p.2)) := by - rw [AEMeasurable.map_map_of_aemeasurable (by fun_prop) (by fun_prop)] - congr - _ = (μ.map X ⊗ₘ κ).map (fun p ↦ ((p.1, f p.1), p.2)) := by rw [h_eq] - _ = (μ.map X).map (fun a ↦ (a, f a)) ⊗ₘ κ.prodMkRight γ := by - rw [Measure.compProd_eq_comp_prod, Measure.compProd_eq_comp_prod, - ← Measure.deterministic_comp_eq_map (f := fun a ↦ (a, f a)), - ← Measure.deterministic_comp_eq_map, Measure.comp_assoc, Measure.comp_assoc] - swap; · fun_prop - swap; · fun_prop - congr 1 - ext b : 1 - rw [Kernel.comp_apply, Kernel.comp_apply, Kernel.prod_apply, Kernel.deterministic_apply, - Kernel.id_apply, Measure.dirac_bind (Kernel.measurable _), Kernel.prod_apply, - Measure.deterministic_comp_eq_map, Kernel.prodMkRight_apply, Kernel.id_apply] - change Measure.map (Prod.map (fun x ↦ (x, f x)) id) ((Measure.dirac b).prod (κ b)) = - (Measure.dirac (b, f b)).prod (κ b) - rw [← Measure.map_prod_map _ _ (by fun_prop) (by fun_prop), Measure.map_id, - Measure.map_dirac' (by fun_prop)] - _ = μ.map (fun a ↦ (X a, f (X a))) ⊗ₘ κ.prodMkRight γ := by - rw [AEMeasurable.map_map_of_aemeasurable (by fun_prop) (by fun_prop)] - congr - -lemma hasCondDistrib_prod_right_iff [IsFiniteMeasure μ] [IsFiniteKernel κ] (X : α → β) (Y : α → Ω) + HasCondDistrib Y (fun a ↦ (X a, f (X a))) (κ.prodMkRight _) μ := + -- `(κ.prodMkRight γ).comap (fun b ↦ (b, f b))` is definitionally equal to `κ` + HasCondDistrib.comp_right (hf := measurable_id.prodMk hf) (Z := X) h + +lemma hasCondDistrib_prod_right_iff [SFinite μ] [IsSFiniteKernel κ] (X : α → β) (Y : α → Ω) {f : β → γ} (hf : Measurable f) : HasCondDistrib Y (fun a ↦ (X a, f (X a))) (κ.prodMkRight _) μ ↔ HasCondDistrib Y X κ μ := by refine ⟨fun h ↦ ?_, fun h ↦ h.prod_right hf⟩ - have hX : AEMeasurable X μ := by - have := h.aemeasurable_snd - have h_eq : X = (fun p ↦ p.1) ∘ (fun a ↦ (X a, f (X a))) := by ext; simp - rw [h_eq] - exact Measurable.comp_aemeasurable (by fun_prop) (by fun_prop) - refine ⟨by fun_prop, ?_⟩ - have h_eq := h.map_eq - calc μ.map (fun x ↦ (X x, Y x)) - _ = (μ.map (fun ω ↦ ((X ω, f (X ω)), Y ω))).map (fun p ↦ (p.1.1, p.2)) := by - rw [AEMeasurable.map_map_of_aemeasurable (by fun_prop) (by fun_prop)] - congr - _ = (μ.map (fun a ↦ (X a, f (X a))) ⊗ₘ κ.prodMkRight γ).map (fun p ↦ (p.1.1, p.2)) := by rw [h_eq] - _ = ((μ.map X).map (fun a ↦ (a, f a)) ⊗ₘ κ.prodMkRight γ).map (fun p ↦ (p.1.1, p.2)) := by - rw [AEMeasurable.map_map_of_aemeasurable (by fun_prop) (by fun_prop)] - congr - _ = μ.map X ⊗ₘ κ := by - simp_rw [Measure.compProd_eq_comp_prod, - ← Measure.deterministic_comp_eq_map (f := fun a ↦ (a, f a)) (by fun_prop), - ← Measure.deterministic_comp_eq_map (f := fun p : (β × γ) × Ω ↦ (p.1.1, p.2)) (by fun_prop), - Measure.comp_assoc] - congr 1 - ext b : 1 - rw [Kernel.comp_apply, Kernel.comp_apply, Kernel.prod_apply, Kernel.id_apply, - Kernel.deterministic_apply, Measure.dirac_bind (Kernel.measurable _), - Kernel.prod_apply, Measure.deterministic_comp_eq_map, Kernel.prodMkRight_apply, - Kernel.id_apply] - change Measure.map (Prod.map (fun x ↦ x.1) id) ((Measure.dirac (b, f b)).prod (κ b)) = _ - rw [← Measure.map_prod_map _ _ (by fun_prop) (by fun_prop), Measure.map_id, - Measure.map_dirac' (by fun_prop)] + have hX : AEMeasurable X μ := measurable_fst.comp_aemeasurable h.aemeasurable_fst + refine ⟨hX.prodMk h.aemeasurable_snd, ?_⟩ + have h_fst : μ.map X = (μ.map (fun a ↦ (X a, f (X a)))).fst := by + rw [Measure.fst, AEMeasurable.map_map_of_aemeasurable (by fun_prop) h.aemeasurable_fst] + rfl + rw [h_fst, ← Measure.map_prodMap_fst_compProd_prodMkRight, ← h.map_eq, + AEMeasurable.map_map_of_aemeasurable (by fun_prop) h.aemeasurable] + rfl lemma HasCondDistrib.indepFun_of_const [IsProbabilityMeasure μ] {Q : Measure Ω} [SFinite Q] (h : HasCondDistrib Y X (Kernel.const β Q) μ) : @@ -130,20 +101,8 @@ lemma hasCondDistrib_self [SFinite μ] (hX : AEMeasurable X μ) : lemma HasCondDistrib.const_map_of_const [IsProbabilityMeasure μ] {Q : Measure Ω} [SFinite Q] (h : HasCondDistrib Y X (Kernel.const β Q) μ) : - HasCondDistrib X Y (Kernel.const Ω (μ.map X)) μ where - aemeasurable := by fun_prop - map_eq := by - calc μ.map (fun ω ↦ (Y ω, X ω)) - _ = (μ.map (fun ω ↦ (X ω, Y ω))).map Prod.swap := by - rw [AEMeasurable.map_map_of_aemeasurable (by fun_prop) (by fun_prop)] - rfl - _ = (μ.map X ⊗ₘ Kernel.const β Q).map Prod.swap := by rw [h.map_eq] - _ = μ.map Y ⊗ₘ Kernel.const Ω (μ.map X) := by simp [h.hasLaw_of_const.map_eq, Measure.prod_swap] - -lemma HasLaw.prod_of_hasCondDistrib {P : Measure β} - (h1 : HasLaw X P μ) (h2 : HasCondDistrib Y X κ μ) : - HasLaw (fun ω ↦ (X ω, Y ω)) (P ⊗ₘ κ) μ := - ⟨by fun_prop, by rw [h2.map_eq, h1.map_eq]⟩ + HasCondDistrib X Y (Kernel.const Ω (μ.map X)) μ := + h.indepFun_of_const.symm.hasCondDistrib_const h.aemeasurable_snd (hasLaw_map h.aemeasurable_fst) /-- `HasCondDistrib` only depends on the almost everywhere equivalence classes of the two random variables. -/ @@ -163,7 +122,10 @@ lemma HasCondDistrib.hasLaw_comp [SFinite μ] [IsSFiniteKernel κ] (h : HasCondD AEMeasurable.map_map_of_aemeasurable (by fun_prop) (by fun_prop)] rfl -lemma HasCondDistrib.prod {Z : α → Ω'} {η : Kernel (β × Ω) Ω'} +/-- Chain rule for conditional distributions: if `κ` is the conditional distribution of `Y` +given `X` and `η` is the conditional distribution of `Z` given `(X, Y)`, then `κ ⊗ₖ η` is the +conditional distribution of `(Y, Z)` given `X`. See `HasCondDistrib.of_compProd` for a converse. -/ +lemma HasCondDistrib.compProd {Z : α → Ω'} {η : Kernel (β × Ω) Ω'} (h1 : HasCondDistrib Y X κ μ) (h2 : HasCondDistrib Z (fun ω ↦ (X ω, Y ω)) η μ) : HasCondDistrib (fun ω ↦ (Y ω, Z ω)) X (κ ⊗ₖ η) μ := by refine ⟨by fun_prop, ?_⟩ @@ -178,24 +140,20 @@ lemma hasCondDistrib_comp_self [SFinite μ] {f : β → Ω} (hf : Measurable f) rw [Measure.compProd_deterministic, AEMeasurable.map_map_of_aemeasurable (by fun_prop) hX] rfl -lemma ae_eq_of_hasCondDistrib_deterministic [MeasurableEq Ω] [SFinite μ] {f : β → Ω} - (hf : Measurable f) (hX : AEMeasurable X μ) - (hY : AEMeasurable Y μ) (h : HasCondDistrib Y X (Kernel.deterministic f hf) μ) : +/-- If the conditional distribution of `Y` given `X` is deterministic, given by a function `f`, then +`Y` is almost surely equal to `f ∘ X`. -/ +lemma HasCondDistrib.ae_eq_of_deterministic [MeasurableEq Ω] [SFinite μ] {f : β → Ω} + {hf : Measurable f} (h : HasCondDistrib Y X (Kernel.deterministic f hf) μ) : Y =ᵐ[μ] f ∘ X := by - refine ae_eq_of_map_prodMk_eq hf hX hY ?_ + refine ae_eq_of_map_prodMk_eq hf h.aemeasurable_fst h.aemeasurable_snd ?_ rw [h.map_eq, Measure.compProd_deterministic, AEMeasurable.map_map_of_aemeasurable (by fun_prop) (by fun_prop)] rfl lemma hasCondDistrib_deterministic_iff [MeasurableEq Ω] [SFinite μ] {f : β → Ω} - (hf : Measurable f) (hX : AEMeasurable X μ) (hY : AEMeasurable Y μ) : - HasCondDistrib Y X (Kernel.deterministic f hf) μ ↔ Y =ᵐ[μ] f ∘ X := by - refine ⟨ae_eq_of_hasCondDistrib_deterministic hf hX hY, fun h ↦ ?_⟩ - refine HasCondDistrib.congr ?_ ?_ h (X := X) - · exact hasCondDistrib_comp_self hf hX - · rfl - -section Const + (hf : Measurable f) (hX : AEMeasurable X μ) : + HasCondDistrib Y X (Kernel.deterministic f hf) μ ↔ Y =ᵐ[μ] f ∘ X := + ⟨fun h ↦ h.ae_eq_of_deterministic, fun h ↦ (hasCondDistrib_comp_self hf hX).congr .rfl h⟩ section CompRight @@ -261,12 +219,7 @@ lemma hasCondDistrib_prodMk_right_unique_iff {U : α → δ} {η : Kernel (β × end UniqueComponent - -lemma _root_.MeasureTheory.Measure.dirac_compProd {κ : Kernel β Ω} [IsSFiniteKernel κ] (b : β) : - Measure.dirac b ⊗ₘ κ = (κ b).map (Prod.mk b) := by - ext s hs - rw [Measure.compProd_apply hs, lintegral_dirac' _ (Kernel.measurable_kernel_prodMk_left hs), - Measure.map_apply measurable_prodMk_left hs] +section Const /-- Conditioning on a constant is the same as having law `κ b`. -/ lemma hasCondDistrib_const_iff [IsProbabilityMeasure μ] [IsSFiniteKernel κ] {b : β} : @@ -285,6 +238,18 @@ alias ⟨HasCondDistrib.hasLaw_of_const', HasLaw.hasCondDistrib_const⟩ := hasC end Const +/-- A random variable with values in `Unit` admits any Markov kernel as conditional +distribution. -/ +lemma hasCondDistrib_unit [SFinite μ] (hX : AEMeasurable X μ) (U : α → Unit) + (η : Kernel β Unit) [IsMarkovKernel η] : + HasCondDistrib U X η μ := by + have hU : U = fun _ ↦ () := funext fun _ ↦ rfl + subst hU + refine HasLaw.mk (hX.prodMk aemeasurable_const) ?_ + rw [η.eq_const_dirac_of_subsingleton (), Measure.compProd_const, Measure.prod_dirac, + AEMeasurable.map_map_of_aemeasurable (by fun_prop) hX] + rfl + section Cond variable [IsSFiniteKernel κ] @@ -307,15 +272,17 @@ variable [IsFiniteMeasure μ] /-- If the conditional distribution of `Y` given `X` is a kernel `κ` which is constant equal to `η` on a measurable set `s`, then the law of `Y` under `μ` conditioned on `X ∈ s` is `η`. -/ -lemma HasCondDistrib.hasLaw_cond (h : HasCondDistrib Y X κ μ) (hY : Measurable Y) +lemma HasCondDistrib.hasLaw_cond (h : HasCondDistrib Y X κ μ) {s : Set β} (hs : MeasurableSet s) {η : Measure Ω} (hκ : Set.EqOn κ (fun _ ↦ η) s) (hμs : μ (X ⁻¹' s) ≠ 0) : HasLaw Y η μ[|X ⁻¹' s] where - aemeasurable := hY.aemeasurable + aemeasurable := h.aemeasurable_snd.mono_ac cond_absolutelyContinuous map_eq := by ext u hu - rw [Measure.map_apply hY hu, cond_apply' (hu.preimage hY), - h.measure_inter_preimage_eq_mul_of_eqOn_const hs hκ hu, ← mul_assoc, + rw [Measure.map_apply_of_aemeasurable (h.aemeasurable_snd.mono_ac cond_absolutelyContinuous) hu, + cond, Measure.smul_apply, smul_eq_mul, + Measure.restrict_apply₀ (h.aemeasurable_snd.restrict.nullMeasurableSet_preimage hu), + Set.inter_comm, h.measure_inter_preimage_eq_mul_of_eqOn_const hs hκ hu, ← mul_assoc, ENNReal.inv_mul_cancel hμs (measure_ne_top _ _), one_mul] /-- If the conditional distribution of `Y` given `X` is a kernel `κ` which is constant on a @@ -344,12 +311,12 @@ end Cond variable [StandardBorelSpace Ω] [Nonempty Ω] [StandardBorelSpace Ω'] [Nonempty Ω'] -lemma HasCondDistrib.condDistrib_eq [IsFiniteMeasure μ] [IsFiniteKernel κ] +lemma HasCondDistrib.condDistrib_ae_eq [IsFiniteMeasure μ] [IsFiniteKernel κ] (h : HasCondDistrib Y X κ μ) : condDistrib Y X μ =ᵐ[μ.map X] κ := by rw [condDistrib_ae_eq_iff_measure_eq_compProd h.aemeasurable_fst h.aemeasurable_snd, h.map_eq] -lemma hasCondDistrib_of_condDistrib_eq [IsFiniteMeasure μ] [IsFiniteKernel κ] +lemma hasCondDistrib_of_condDistrib_ae_eq [IsFiniteMeasure μ] [IsSFiniteKernel κ] (hX : AEMeasurable X μ) (hY : AEMeasurable Y μ) (h : condDistrib Y X μ =ᵐ[μ.map X] κ) : HasCondDistrib Y X κ μ where @@ -365,16 +332,27 @@ lemma HasCondDistrib.hasCondDistrib_sectR [IsFiniteMeasure μ] [StandardBorelSpa suffices ∀ᵐ z ∂μ.map Z, condDistrib g f (condDistrib W Z μ z) =ᵐ[(condDistrib W Z μ z).map f] (η.sectR z) by filter_upwards [this] with z hz - exact hasCondDistrib_of_condDistrib_eq (by fun_prop) (by fun_prop) hz + exact hasCondDistrib_of_condDistrib_ae_eq (by fun_prop) (by fun_prop) hz have h_eq : condDistrib (g ∘ W) (fun a ↦ (Z a, (f ∘ W) a)) μ =ᵐ[μ.map Z ⊗ₘ (condDistrib W Z μ).map f] η := by rw [← Measure.compProd_congr (condDistrib_comp hcd.aemeasurable_fst.fst hW hf), compProd_map_condDistrib hcd.aemeasurable_fst.fst (hf.comp_aemeasurable hW)] - exact hcd.condDistrib_eq + exact hcd.condDistrib_ae_eq filter_upwards [ condDistrib_condDistrib_ae_eq_sectR_condDistrib hf hg hW hcd.aemeasurable_fst.fst, Measure.ae_ae_of_ae_compProd h_eq] with z hc ha rw [Kernel.map_apply _ hf] at ha filter_upwards [hc, ha] with b hcb hab using hcb.trans hab +/-- If `Y` has conditional distribution `κ` given `X`, then the conditional expectation of `g ∘ Y` +given `X` is `∫ y, g y ∂(κ (X ·))`. -/ +lemma HasCondDistrib.condExp_comp_ae_eq [IsFiniteMeasure μ] [IsFiniteKernel κ] + {F : Type*} [NormedAddCommGroup F] [NormedSpace ℝ F] [CompleteSpace F] + (h : HasCondDistrib Y X κ μ) (hX : Measurable X) {g : Ω → F} (hg : StronglyMeasurable g) + (hint : Integrable (fun a ↦ g (Y a)) μ) : + μ[fun a ↦ g (Y a) | mβ.comap X] =ᵐ[μ] fun a ↦ ∫ y, g y ∂(κ (X a)) := by + refine (condExp_ae_eq_integral_condDistrib hX h.aemeasurable_snd hg hint).trans ?_ + filter_upwards [ae_of_ae_map hX.aemeasurable h.condDistrib_ae_eq] with a ha + rw [ha] + end ProbabilityTheory diff --git a/LeanMachineLearning/ForMathlib/Probability/HasLaw.lean b/LeanMachineLearning/ForMathlib/Probability/HasLaw.lean index b8c69102..2ef10159 100644 --- a/LeanMachineLearning/ForMathlib/Probability/HasLaw.lean +++ b/LeanMachineLearning/ForMathlib/Probability/HasLaw.lean @@ -5,13 +5,20 @@ Authors: Rémy Degenne -/ module +public import LeanMachineLearning.ForMathlib.Probability.ConditionalProbability public import Mathlib.MeasureTheory.Constructions.Cylinders public import Mathlib.MeasureTheory.Integral.Indicator -public import Mathlib.Probability.ConditionalProbability public import Mathlib.Probability.HasLaw -public import Mathlib.Probability.IdentDistrib +public import Mathlib.Probability.ProductMeasure /-! # Lemmas about `HasLaw` + +## Main statements + +* `hasLaw_of_forall_hasLaw_cond`: a random variable which has law `μ` conditionally on each atom + of positive probability of a countable measurable partition has law `μ`. +* `hasLaw_of_forall_eventually_eq`: if random variables with law `μ` on a product space converge + coordinatewise and eventually constantly to `Y'`, then `Y'` has law `μ`. -/ @[expose] public section @@ -23,75 +30,50 @@ namespace ProbabilityTheory variable {Ω 𝓧 : Type*} {mΩ : MeasurableSpace Ω} {m𝓧 : MeasurableSpace 𝓧} {P : Measure Ω} -lemma _root_.AEMeasurable.hasLaw_map {X : Ω → 𝓧} (hX : AEMeasurable X P) : - HasLaw X (P.map X) P := ⟨hX, rfl⟩ +section Prod + +variable {𝓨 : Type*} {m𝓨 : MeasurableSpace 𝓨} + +lemma hasLaw_fst_prod (μ : Measure 𝓧) (ν : Measure 𝓨) [IsProbabilityMeasure ν] : + HasLaw Prod.fst μ (μ.prod ν) := + measurePreserving_fst.hasLaw + +lemma hasLaw_snd_prod (μ : Measure 𝓧) [IsProbabilityMeasure μ] (ν : Measure 𝓨) [SFinite ν] : + HasLaw Prod.snd ν (μ.prod ν) := + measurePreserving_snd.hasLaw + +end Prod -lemma _root_.Measurable.hasLaw_map {X : Ω → 𝓧} (hX : Measurable X) (P : Measure Ω) : - HasLaw X (P.map X) P := ⟨hX.aemeasurable, rfl⟩ +lemma hasLaw_eval_infinitePi {ι : Type*} {𝓧 : ι → Type*} {m𝓧 : ∀ i, MeasurableSpace (𝓧 i)} + (μ : (i : ι) → Measure (𝓧 i)) [∀ i, IsProbabilityMeasure (μ i)] (i : ι) : + HasLaw (Function.eval i) (μ i) (Measure.infinitePi μ) := + (measurePreserving_eval_infinitePi μ i).hasLaw section Cond variable {ι : Type*} [Countable ι] {mι : MeasurableSpace ι} [MeasurableSingletonClass ι] -/-- Two random variables which are identically distributed conditionally on each atom of a -countable measurable partition are identically distributed. -/ -lemma identDistrib_of_forall_identDistrib_cond [IsFiniteMeasure P] {g : Ω → ι} - (hg : Measurable g) {X Y : Ω → 𝓧} (hX : Measurable X) (hY : Measurable Y) - (h : ∀ i, IdentDistrib X Y P[|g ⁻¹' {i}] P[|g ⁻¹' {i}]) : - IdentDistrib X Y P P where - aemeasurable_fst := hX.aemeasurable - aemeasurable_snd := hY.aemeasurable - map_eq := by - ext s hs - rw [Measure.map_apply hX hs, Measure.map_apply hY hs] - have h_union (t : Set Ω) : t = ⋃ i, t ∩ g ⁻¹' {i} := by ext; simp - have h_disj (t : Set Ω) : Pairwise (Function.onFun Disjoint fun i ↦ t ∩ g ⁻¹' {i}) := by - intro i j hij - rw [Function.onFun, Set.disjoint_left] - rintro x ⟨-, hi⟩ ⟨-, hj⟩ - exact hij ((show g x = i from hi).symm.trans hj) - rw [h_union (X ⁻¹' s), h_union (Y ⁻¹' s), - measure_iUnion (h_disj _) fun i ↦ (hs.preimage hX).inter (hg (measurableSet_singleton i)), - measure_iUnion (h_disj _) fun i ↦ (hs.preimage hY).inter (hg (measurableSet_singleton i))] - refine tsum_congr fun i ↦ ?_ - rw [Set.inter_comm, ← cond_mul_eq_inter (hg (measurableSet_singleton i)), - Set.inter_comm _ (g ⁻¹' {i}), ← cond_mul_eq_inter (hg (measurableSet_singleton i)), - ← Measure.map_apply hX hs, ← Measure.map_apply hY hs, (h i).map_eq] - /-- If a random variable has law `μ` conditionally on each atom of positive probability of a countable measurable partition, then it has law `μ`. -/ lemma hasLaw_of_forall_hasLaw_cond [IsProbabilityMeasure P] {g : Ω → ι} (hg : Measurable g) - {X : Ω → 𝓧} (hX : Measurable X) {μ : Measure 𝓧} + {X : Ω → 𝓧} (hX : AEMeasurable X P) {μ : Measure 𝓧} (h : ∀ i, P (g ⁻¹' {i}) ≠ 0 → HasLaw X μ P[|g ⁻¹' {i}]) : HasLaw X μ P where - aemeasurable := hX.aemeasurable + aemeasurable := hX map_eq := by - ext s hs - rw [Measure.map_apply hX hs] - have h_union : X ⁻¹' s = ⋃ i, X ⁻¹' s ∩ g ⁻¹' {i} := by ext; simp - have h_disj : Pairwise (Function.onFun Disjoint fun i ↦ X ⁻¹' s ∩ g ⁻¹' {i}) := by - intro i j hij - rw [Function.onFun, Set.disjoint_left] - rintro x ⟨-, hi⟩ ⟨-, hj⟩ - exact hij ((show g x = i from hi).symm.trans hj) - have h_univ : Set.univ = ⋃ i, g ⁻¹' {i} := by ext; simp - have h_disj_univ : Pairwise (Function.onFun Disjoint fun i ↦ g ⁻¹' {i}) := by - intro i j hij - rw [Function.onFun, Set.disjoint_left] - exact fun x hi hj ↦ hij ((show g x = i from hi).symm.trans hj) - calc P (X ⁻¹' s) - _ = ∑' i, P (X ⁻¹' s ∩ g ⁻¹' {i}) := by - conv_lhs => rw [h_union] - exact measure_iUnion h_disj fun i ↦ (hs.preimage hX).inter (hg (measurableSet_singleton i)) - _ = ∑' i, μ s * P (g ⁻¹' {i}) := by - refine tsum_congr fun i ↦ ?_ - rw [Set.inter_comm, ← cond_mul_eq_inter (hg (measurableSet_singleton i))] + have h_eq i : (P (g ⁻¹' {i}) • P[|g ⁻¹' {i}]).map X = P (g ⁻¹' {i}) • μ := by by_cases hi : P (g ⁻¹' {i}) = 0 · simp [hi] - · rw [← Measure.map_apply hX hs, (h i hi).map_eq] - _ = μ s := by - rw [ENNReal.tsum_mul_left, ← measure_iUnion h_disj_univ - fun i ↦ hg (measurableSet_singleton i), ← h_univ, measure_univ, mul_one] + · rw [Measure.map_smul _ (h i hi).aemeasurable, (h i hi).map_eq] + have h_univ : ∑' i, P (g ⁻¹' {i}) = 1 := by + rw [← measure_iUnion (fun i j hij ↦ (Set.disjoint_singleton.2 hij).preimage g) + fun i ↦ hg (.singleton i), ← Set.preimage_iUnion, Set.iUnion_singleton_eq_range, + Set.range_id', Set.preimage_univ, measure_univ] + rw [← Measure.sum_meas_smul_cond_fiber hg P] at hX ⊢ + simp_rw [Measure.map_sum hX, h_eq] + ext s hs + simp_rw [Measure.sum_apply _ hs, Measure.smul_apply, smul_eq_mul, ENNReal.tsum_mul_right, + h_univ, one_mul] end Cond @@ -100,40 +82,42 @@ section Pi variable {ι : Type*} {𝓧 : ι → Type*} [∀ i, MeasurableSpace (𝓧 i)] /-- Let `Y n : Ω → Π i, 𝓧 i` be random variables with law `μ`, indexed by a countably generated -filter `L`. If for every `ω` and `i`, `Y n ω i` is eventually equal to `Y' ω i` along `L`, then `Y'` -also has law `μ`. -/ +filter `L`. If for every `i`, for almost every `ω`, `Y n ω i` is eventually equal to `Y' ω i` +along `L`, then `Y'` also has law `μ`. -/ lemma hasLaw_of_forall_eventually_eq [IsFiniteMeasure P] {κ : Type*} {L : Filter κ} [L.NeBot] [L.IsCountablyGenerated] {μ : Measure (Π i, 𝓧 i)} {Y : κ → Ω → Π i, 𝓧 i} {Y' : Ω → Π i, 𝓧 i} (hY : ∀ n, Measurable (Y n)) (hY' : AEMeasurable Y' P) - (h_law : ∀ n, HasLaw (Y n) μ P) (h_lim : ∀ ω i, ∀ᶠ n in L, Y n ω i = Y' ω i) : - HasLaw Y' μ P where - aemeasurable := hY' - map_eq := by - refine ext_of_generate_finite (measurableCylinders _) generateFrom_measurableCylinders.symm - isPiSystem_measurableCylinders (fun s hs ↦ ?_) ?_ - · obtain ⟨I, S, hS, rfl⟩ := (mem_measurableCylinders s).1 hs - rw [Measure.map_apply_of_aemeasurable hY' (hS.cylinder _)] - have h_tendsto : Tendsto (fun n ↦ P (Y n ⁻¹' cylinder I S)) L - (𝓝 (P (Y' ⁻¹' cylinder I S))) := by - refine tendsto_measure_of_tendsto_indicator_of_isFiniteMeasure L P - (fun n ↦ (hS.cylinder _).preimage (hY n)) fun ω ↦ ?_ - have h_ev : ∀ᶠ n in L, ∀ i ∈ I, Y n ω i = Y' ω i := - (eventually_all_finset I).2 fun i _ ↦ h_lim ω i - filter_upwards [h_ev] with n hn - simp only [Set.mem_preimage, mem_cylinder] - have : I.restrict (Y n ω) = I.restrict (Y' ω) := funext fun i ↦ hn i i.2 - rw [this] - have h_const : Tendsto (fun n ↦ P (Y n ⁻¹' cylinder I S)) L (𝓝 (μ (cylinder I S))) := by - have : (fun n ↦ P (Y n ⁻¹' cylinder I S)) = fun _ ↦ μ (cylinder I S) := by - funext n - rw [← Measure.map_apply (hY n) (hS.cylinder _), (h_law n).map_eq] - rw [this] - exact tendsto_const_nhds - exact tendsto_nhds_unique h_tendsto h_const - · obtain ⟨n⟩ := L.nonempty_of_neBot - rw [Measure.map_apply_of_aemeasurable hY' MeasurableSet.univ, Set.preimage_univ, - ← (h_law n).map_eq, - Measure.map_apply (hY n) MeasurableSet.univ, Set.preimage_univ] + (h_law : ∀ n, HasLaw (Y n) μ P) (h_lim : ∀ i, ∀ᵐ ω ∂P, ∀ᶠ n in L, Y n ω i = Y' ω i) : + HasLaw Y' μ P := by + -- we replace `Y'` by a measurable function almost everywhere equal to it + refine HasLaw.congr ?_ hY'.ae_eq_mk + have hY'm := hY'.measurable_mk + have h_lim' i : ∀ᵐ ω ∂P, ∀ᶠ n in L, Y n ω i = hY'.mk Y' ω i := by + filter_upwards [h_lim i, hY'.ae_eq_mk] with ω hω h_eq + rwa [← h_eq] + refine ⟨hY'm.aemeasurable, ?_⟩ + -- two finite measures which agree on measurable cylinders are equal + refine ext_of_generate_finite (measurableCylinders _) generateFrom_measurableCylinders.symm + isPiSystem_measurableCylinders (fun s hs ↦ ?_) ?_ + · obtain ⟨I, S, hS, rfl⟩ := (mem_measurableCylinders s).1 hs + rw [Measure.map_apply hY'm (hS.cylinder _)] + have h_tendsto : Tendsto (fun n ↦ P (Y n ⁻¹' cylinder I S)) L + (𝓝 (P (hY'.mk Y' ⁻¹' cylinder I S))) := by + refine tendsto_measure_of_ae_tendsto_indicator_of_isFiniteMeasure L + ((hS.cylinder _).preimage hY'm) (fun n ↦ (hS.cylinder _).preimage (hY n)) ?_ + filter_upwards [(eventually_all_finset I).2 fun i _ ↦ h_lim' i] with ω hω + filter_upwards [(eventually_all_finset I).2 hω] with n hn + simp only [Set.mem_preimage, mem_cylinder] + have : I.restrict (Y n ω) = I.restrict (hY'.mk Y' ω) := funext fun i ↦ hn i i.2 + rw [this] + have h_const : (fun n ↦ P (Y n ⁻¹' cylinder I S)) = fun _ ↦ μ (cylinder I S) := by + funext n + rw [← Measure.map_apply (hY n) (hS.cylinder _), (h_law n).map_eq] + rw [h_const] at h_tendsto + exact tendsto_nhds_unique h_tendsto tendsto_const_nhds + · obtain ⟨n⟩ := L.nonempty_of_neBot + rw [Measure.map_apply hY'm MeasurableSet.univ, Set.preimage_univ, ← (h_law n).map_eq, + Measure.map_apply (hY n) MeasurableSet.univ, Set.preimage_univ] end Pi diff --git a/LeanMachineLearning/ForMathlib/Probability/IdentDistrib.lean b/LeanMachineLearning/ForMathlib/Probability/IdentDistrib.lean new file mode 100644 index 00000000..3f91d0fd --- /dev/null +++ b/LeanMachineLearning/ForMathlib/Probability/IdentDistrib.lean @@ -0,0 +1,81 @@ +/- +Copyright (c) 2025 Rémy Degenne. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Rémy Degenne, Paulo Rauber +-/ +module + +public import LeanMachineLearning.ForMathlib.Probability.ConditionalProbability +public import Mathlib.Probability.IdentDistrib + +/-! +# Lemmas about identically distributed random variables + +## Main statements + +* `identDistrib_map_right_iff`, `identDistrib_map_left_iff`: identical distribution with a random + variable under an image measure. +* `identDistrib_of_forall_identDistrib_cond`: two random variables which are identically + distributed conditionally on each atom of a countable measurable partition are identically + distributed. +-/ + +@[expose] public section + +open MeasureTheory + +namespace ProbabilityTheory + +section Map + +variable {Ω Ω' E : Type*} {mΩ : MeasurableSpace Ω} {mΩ' : MeasurableSpace Ω'} + {mE : MeasurableSpace E} {μ ν : Measure Ω} + +lemma identDistrib_map_right_iff {X : Ω → E} {Y : Ω' → E} {f : Ω → Ω'} + (hf : AEMeasurable f ν) (hX : AEMeasurable X μ) (hY : AEMeasurable Y (ν.map f)) : + IdentDistrib X Y μ (ν.map f) ↔ IdentDistrib X (Y ∘ f) μ ν := by + refine ⟨fun h ↦ ?_, fun h ↦ ?_⟩ + · constructor + · exact hX + · fun_prop + · rw [h.map_eq, AEMeasurable.map_map_of_aemeasurable (by fun_prop) hf] + · constructor + · exact hX + · fun_prop + · rw [h.map_eq, AEMeasurable.map_map_of_aemeasurable hY hf] + +lemma identDistrib_comm (X : Ω → E) (Y : Ω' → E) {ν : Measure Ω'} : + IdentDistrib X Y μ ν ↔ IdentDistrib Y X ν μ := + ⟨fun h ↦ h.symm, fun h ↦ h.symm⟩ + +lemma identDistrib_map_left_iff {X : Ω → E} {Y : Ω' → E} {f : Ω → Ω'} + (hf : AEMeasurable f ν) (hX : AEMeasurable X μ) (hY : AEMeasurable Y (ν.map f)) : + IdentDistrib Y X (ν.map f) μ ↔ IdentDistrib (Y ∘ f) X ν μ := by + rw [identDistrib_comm Y, identDistrib_comm _ X] + exact identDistrib_map_right_iff hf hX hY + +end Map + +section Cond + +variable {Ω 𝓧 ι : Type*} {mΩ : MeasurableSpace Ω} {m𝓧 : MeasurableSpace 𝓧} {P : Measure Ω} + [Countable ι] {mι : MeasurableSpace ι} [MeasurableSingletonClass ι] + +/-- Two random variables which are identically distributed conditionally on each atom of a +countable measurable partition are identically distributed. -/ +lemma identDistrib_of_forall_identDistrib_cond [IsFiniteMeasure P] {g : Ω → ι} + (hg : Measurable g) {X Y : Ω → 𝓧} (hX : AEMeasurable X P) (hY : AEMeasurable Y P) + (h : ∀ i, IdentDistrib X Y P[|g ⁻¹' {i}] P[|g ⁻¹' {i}]) : + IdentDistrib X Y P P where + aemeasurable_fst := hX + aemeasurable_snd := hY + map_eq := by + rw [← Measure.sum_meas_smul_cond_fiber hg P] at hX hY ⊢ + simp_rw [Measure.map_sum hX, Measure.map_sum hY] + congr with i : 1 + rw [Measure.map_smul _ (h i).aemeasurable_fst, Measure.map_smul _ (h i).aemeasurable_snd, + (h i).map_eq] + +end Cond + +end ProbabilityTheory diff --git a/LeanMachineLearning/ForMathlib/Probability/Independence/IndepFun.lean b/LeanMachineLearning/ForMathlib/Probability/Independence/Basic.lean similarity index 72% rename from LeanMachineLearning/ForMathlib/Probability/Independence/IndepFun.lean rename to LeanMachineLearning/ForMathlib/Probability/Independence/Basic.lean index 297c9c4b..8525ab8a 100644 --- a/LeanMachineLearning/ForMathlib/Probability/Independence/IndepFun.lean +++ b/LeanMachineLearning/ForMathlib/Probability/Independence/Basic.lean @@ -5,10 +5,24 @@ Authors: Rémy Degenne, Paulo Rauber -/ module -public import Mathlib.Probability.IdentDistrib -public import Mathlib.Probability.Independence.InfinitePi +public import LeanMachineLearning.ForMathlib.Probability.HasLaw +public import Mathlib.Probability.Independence.Basic /-! # Lemmas about independence + +## Main statements + +* `indepFun_cond_of_indepFun`: if `X` and `Y` are independent, they are still independent under + the measure conditioned on an event about `Y`. +* `iIndepFun_nat_iff_forall_indepFun`: a sequence of random variables is independent iff each + of them is independent of the previous ones. +* `indepFun_map_iff`: independence under an image measure. +* `IndepFun.comp_hasLaw`: independence is preserved by composition with a random variable with + the right law. +* `IndepFun.of_measurable`: if `Y` and `Z` are independent, then so are any `Y'` measurable with + respect to `σ(Y)` and any `Z'` measurable with respect to `σ(Z)`. +* `cond_of_indepFun`: if `X` and `T` are independent, conditioning on an event about `X` does not + change the law of `T`. -/ @[expose] public section @@ -17,7 +31,7 @@ open MeasureTheory Finset namespace ProbabilityTheory -variable {α Ω Ω' E ι : Type*} [Countable ι] {mα : MeasurableSpace α} +variable {α Ω Ω' E : Type*} {mα : MeasurableSpace α} {mΩ : MeasurableSpace Ω} {mΩ' : MeasurableSpace Ω'} {mE : MeasurableSpace E} {μ ν : Measure Ω} @@ -117,8 +131,9 @@ lemma iIndepFun_nat_iff_forall_indepFun [IsProbabilityMeasure μ] {X : ℕ → ih _ (erase_ssubset (max'_mem _ hs)) fun i hi => hsets i (erase_subset _ _ hi), prod_insert (notMem_erase _ _)] --- todo: kernel version? -lemma IndepFun_map_iff [IsFiniteMeasure μ] {X : Ω' → E} {Y : Ω' → E} {f : Ω → Ω'} +-- TODO: kernel version? +lemma indepFun_map_iff {F : Type*} {mF : MeasurableSpace F} [IsFiniteMeasure μ] {X : Ω' → E} + {Y : Ω' → F} {f : Ω → Ω'} (hf : AEMeasurable f μ) (hX : AEMeasurable X (μ.map f)) (hY : AEMeasurable Y (μ.map f)) : X ⟂ᵢ[μ.map f] Y ↔ (X ∘ f) ⟂ᵢ[μ] (Y ∘ f) := by rw [indepFun_iff_map_prod_eq_prod_map_map hX hY, @@ -127,37 +142,14 @@ lemma IndepFun_map_iff [IsFiniteMeasure μ] {X : Ω' → E} {Y : Ω' → E} {f : AEMeasurable.map_map_of_aemeasurable (by fun_prop) (by fun_prop)] rfl -lemma iIndepFun_map_iff [IsProbabilityMeasure μ] {X : ι → Ω' → E} {f : Ω → Ω'} - (hf : AEMeasurable f μ) (hX : ∀ n, AEMeasurable (X n) (μ.map f)) : - iIndepFun X (μ.map f) ↔ iIndepFun (fun n ↦ X n ∘ f) μ := by - rw [iIndepFun_iff_map_fun_eq_infinitePi_map₀' hX, - iIndepFun_iff_map_fun_eq_infinitePi_map₀' (by fun_prop)] - rw [AEMeasurable.map_map_of_aemeasurable (by fun_prop) hf] - congr! 3 - rw [AEMeasurable.map_map_of_aemeasurable (hX _) hf] - -lemma identDistrib_map_right_iff {X : Ω → E} {Y : Ω' → E} {f : Ω → Ω'} - (hf : AEMeasurable f ν) (hX : AEMeasurable X μ) (hY : AEMeasurable Y (ν.map f)) : - IdentDistrib X Y μ (ν.map f) ↔ IdentDistrib X (Y ∘ f) μ ν := by - refine ⟨fun h ↦ ?_, fun h ↦ ?_⟩ - · constructor - · exact hX - · fun_prop - · rw [h.map_eq, AEMeasurable.map_map_of_aemeasurable (by fun_prop) hf] - · constructor - · exact hX - · fun_prop - · rw [h.map_eq, AEMeasurable.map_map_of_aemeasurable hY hf] - -lemma identDistrib_comm (X : Ω → E) (Y : Ω' → E) {ν : Measure Ω'} : - IdentDistrib X Y μ ν ↔ IdentDistrib Y X ν μ := - ⟨fun h ↦ h.symm, fun h ↦ h.symm⟩ - -lemma identDistrib_map_left_iff {X : Ω → E} {Y : Ω' → E} {f : Ω → Ω'} - (hf : AEMeasurable f ν) (hX : AEMeasurable X μ) (hY : AEMeasurable Y (ν.map f)) : - IdentDistrib Y X (ν.map f) μ ↔ IdentDistrib (Y ∘ f) X ν μ := by - rw [identDistrib_comm Y, identDistrib_comm _ X] - exact identDistrib_map_right_iff hf hX hY +/-- If `X` and `Y` are independent under `μ'` and `f` has law `μ'` under `μ`, then `X ∘ f` and +`Y ∘ f` are independent under `μ`. -/ +lemma IndepFun.comp_hasLaw {F : Type*} {mF : MeasurableSpace F} [IsFiniteMeasure μ] + {μ' : Measure Ω'} {X : Ω' → E} {Y : Ω' → F} {f : Ω → Ω'} (h : X ⟂ᵢ[μ'] Y) + (hf : HasLaw f μ' μ) (hX : AEMeasurable X μ') (hY : AEMeasurable Y μ') : + (X ∘ f) ⟂ᵢ[μ] (Y ∘ f) := by + rw [← hf.map_eq] at h hX hY + exact (indepFun_map_iff hf.aemeasurable hX hY).1 h end ProbabilityTheory @@ -168,13 +160,17 @@ section Prod variable {α β γ δ : Type*} {mα : MeasurableSpace α} {mβ : MeasurableSpace β} {mγ : MeasurableSpace γ} {mδ : MeasurableSpace δ} -lemma hasLaw_fst_prod (μ : Measure α) (ν : Measure β) [IsProbabilityMeasure ν] : - HasLaw Prod.fst μ (μ.prod ν) where - map_eq := Measure.fst_prod +lemma indepFun_fst_prod {μ : Measure α} [IsFiniteMeasure μ] {X : α → γ} {Y : α → δ} + (hX : AEMeasurable X μ) (hY : AEMeasurable Y μ) (h_indep : IndepFun X Y μ) + (ν : Measure β) [IsProbabilityMeasure ν] : + IndepFun (fun ω ↦ X ω.1) (fun ω ↦ Y ω.1) (μ.prod ν) := + h_indep.comp_hasLaw (hasLaw_fst_prod μ ν) hX hY -lemma hasLaw_snd_prod (μ : Measure α) [IsProbabilityMeasure μ] (ν : Measure β) [SFinite ν] : - HasLaw Prod.snd ν (μ.prod ν) where - map_eq := Measure.snd_prod +lemma indepFun_snd_prod {μ : Measure α} [IsFiniteMeasure μ] {X : α → γ} {Y : α → δ} + (hX : AEMeasurable X μ) (hY : AEMeasurable Y μ) (h_indep : IndepFun X Y μ) + (ν : Measure β) [IsProbabilityMeasure ν] : + IndepFun (fun ω ↦ X ω.2) (fun ω ↦ Y ω.2) (ν.prod μ) := + h_indep.comp_hasLaw (hasLaw_snd_prod ν μ) hX hY /-- If `X` and `T` are independent under `ν`, then under `μ.prod ν` the function `X ∘ Prod.snd` is independent of `(Prod.fst, T ∘ Prod.snd)`. -/ @@ -244,4 +240,48 @@ lemma iIndepFun.indepFun_of_measurable_iSup_comap {ι Ω β : Type*} {𝓧 : ι (Set.disjoint_singleton_left.2 hi) simpa using h +section OfMeasurable + +variable {α γ δ γ' δ' : Type*} {mα : MeasurableSpace α} {mγ : MeasurableSpace γ} + {mδ : MeasurableSpace δ} {mγ' : MeasurableSpace γ'} {mδ' : MeasurableSpace δ'} + {μ : Measure α} {Y : α → γ} {Z : α → δ} {Y' : α → γ'} {Z' : α → δ'} + +lemma IndepFun.of_measurable_left + (h_indep : Y ⟂ᵢ[μ] Z) (hY_meas : Measurable[mγ.comap Y] Y') : + Y' ⟂ᵢ[μ] Z := by + rw [IndepFun_iff_Indep] at h_indep ⊢ + exact indep_of_indep_of_le_left h_indep hY_meas.comap_le + +lemma IndepFun.of_measurable_right + (h_indep : Y ⟂ᵢ[μ] Z) (hZ_meas : Measurable[mδ.comap Z] Z') : + Y ⟂ᵢ[μ] Z' := by + rw [IndepFun_iff_Indep] at h_indep ⊢ + exact indep_of_indep_of_le_right h_indep hZ_meas.comap_le + +lemma IndepFun.of_measurable (h_indep : Y ⟂ᵢ[μ] Z) + (hY_meas : Measurable[mγ.comap Y] Y') (hZ_meas : Measurable[mδ.comap Z] Z') : + Y' ⟂ᵢ[μ] Z' := + (h_indep.of_measurable_left hY_meas).of_measurable_right hZ_meas + +end OfMeasurable + +section Cond + +variable {α β γ : Type*} {mα : MeasurableSpace α} {mβ : MeasurableSpace β} + {mγ : MeasurableSpace γ} {μ : Measure α} {X : α → β} {T : α → γ} + +lemma cond_of_indepFun [IsZeroOrProbabilityMeasure μ] (h : IndepFun X T μ) + (hX : Measurable X) (hT : Measurable T) {s : Set β} (hs : MeasurableSet s) + (hμs : μ (X ⁻¹' s) ≠ 0) : + (μ[|X ⁻¹' s]).map T = μ.map T := by + ext t ht + rw [Measure.map_apply (by fun_prop) ht, Measure.map_apply (by fun_prop) ht, cond_apply (hX hs), + IndepSet.measure_inter_eq_mul, ← mul_assoc, ENNReal.inv_mul_cancel, one_mul] + · exact hμs + · simp + · rw [indepFun_iff_indepSet_preimage hX hT] at h + exact h s t hs ht + +end Cond + end ProbabilityTheory diff --git a/LeanMachineLearning/ForMathlib/Probability/Independence/CondDistrib.lean b/LeanMachineLearning/ForMathlib/Probability/Independence/CondDistrib.lean deleted file mode 100644 index 193345a7..00000000 --- a/LeanMachineLearning/ForMathlib/Probability/Independence/CondDistrib.lean +++ /dev/null @@ -1,592 +0,0 @@ -/- -Copyright (c) 2025 Rémy Degenne. All rights reserved. -Released under Apache 2.0 license as described in the file LICENSE. -Authors: Rémy Degenne --/ -module - -public import LeanMachineLearning.ForMathlib.Probability.Kernel.KernelSub -public import Mathlib.MeasureTheory.Measure.ProbabilityMeasure -public import Mathlib.Probability.Independence.Basic -public import Mathlib.Probability.Independence.Conditional - -import Mathlib.Probability.Kernel.CompProdEqIff - -/-! -# Lemmas about conditional distributions - --/ - -@[expose] public section - -open MeasureTheory ProbabilityTheory Finset -open scoped ENNReal NNReal - -variable {α β γ δ Ω Ω' : Type*} - {m mα : MeasurableSpace α} {μ : Measure α} {mβ : MeasurableSpace β} {mγ : MeasurableSpace γ} - {mδ : MeasurableSpace δ} - [MeasurableSpace Ω] [StandardBorelSpace Ω] [Nonempty Ω] - [mΩ' : MeasurableSpace Ω'] [StandardBorelSpace Ω'] [Nonempty Ω'] - {X : α → β} {Y : α → Ω} {Z : α → Ω'} {T : α → γ} - -namespace ProbabilityTheory - -section CondDistrib - -variable [IsFiniteMeasure μ] - -lemma map_swap_compProd_map_condDistrib (hX : AEMeasurable X μ) (hY : AEMeasurable Y μ) : - (μ.map X ⊗ₘ condDistrib Y X μ).map Prod.swap = μ.map (fun a ↦ (Y a, X a)) := by - rw [compProd_map_condDistrib hX hY, - AEMeasurable.map_map_of_aemeasurable measurable_swap.aemeasurable (hX.prodMk hY)] - rfl - -lemma condDistrib_prod_left [StandardBorelSpace β] [Nonempty β] - (hX : AEMeasurable X μ) (hY : AEMeasurable Y μ) (hT : AEMeasurable T μ) : - condDistrib (fun ω ↦ (X ω, Y ω)) T μ - =ᵐ[μ.map T] condDistrib X T μ ⊗ₖ condDistrib Y (fun ω ↦ (T ω, X ω)) μ := by - refine condDistrib_ae_eq_of_measure_eq_compProd hT (by fun_prop) ?_ - rw [← Measure.compProd_assoc', compProd_map_condDistrib hT hX, - compProd_map_condDistrib (hT.prodMk hX) hY, - AEMeasurable.map_map_of_aemeasurable (by fun_prop) (by fun_prop)] - rfl - -lemma condDistrib_condDistrib_ae_eq_sectR_condDistrib [StandardBorelSpace β] [Nonempty β] - {f : Ω' → β} {g : Ω' → Ω} (hf : Measurable f) (hg : Measurable g) (hZ : AEMeasurable Z μ) - (hT : AEMeasurable T μ) : - ∀ᵐ t ∂(μ.map T), - condDistrib g f (condDistrib Z T μ t) =ᵐ[(condDistrib Z T μ t).map f] - (condDistrib (g ∘ Z) (fun a ↦ (T a, (f ∘ Z) a)) μ).sectR t := by - filter_upwards [ - condDistrib_prod_left (hf.comp_aemeasurable hZ) (hg.comp_aemeasurable hZ) hT, - condDistrib_comp hT hZ (hf.prodMk hg), condDistrib_comp hT hZ hf] with t h_prod h_pair h_fst - rw [condDistrib_ae_eq_iff_measure_eq_compProd hf.aemeasurable hg.aemeasurable] - calc (condDistrib Z T μ t).map (fun ω' ↦ (f ω', g ω')) - _ = condDistrib (fun a ↦ ((f ∘ Z) a, (g ∘ Z) a)) T μ t := by - rw [← Kernel.map_apply _ (hf.prodMk hg)] - exact h_pair.symm - _ = (condDistrib Z T μ t).map f - ⊗ₘ (condDistrib (g ∘ Z) (fun a ↦ (T a, (f ∘ Z) a)) μ).sectR t := by - rw [h_prod, Kernel.compProd_apply_eq_compProd_sectR, h_fst, Kernel.map_apply _ hf] - -lemma condDistrib_prod_self_left [StandardBorelSpace β] [Nonempty β] [StandardBorelSpace γ] - [Nonempty γ] - (hX : AEMeasurable X μ) (hT : AEMeasurable T μ) : - condDistrib (fun ω ↦ (X ω, T ω)) T μ =ᵐ[μ.map T] condDistrib X T μ ×ₖ Kernel.id := by - have h_prod := condDistrib_prod_left hX hT hT (μ := μ) - have h_fst := condDistrib_comp_self (μ := μ) (X := fun ω ↦ (T ω, X ω)) (f := Prod.fst) - (hT.prodMk hX) measurable_fst - rw [(compProd_map_condDistrib hT hX).symm] at h_fst - have h_fst' := (Measure.ae_compProd_iff (Kernel.measurableSet_eq _ _)).mp h_fst - filter_upwards [h_prod, h_fst'] with z hz1 hz2 - rw [hz1] - simp only [Kernel.deterministic_apply] at hz2 - change ∀ᵐ y ∂(condDistrib X T μ z), condDistrib T (fun ω ↦ (T ω, X ω)) μ (z, y) = Measure.dirac z - at hz2 - ext t ht - rw [Kernel.compProd_apply ht] - calc ∫⁻ y, condDistrib T (fun ω ↦ (T ω, X ω)) μ (z, y) (Prod.mk y ⁻¹' t) ∂condDistrib X T μ z - _ = ∫⁻ y, (Measure.dirac z) (Prod.mk y ⁻¹' t) ∂condDistrib X T μ z := - lintegral_congr_ae (hz2.mono fun y hy ↦ by simp only [hy]) - _ = ∫⁻ y, (Prod.mk y ⁻¹' t).indicator 1 z ∂condDistrib X T μ z := - lintegral_congr fun y ↦ Measure.dirac_apply' _ (ht.preimage (by fun_prop)) - _ = (condDistrib X T μ z) ((fun y ↦ (y, z)) ⁻¹' t) := by - rw [← lintegral_indicator_one (ht.preimage (by fun_prop : Measurable fun y ↦ (y, z)))] - exact lintegral_congr fun _ ↦ rfl - _ = ((condDistrib X T μ ×ₖ Kernel.id) z) t := by - rw [Kernel.prod_apply, Kernel.id_apply, Measure.prod_apply_symm ht, lintegral_dirac] - --- proved by Claude, then modified -lemma CondIndepFun.prod_right [StandardBorelSpace α] [StandardBorelSpace β] [Nonempty β] - [StandardBorelSpace γ] [Nonempty γ] [StandardBorelSpace δ] [Nonempty δ] - {X : α → β} {Y : α → γ} {Z : α → δ} - (hX : Measurable X) (hY : Measurable Y) (hZ : Measurable Z) - (h : X ⟂ᵢ[Z, hZ; μ] Y) : - X ⟂ᵢ[Z, hZ; μ] (fun ω ↦ (Y ω, Z ω)) := by - rw [condIndepFun_iff_condDistrib_prod_ae_eq_prodMkRight hY hX hZ, - condDistrib_ae_eq_iff_measure_eq_compProd (by fun_prop) (by fun_prop)] at h - rw [condIndepFun_iff_condDistrib_prod_ae_eq_prodMkRight (by fun_prop) hX hZ, - condDistrib_ae_eq_iff_measure_eq_compProd (by fun_prop) (by fun_prop)] - -- Key: condDistrib (Y, Z) Z μ z = (condDistrib Y Z μ z).map (y ↦ (y, z)) - have h_cond : condDistrib (fun ω ↦ (Y ω, Z ω)) Z μ =ᵐ[μ.map Z] - fun z ↦ (condDistrib Y Z μ z).map (fun y ↦ (y, z)) := by - suffices condDistrib (fun ω ↦ (Y ω, Z ω)) Z μ =ᵐ[μ.map Z] - (condDistrib Y Z μ) ×ₖ Kernel.id by - refine this.trans (ae_of_all _ fun x ↦ ?_) - simp only - rw [Kernel.prod_apply, Kernel.id_apply] - ext s hs - rw [Measure.map_apply (by fun_prop) hs, Measure.prod_apply_symm hs, lintegral_dirac] - exact condDistrib_prod_self_left hY.aemeasurable hZ.aemeasurable - -- Main calculation - calc μ.map (fun x ↦ ((Z x, X x), (Y x, Z x))) - _ = (μ.map (fun x ↦ ((Z x, X x), Y x))).map (fun p ↦ (p.1, (p.2, p.1.1))) := by - rw [Measure.map_map (by fun_prop) (by fun_prop)]; rfl - _ = (μ.map (fun ω ↦ (Z ω, X ω)) ⊗ₘ (condDistrib Y Z μ).prodMkRight β).map - (fun p ↦ (p.1, (p.2, p.1.1))) := by rw [h] - _ = μ.map (fun ω ↦ (Z ω, X ω)) ⊗ₘ (condDistrib (fun ω ↦ (Y ω, Z ω)) Z μ).prodMkRight β := by - ext s hs - rw [Measure.map_apply (by fun_prop) hs, - Measure.compProd_apply (hs.preimage (by fun_prop)), Measure.compProd_apply hs] - have h_cond' : ∀ᵐ p ∂(μ.map (fun ω ↦ (Z ω, X ω))), - condDistrib (fun ω ↦ (Y ω, Z ω)) Z μ p.1 = - (condDistrib Y Z μ p.1).map (fun y ↦ (y, p.1)) := by - have h_fst : (μ.map (fun ω ↦ (Z ω, X ω))).map Prod.fst = μ.map Z := by - rw [Measure.map_map (by fun_prop) (by fun_prop)]; rfl - rw [← h_fst] at h_cond - exact mem_ae_of_mem_ae_map (by fun_prop) h_cond - refine lintegral_congr_ae (h_cond'.mono fun ⟨z, x⟩ hzx ↦ ?_) - simp only [Kernel.prodMkRight_apply, hzx, - Measure.map_apply (by fun_prop : Measurable fun y ↦ (y, z)) - (hs.preimage (by fun_prop : Measurable (Prod.mk (z, x))))] - congr 1 - -lemma fst_condDistrib_prod [StandardBorelSpace β] [Nonempty β] - (hX : AEMeasurable X μ) (hY : AEMeasurable Y μ) (hT : AEMeasurable T μ) : - (condDistrib (fun ω ↦ (X ω, Y ω)) T μ).fst =ᵐ[μ.map T] condDistrib X T μ := by - filter_upwards [condDistrib_prod_left hX hY hT] with c hc - rw [Kernel.fst_apply, hc, ← Kernel.fst_apply, Kernel.fst_compProd] - -lemma condDistrib_of_indepFun (h : IndepFun X Y μ) (hX : AEMeasurable X μ) (hY : AEMeasurable Y μ) : - condDistrib Y X μ =ᵐ[μ.map X] Kernel.const β (μ.map Y) := by - refine condDistrib_ae_eq_of_measure_eq_compProd hX hY ?_ - simp only [Measure.compProd_const] - exact (indepFun_iff_map_prod_eq_prod_map_map hX hY).mp h - -lemma indepFun_iff_condDistrib_eq_const (hX : AEMeasurable X μ) (hY : AEMeasurable Y μ) : - IndepFun X Y μ ↔ condDistrib Y X μ =ᵐ[μ.map X] Kernel.const β (μ.map Y) := by - refine ⟨fun h ↦ condDistrib_of_indepFun h hX hY, fun h ↦ ?_⟩ - rw [indepFun_iff_map_prod_eq_prod_map_map hX hY, ← compProd_map_condDistrib hX hY, - Measure.compProd_congr h] - simp - -lemma Measure.snd_compProd_prodMkLeft {α β γ : Type*} - {mα : MeasurableSpace α} {mβ : MeasurableSpace β} {mγ : MeasurableSpace γ} - {μ : Measure (α × β)} [SFinite μ] {κ : Kernel β γ} [IsSFiniteKernel κ] : - (μ ⊗ₘ (κ.prodMkLeft α)).snd = κ ∘ₘ μ.snd := by - ext s hs - rw [Measure.snd_apply hs, Measure.compProd_apply (hs.preimage (by fun_prop)), - Measure.bind_apply hs (by fun_prop), Measure.snd, - lintegral_map (κ.measurable_coe hs) (by fun_prop)] - simp only [Kernel.prodMkLeft_apply] - congr - -lemma Measure.snd_compProd_prodMkRight {α β γ : Type*} - {mα : MeasurableSpace α} {mβ : MeasurableSpace β} {mγ : MeasurableSpace γ} - {μ : Measure (α × β)} [SFinite μ] {κ : Kernel α γ} [IsSFiniteKernel κ] : - (μ ⊗ₘ (κ.prodMkRight β)).snd = κ ∘ₘ μ.fst := by - ext s hs - rw [Measure.snd_apply hs, Measure.compProd_apply (hs.preimage (by fun_prop)), - Measure.bind_apply hs (by fun_prop), Measure.fst, - lintegral_map (κ.measurable_coe hs) (by fun_prop)] - simp only [Kernel.prodMkRight_apply] - congr - -lemma Measure.snd_prodAssoc_compProd_prodMkLeft {α β γ : Type*} - {mα : MeasurableSpace α} {mβ : MeasurableSpace β} {mγ : MeasurableSpace γ} - {μ : Measure (α × β)} [SFinite μ] {κ : Kernel β γ} [IsSFiniteKernel κ] : - (((μ ⊗ₘ (κ.prodMkLeft α))).map MeasurableEquiv.prodAssoc).snd = μ.snd ⊗ₘ κ := by - ext s hs - rw [Measure.snd_apply hs, Measure.map_apply (by fun_prop) (hs.preimage (by fun_prop)), - Measure.compProd_apply, Measure.compProd_apply hs, Measure.snd, lintegral_map _ (by fun_prop)] - · simp only [Kernel.prodMkLeft_apply] - congr - · exact Kernel.measurable_kernel_prodMk_left hs - · exact hs.preimage (by fun_prop) - -lemma Measure.map_swap_comprod_eq_fst_compProd {α β γ : Type*} - {mα : MeasurableSpace α} {mβ : MeasurableSpace β} {mγ : MeasurableSpace γ} - {μ : Measure (α × β)} [SFinite μ] {κ : Kernel α γ} [IsSFiniteKernel κ] : - (((((μ ⊗ₘ (κ.prodMkRight β))).map Prod.swap).map MeasurableEquiv.prodAssoc.symm).fst).map - Prod.swap - = μ.fst ⊗ₘ κ := by - rw [Measure.map_map (by fun_prop) (by fun_prop), Measure.fst, - Measure.map_map (by fun_prop) (by fun_prop), Measure.map_map (by fun_prop) (by fun_prop)] - ext s hs - rw [Measure.map_apply (by fun_prop) hs, Measure.compProd_apply hs, - Measure.compProd_apply (hs.preimage (by fun_prop)), Measure.fst, lintegral_map _ (by fun_prop)] - · congr - · exact Kernel.measurable_kernel_prodMk_left hs - -lemma ProbabilityMeasure.ext_iff_coe {α : Type*} {mα : MeasurableSpace α} - {μ ν : ProbabilityMeasure α} : - μ = ν ↔ (μ : Measure α) = ν := Subtype.ext_iff - -lemma FiniteMeasure.ext_iff_coe {α : Type*} {mα : MeasurableSpace α} {μ ν : FiniteMeasure α} : - μ = ν ↔ (μ : Measure α) = ν := Subtype.ext_iff - -instance : PartialOrder (FiniteMeasure α) := - PartialOrder.lift _ FiniteMeasure.toMeasure_injective - -lemma FiniteMeasure.le_iff_coe {μ ν : FiniteMeasure α} : - μ ≤ ν ↔ (μ : Measure α) ≤ (ν : Measure α) := Iff.rfl - -noncomputable -instance : Sub (FiniteMeasure α) := - ⟨fun μ ν ↦ ⟨μ.toMeasure - ν.toMeasure, inferInstance⟩⟩ - -lemma FiniteMeasure.sub_def (μ ν : FiniteMeasure α) : - μ - ν = ⟨μ.toMeasure - ν.toMeasure, inferInstance⟩ := - rfl - -@[simp, norm_cast] -lemma FiniteMeasure.toMeasure_sub (μ ν : FiniteMeasure α) : ↑(μ - ν) = (↑μ - ↑ν : Measure α) := - rfl - -instance : CanonicallyOrderedAdd (FiniteMeasure α) where - le_add_self μ ν := fun s ↦ by simp - exists_add_of_le {μ ν} hμν := by - refine ⟨ν - μ, ?_⟩ - rw [FiniteMeasure.ext_iff_coe] - simp only [FiniteMeasure.toMeasure_add, FiniteMeasure.toMeasure_sub] - rw [add_comm, Measure.sub_add_cancel_of_le hμν] - le_self_add μ ν := by - simp only [FiniteMeasure.le_iff_coe, FiniteMeasure.toMeasure_add] - exact Measure.le_add_right le_rfl - -instance : OrderedSub (FiniteMeasure α) where - tsub_le_iff_right μ ν ξ := by - simp only [FiniteMeasure.le_iff_coe, FiniteMeasure.toMeasure_sub, FiniteMeasure.toMeasure_add] - exact Measure.sub_le_iff_le_add - -lemma Kernel.prodMkLeft_ae_eq_iff [MeasurableSpace.CountableOrCountablyGenerated α β] - {κ η : Kernel α β} [IsFiniteKernel κ] [IsFiniteKernel η] - {μ : Measure (γ × α)} : - κ.prodMkLeft γ =ᵐ[μ] η.prodMkLeft γ ↔ κ =ᵐ[μ.snd] η := by - rw [Measure.snd, Filter.EventuallyEq, Filter.EventuallyEq, ae_map_iff (by fun_prop)] - · simp - · classical - exact Kernel.measurableSet_eq κ η - -lemma Kernel.prodMkRight_ae_eq_iff [MeasurableSpace.CountableOrCountablyGenerated α β] - {κ η : Kernel α β} [IsFiniteKernel κ] [IsFiniteKernel η] - {μ : Measure (α × γ)} : - κ.prodMkRight γ =ᵐ[μ] η.prodMkRight γ ↔ κ =ᵐ[μ.fst] η := by - rw [Measure.fst, Filter.EventuallyEq, Filter.EventuallyEq, ae_map_iff (by fun_prop)] - · simp - · classical - exact Kernel.measurableSet_eq κ η - -omit [StandardBorelSpace Ω'] [Nonempty Ω'] in -lemma condIndepFun_of_exists_condDistrib_prod_ae_eq_prodMkRight - [StandardBorelSpace α] [StandardBorelSpace β] [Nonempty β] - (hX : Measurable X) (hY : Measurable Y) (hZ : Measurable Z) {η : Kernel Ω' Ω} - [IsMarkovKernel η] - (h : condDistrib Y (fun ω ↦ (Z ω, X ω)) μ =ᵐ[μ.map (fun ω ↦ (Z ω, X ω))] η.prodMkRight _) : - Y ⟂ᵢ[Z, hZ; μ] X := by - have hη_eq : condDistrib Y Z μ =ᵐ[μ.map Z] η := by - rw [condDistrib_ae_eq_iff_measure_eq_compProd (by fun_prop) (by fun_prop)] at h ⊢ - have h_fst : μ.map Z = (μ.map (fun ω ↦ (Z ω, X ω))).fst := by - rw [Measure.fst_map_prodMk hZ hX] - rw [h_fst, ← Measure.map_swap_comprod_eq_fst_compProd, ← h, - Measure.map_map (by fun_prop) (by fun_prop), Measure.map_map (by fun_prop) (by fun_prop), - Measure.fst, - Measure.map_map (by fun_prop) (by fun_prop), Measure.map_map (by fun_prop) (by fun_prop)] - congr - symm - rw [condIndepFun_iff_condDistrib_prod_ae_eq_prodMkRight hY hX hZ] - refine h.trans ?_ - rw [Kernel.prodMkRight_ae_eq_iff, Measure.fst_map_prodMk (by fun_prop) (by fun_prop)] - exact hη_eq.symm - -omit [StandardBorelSpace Ω'] [Nonempty Ω'] in -lemma condIndepFun_of_exists_condDistrib_prod_ae_eq_prodMkLeft - [StandardBorelSpace α] [StandardBorelSpace β] [Nonempty β] - (hX : Measurable X) (hY : Measurable Y) (hZ : Measurable Z) {η : Kernel Ω' Ω} - [IsMarkovKernel η] - (h : condDistrib Y (fun ω ↦ (X ω, Z ω)) μ =ᵐ[μ.map (fun ω ↦ (X ω, Z ω))] η.prodMkLeft _) : - Y ⟂ᵢ[Z, hZ; μ] X := by - refine condIndepFun_of_exists_condDistrib_prod_ae_eq_prodMkRight hX hY hZ ?_ (η := η) - rw [← Kernel.compProd_eq_iff, compProd_map_condDistrib (by fun_prop) (by fun_prop)] at h ⊢ - have : μ.map (fun a ↦ ((Z a, X a), Y a)) - = (μ.map (fun a ↦ ((X a, Z a), Y a))).map (fun p ↦ ((p.1.2, p.1.1), p.2)) := by - rw [Measure.map_map (by fun_prop) (by fun_prop)] - rfl - rw [this, h] - ext s hs - rw [Measure.map_apply, Measure.compProd_apply, Measure.compProd_apply, lintegral_map, - lintegral_map] - · simp only [Kernel.prodMkLeft_apply, Kernel.prodMkRight_apply] - congr - · exact Kernel.measurable_kernel_prodMk_left hs - · fun_prop - · refine Kernel.measurable_kernel_prodMk_left ?_ - exact hs.preimage (by fun_prop) - · fun_prop - · exact hs - · exact hs.preimage (by fun_prop) - · fun_prop - · exact hs - -/-- Law of `Y` conditioned on `X`. -/ -notation "𝓛[" Y " | " X "; " μ "]" => condDistrib Y X μ - --- generalize to map instead of fst -omit [StandardBorelSpace Ω'] [Nonempty Ω'] in -lemma condIndepFun_fst_prod [StandardBorelSpace α] [StandardBorelSpace β] [Nonempty β] - [StandardBorelSpace γ] - (hX : Measurable X) (hY : Measurable Y) (hZ : Measurable Z) - (ν : Measure γ) [IsProbabilityMeasure ν] - (h_indep : CondIndepFun (mΩ'.comap Z) hZ.comap_le Y X μ) : - CondIndepFun (mΩ'.comap (fun ω ↦ Z ω.1)) (hZ.comp measurable_fst).comap_le - (fun ω ↦ Y ω.1) (fun ω ↦ X ω.1) (μ.prod ν) := by - rw [condIndepFun_iff_map_prod_eq_prod_condDistrib_prod_condDistrib (by fun_prop) - (by fun_prop) (by fun_prop)] at h_indep ⊢ - have h1 : 𝓛[fun ω ↦ Y ω.1 | fun ω ↦ Z ω.1; μ.prod ν] =ᵐ[μ.map Z] 𝓛[Y | Z; μ] := - condDistrib_fst_prod (Y := Y) (X := Z) (ν := ν) (μ := μ) (by fun_prop) (by fun_prop) - have h2 : 𝓛[fun ω ↦ X ω.1 | fun ω ↦ Z ω.1; μ.prod ν] =ᵐ[μ.map Z] 𝓛[X | Z; μ] := - condDistrib_fst_prod (Y := X) (X := Z) (ν := ν) (μ := μ) (by fun_prop) (by fun_prop) - have h_fst1 : (μ.prod ν).map (fun ω ↦ Z ω.1) = μ.map Z := by - conv_rhs => rw [← Measure.fst_prod (μ := μ) (ν := ν), Measure.fst, - Measure.map_map (by fun_prop) (by fun_prop)] - rfl - have h_fst2 : (μ.prod ν).map (fun ω ↦ (Z ω.1, Y ω.1, X ω.1)) - = μ.map (fun ω ↦ (Z ω, Y ω, X ω)) := by - conv_rhs => rw [← Measure.fst_prod (μ := μ) (ν := ν), Measure.fst, - Measure.map_map (by fun_prop) (by fun_prop)] - rfl - rw [h_fst1, h_fst2, h_indep] - refine Measure.bind_congr_right ?_ - filter_upwards [h1, h2] with x hx1 hx2 - simp_rw [Kernel.prod_apply] - rw [hx1, ← hx2] - -omit [StandardBorelSpace Ω] [Nonempty Ω] in -lemma indepFun_fst_prod (hX : AEMeasurable X μ) (hY : AEMeasurable Y μ) (h_indep : IndepFun X Y μ) - (ν : Measure γ) [IsProbabilityMeasure ν] : - IndepFun (fun ω ↦ X ω.1) (fun ω ↦ Y ω.1) (μ.prod ν) := by - rw [indepFun_iff_map_prod_eq_prod_map_map (by fun_prop) (by fun_prop)] at h_indep ⊢ - have : AEMeasurable (fun ω ↦ (X ω, Y ω)) (Measure.map Prod.fst (μ.prod ν)) := by - simp only [Measure.map_fst_prod, measure_univ, one_smul] - fun_prop - have : AEMeasurable X (Measure.map Prod.fst (μ.prod ν)) := by - simp only [Measure.map_fst_prod, measure_univ, one_smul] - fun_prop - have : AEMeasurable Y (Measure.map Prod.fst (μ.prod ν)) := by - simp only [Measure.map_fst_prod, measure_univ, one_smul] - fun_prop - have h : (μ.prod ν).map (fun ω ↦ (X ω.1, Y ω.1)) = μ.map (fun ω ↦ (X ω, Y ω)) := by - conv_rhs => rw [← Measure.fst_prod (μ := μ) (ν := ν), Measure.fst, - AEMeasurable.map_map_of_aemeasurable (by fun_prop) (by fun_prop)] - rfl - rw [h, h_indep] - conv_lhs => rw [← Measure.fst_prod (μ := μ) (ν := ν), Measure.fst, - AEMeasurable.map_map_of_aemeasurable (by fun_prop) (by fun_prop), - AEMeasurable.map_map_of_aemeasurable (by fun_prop) (by fun_prop)] - rfl - -omit [StandardBorelSpace Ω] [Nonempty Ω] in -lemma indepFun_snd_prod (hX : AEMeasurable X μ) (hY : AEMeasurable Y μ) (h_indep : IndepFun X Y μ) - (ν : Measure γ) [IsProbabilityMeasure ν] : - IndepFun (fun ω ↦ X ω.2) (fun ω ↦ Y ω.2) (ν.prod μ) := by - rw [indepFun_iff_map_prod_eq_prod_map_map (by fun_prop) (by fun_prop)] at h_indep ⊢ - have : AEMeasurable (fun ω ↦ (X ω, Y ω)) (Measure.map Prod.snd (ν.prod μ)) := by - simp only [Measure.map_snd_prod, measure_univ, one_smul] - fun_prop - have : AEMeasurable X (Measure.map Prod.snd (ν.prod μ)) := by - simp only [Measure.map_snd_prod, measure_univ, one_smul] - fun_prop - have : AEMeasurable Y (Measure.map Prod.snd (ν.prod μ)) := by - simp only [Measure.map_snd_prod, measure_univ, one_smul] - fun_prop - have h : (ν.prod μ).map (fun ω ↦ (X ω.2, Y ω.2)) = μ.map (fun ω ↦ (X ω, Y ω)) := by - conv_rhs => rw [← Measure.snd_prod (μ := ν) (ν := μ), Measure.snd, - AEMeasurable.map_map_of_aemeasurable (by fun_prop) (by fun_prop)] - rfl - rw [h, h_indep] - conv_lhs => rw [← Measure.snd_prod (μ := ν) (ν := μ), Measure.snd, - AEMeasurable.map_map_of_aemeasurable (by fun_prop) (by fun_prop), - AEMeasurable.map_map_of_aemeasurable (by fun_prop) (by fun_prop)] - rfl - --- cf. measurableSet_graph (Mathlib/MeasureTheory/Measure/Lebesgue/Basic.lean) -lemma measurableSet_graph' {β Ω : Type*} {_ : MeasurableSpace β} {_ : MeasurableSpace Ω} - [MeasurableEq Ω] {f : β → Ω} (hf : Measurable f) : - MeasurableSet {p : β × Ω | p.2 = f p.1} := - measurableSet_eq_fun (by fun_prop) (by fun_prop) - -omit [IsFiniteMeasure μ] in -lemma ae_eq_of_map_prodMk_eq {β Ω : Type*} {_ : MeasurableSpace β} {_ : MeasurableSpace Ω} - [MeasurableEq Ω] {X : α → β} {Y : α → Ω} {f : β → Ω} (hf : Measurable f) (hX : AEMeasurable X μ) - (hY : AEMeasurable Y μ) (h : μ.map (fun ω ↦ (X ω, Y ω)) = μ.map (fun ω ↦ (X ω, f (X ω)))) : - Y =ᵐ[μ] f ∘ X := by - have hp : ∀ᵐ p ∂μ.map (fun ω ↦ (X ω, f (X ω))), p.2 = f p.1 := - (ae_map_iff (by fun_prop) (measurableSet_graph' hf)).2 (by simp) - exact ae_of_ae_map (by fun_prop) (h ▸ hp) - -lemma ae_eq_of_condDistrib_eq_deterministic {f : β → Ω} (hf : Measurable f) (hX : AEMeasurable X μ) - (hY : AEMeasurable Y μ) (h : condDistrib Y X μ =ᵐ[μ.map X] Kernel.deterministic f hf) : - Y =ᵐ[μ] f ∘ X := by - have hfX := condDistrib_comp_self hX hf - rw [condDistrib_ae_eq_iff_measure_eq_compProd hX (by fun_prop)] at h hfX - exact ae_eq_of_map_prodMk_eq hf hX hY (hfX ▸ h) - -end CondDistrib - -section Cond - -lemma condDistrib_ae_eq_cond [Countable β] [MeasurableSingletonClass β] - [IsFiniteMeasure μ] - (hX : Measurable X) (hY : Measurable Y) : - condDistrib Y X μ =ᵐ[μ.map X] fun b ↦ (μ[|X ⁻¹' {b}]).map Y := by - rw [Filter.EventuallyEq, ae_iff_of_countable] - intro b hb - ext s hs - rw [condDistrib_apply_of_ne_zero hX hY, - Measure.map_apply hX (measurableSet_singleton _), Measure.map_apply hY hs, - Measure.map_apply (hX.prodMk hY) ((measurableSet_singleton _).prod hs), - cond_apply (hX (measurableSet_singleton _))] - · congr - · exact hb - -lemma lintegral_cond {μ : Measure α} (s : Set α) (f : α → ℝ≥0∞) : - ∫⁻ x, f x ∂μ[|s] = (μ s)⁻¹ * ∫⁻ (a : α) in s, f a ∂μ := by - unfold cond - simp [lintegral_smul_measure] - -omit [Nonempty Ω'] in -lemma condDistrib_prod_of_forall_condDistrib_cond [Countable Ω'] [IsFiniteMeasure μ] - (hX : Measurable X) (hY : Measurable Y) (hZ : Measurable Z) - (κ : Kernel (β × Ω') Ω) [IsFiniteKernel κ] - (h_cond : ∀ b, μ (Z ⁻¹' {b}) ≠ 0 → condDistrib Y X μ[|Z ⁻¹' {b}] =ᵐ[μ[|Z ⁻¹' {b}].map X] - (κ.comap (fun ω ↦ (ω, b)) (by fun_prop) : Kernel β Ω)) : - condDistrib Y (fun ω ↦ (X ω, Z ω)) μ =ᵐ[μ.map (fun ω ↦ (X ω, Z ω))] κ := by - refine condDistrib_ae_eq_of_measure_eq_compProd (by fun_prop) (by fun_prop) ?_ - ext s hs - suffices ∀ b, (Measure.map (fun x ↦ ((X x, Z x), Y x)) μ) (s ∩ {p | p.1.2 = b}) = - (Measure.map (fun ω ↦ (X ω, Z ω)) μ ⊗ₘ κ) (s ∩ {p | p.1.2 = b}) by - have hs_iUnion : s = ⋃ b, s ∩ {p | p.1.2 = b} := by - ext p - simp only [Set.mem_iUnion, Set.mem_inter_iff, Set.mem_ofPred_eq] - grind - have h_disj : Pairwise (Function.onFun Disjoint fun b ↦ s ∩ {p | p.1.2 = b}) := by - intro i j hij - simp only [Set.disjoint_iff_inter_eq_empty] - ext - grind - have h_meas (b : Ω') : MeasurableSet (s ∩ {p | p.1.2 = b}) := - hs.inter ((measurableSet_singleton _).preimage (by fun_prop)) - rw [hs_iUnion, measure_iUnion h_disj h_meas, measure_iUnion h_disj h_meas] - congr with b - exact this b - intro b - by_cases hb : μ (Z ⁻¹' {b}) = 0 - · have h_left : (Measure.map (fun x ↦ ((X x, Z x), Y x)) μ) (s ∩ {p | p.1.2 = b}) = 0 := by - suffices (Measure.map (fun x ↦ ((X x, Z x), Y x)) μ) {p | p.1.2 = b} = 0 from - measure_mono_null Set.inter_subset_right this - rw [Measure.map_apply (by fun_prop)] - · simpa - · exact (measurableSet_singleton _).preimage (by fun_prop) - have h_right : (Measure.map (fun ω ↦ (X ω, Z ω)) μ ⊗ₘ κ) (s ∩ {p | p.1.2 = b}) = 0 := by - suffices (Measure.map (fun ω ↦ (X ω, Z ω)) μ ⊗ₘ κ) {p | p.1.2 = b} = 0 from - measure_mono_null Set.inter_subset_right this - rw [Measure.compProd_apply, lintegral_map] - rotate_left - · exact Kernel.measurable_kernel_prodMk_left - ((measurableSet_singleton _).preimage (by fun_prop)) - · fun_prop - · exact (measurableSet_singleton _).preimage (by fun_prop) - simp only [Set.preimage_ofPred_eq] - classical - have h_le : ∫⁻ a, (κ (X a, Z a)) {a_1 | Z a = b} ∂μ ≤ - ∫⁻ a, {a' | Z a' = b}.indicator (fun _ ↦ κ.bound) a ∂μ := by - gcongr with a - by_cases hZ : Z a = b - · simp only [hZ, Set.ofPred_true, Set.mem_ofPred_eq, Set.indicator_of_mem] - exact κ.measure_le_bound _ _ - · simp [hZ] - refine le_antisymm (h_le.trans ?_) zero_le - rw [lintegral_indicator] - swap; · exact (measurableSet_singleton _).preimage (by fun_prop) - simp only [lintegral_const, MeasurableSet.univ, Measure.restrict_apply, Set.univ_inter, - nonpos_iff_eq_zero, mul_eq_zero] - exact .inr hb - rw [h_left, h_right] - specialize h_cond b hb - rw [condDistrib_ae_eq_iff_measure_eq_compProd (by fun_prop) (by fun_prop)] at h_cond - rw [Measure.ext_iff] at h_cond - have hs' : MeasurableSet {p : β × Ω | ((p.1, b), p.2) ∈ s} := hs.preimage (by fun_prop) - have h1 := h_cond {p | ((p.1, b), p.2) ∈ s} hs' - have h_indicator : Measurable ({ω' | Z ω' = b}.indicator (fun x ↦ 1)) := - Measurable.indicator (by fun_prop) ((measurableSet_singleton _).preimage (by fun_prop)) - rw [Measure.map_apply] at h1 ⊢ - rotate_left - · fun_prop - · exact hs.inter ((measurableSet_singleton _).preimage (by fun_prop)) - · fun_prop - · exact hs' - rw [cond_apply] at h1 - swap; · exact (measurableSet_singleton _).preimage (by fun_prop) - have h1' : μ (Z ⁻¹' {b} ∩ (fun x ↦ (X x, Y x)) ⁻¹' {p | ((p.1, b), p.2) ∈ s}) = - (μ (Z ⁻¹' {b})) * - (Measure.map X μ[|Z ⁻¹' {b}] ⊗ₘ κ.comap (fun ω ↦ (ω, b)) (by fun_prop)) - {p | ((p.1, b), p.2) ∈ s} := by - rw [← h1, ← mul_assoc, ENNReal.mul_inv_cancel hb (by simp), one_mul] - convert h1' - · ext x - simp only [Set.preimage_inter, Set.preimage_ofPred_eq, Set.mem_inter_iff, Set.mem_preimage, - Set.mem_ofPred_eq] - grind - · rw [Measure.compProd_apply, Measure.compProd_apply, lintegral_map, lintegral_map] - rotate_left - · exact Kernel.measurable_kernel_prodMk_left hs' - · fun_prop - · apply Kernel.measurable_kernel_prodMk_left - exact hs.inter ((measurableSet_singleton _).preimage (by fun_prop)) - · fun_prop - · exact hs' - · exact hs.inter ((measurableSet_singleton _).preimage (by fun_prop)) - rw [lintegral_cond, ← mul_assoc, ENNReal.mul_inv_cancel hb (by simp), one_mul] - simp only [Set.preimage_inter, Set.preimage_ofPred_eq, Kernel.coe_comap, Function.comp_apply] - classical - have h_eq : (fun a ↦ κ (X a, Z a) (Prod.mk (X a, Z a) ⁻¹' s ∩ {a_1 | Z a = b})) = - {a | Z a = b}.indicator - (fun a ↦ κ (X a, b) (Prod.mk (X a, b) ⁻¹' s ∩ {a_1 | Z a = b})) := by - ext a - by_cases hZ : Z a = b <;> simp [hZ] - simp_rw [h_eq] - rw [lintegral_indicator] - swap; · exact (measurableSet_singleton _).preimage (by fun_prop) - refine setLIntegral_congr_fun ((measurableSet_singleton _).preimage (by fun_prop)) fun a ha ↦ ?_ - congr 1 with ω - simp only [Set.mem_inter_iff, Set.mem_preimage, Set.mem_ofPred_eq, and_iff_left_iff_imp] - grind - -lemma cond_of_indepFun [IsZeroOrProbabilityMeasure μ] (h : IndepFun X T μ) - (hX : Measurable X) (hT : Measurable T) {s : Set β} (hs : MeasurableSet s) - (hμs : μ (X ⁻¹' s) ≠ 0) : - (μ[|X ⁻¹' s]).map T = μ.map T := by - ext t ht - rw [Measure.map_apply (by fun_prop) ht, Measure.map_apply (by fun_prop) ht, cond_apply (hX hs), - IndepSet.measure_inter_eq_mul, ← mul_assoc, ENNReal.inv_mul_cancel, one_mul] - · exact hμs - · simp - · rw [indepFun_iff_indepSet_preimage hX hT] at h - exact h s t hs ht - -omit [Nonempty Ω'] in -lemma cond_of_condIndepFun [StandardBorelSpace α] [StandardBorelSpace β] [Nonempty β] [Countable β] - [Countable Ω'] - [IsZeroOrProbabilityMeasure μ] - (hZ : Measurable Z) - (h : CondIndepFun (MeasurableSpace.comap Z inferInstance) hZ.comap_le Y X μ) - (hX : Measurable X) (hY : Measurable Y) {b : β} {ω : Ω'} - (hμ : μ (Z ⁻¹' {ω} ∩ X ⁻¹' {b}) ≠ 0) : - (μ[|Z ⁻¹' {ω} ∩ X ⁻¹' {b}]).map Y = (μ[|Z ⁻¹' {ω}]).map Y := by - symm at h - have h := (condIndepFun_iff_condDistrib_prod_ae_eq_prodMkRight hY hX hZ).mp h - have h_left := condDistrib_ae_eq_cond (hZ.prodMk hX) hY (μ := μ) - have h_right := condDistrib_ae_eq_cond hZ hY (μ := μ) - rw [Filter.EventuallyEq, ae_iff_of_countable] at h h_left h_right - specialize h (ω, b) - specialize h_left (ω, b) - specialize h_right ω - rw [Measure.map_apply (by fun_prop) (measurableSet_singleton _)] at h h_left h_right - rw [← Set.singleton_prod_singleton, Set.mk_preimage_prod] at h h_left - have hZ_ne : μ (Z ⁻¹' {ω}) ≠ 0 := fun h ↦ hμ (measure_mono_null Set.inter_subset_left h) - rw [← h_right hZ_ne, ← h_left hμ, h hμ] - simp - -end Cond - -end ProbabilityTheory diff --git a/LeanMachineLearning/ForMathlib/Probability/Independence/CondIndepFun.lean b/LeanMachineLearning/ForMathlib/Probability/Independence/CondIndepFun.lean deleted file mode 100644 index 420483c0..00000000 --- a/LeanMachineLearning/ForMathlib/Probability/Independence/CondIndepFun.lean +++ /dev/null @@ -1,103 +0,0 @@ -/- -Copyright (c) 2026 Rémy Degenne. All rights reserved. -Released under Apache 2.0 license as described in the file LICENSE. -Authors: Rémy Degenne --/ -module - -public import Mathlib.MeasureTheory.Function.FactorsThrough -public import Mathlib.Probability.Independence.Basic -public import Mathlib.Probability.Independence.Conditional - -/-! # Laws of `stepsUntil` and `rewardByCount` --/ - -@[expose] public section - -open MeasureTheory ProbabilityTheory Finset -open scoped ENNReal NNReal - -namespace ProbabilityTheory - -variable {α β γ δ γ' δ' : Type*} - {mα : MeasurableSpace α} {mβ : MeasurableSpace β} {mγ : MeasurableSpace γ} - {mδ : MeasurableSpace δ} {mγ' : MeasurableSpace γ'} {mδ' : MeasurableSpace δ'} - [StandardBorelSpace δ'] [Nonempty δ'] [StandardBorelSpace γ'] [Nonempty γ'] - {μ : Measure α} - {X : α → β} {hX : Measurable X} {Y : α → γ} {Z : α → δ} {Y' : α → γ'} {Z' : α → δ'} - -lemma Kernel.IndepFun.of_prod_right {ε Ω : Type*} {mΩ : MeasurableSpace Ω} {mε : MeasurableSpace ε} - {μ : Measure Ω} {κ : Kernel Ω α} {X : α → β} {Y : α → γ} {T : α → ε} - (h : IndepFun X (fun ω ↦ (Y ω, T ω)) κ μ) : - IndepFun X Y κ μ := by - rw [Kernel.indepFun_iff_measure_inter_preimage_eq_mul] at h ⊢ - intro s t hs ht - specialize h s (t ×ˢ .univ) hs (ht.prod .univ) - simpa [Set.mk_preimage_prod] using h - -lemma Kernel.IndepFun.of_prod_left {ε Ω : Type*} {mΩ : MeasurableSpace Ω} {mε : MeasurableSpace ε} - {μ : Measure Ω} {κ : Kernel Ω α} {X : α → β} {Y : α → γ} {T : α → ε} - (h : IndepFun (fun ω ↦ (X ω, T ω)) Y κ μ) : - IndepFun X Y κ μ := h.symm.of_prod_right.symm - -lemma CondIndepFun.of_prod_right {ε : Type*} {mε : MeasurableSpace ε} - [StandardBorelSpace α] [IsFiniteMeasure μ] - {X : α → β} {Y : α → γ} {Z : α → δ} {T : α → ε} (hZ : Measurable Z) - (h : X ⟂ᵢ[Z, hZ; μ] (fun ω ↦ (Y ω, T ω))) : - X ⟂ᵢ[Z, hZ; μ] Y := - Kernel.IndepFun.of_prod_right h - -lemma CondIndepFun.of_prod_left {ε : Type*} {mε : MeasurableSpace ε} - [StandardBorelSpace α] [IsFiniteMeasure μ] - {X : α → β} {Y : α → γ} {Z : α → δ} {T : α → ε} (hZ : Measurable Z) - (h : (fun ω ↦ (X ω, T ω)) ⟂ᵢ[Z, hZ; μ] Y) : - X ⟂ᵢ[Z, hZ; μ] Y := - Kernel.IndepFun.of_prod_left h - -lemma IndepFun.of_measurable (h_indep : Y ⟂ᵢ[μ] Z) - (hY_meas : Measurable[mγ.comap Y] Y') (hZ_meas : Measurable[mδ.comap Z] Z') : - Y' ⟂ᵢ[μ] Z' := by - obtain ⟨φ, hφ_meas, h_eqY⟩ : ∃ φ, Measurable φ ∧ Y' = φ ∘ Y := hY_meas.exists_eq_measurable_comp - obtain ⟨ψ, hψ_meas, h_eqZ⟩ : ∃ ψ, Measurable ψ ∧ Z' = ψ ∘ Z := hZ_meas.exists_eq_measurable_comp - rw [h_eqY, h_eqZ] - exact h_indep.comp hφ_meas hψ_meas - -lemma IndepFun.of_measurable_left - (h_indep : Y ⟂ᵢ[μ] Z) (hY_meas : Measurable[mγ.comap Y] Y') : - Y' ⟂ᵢ[μ] Z := by - obtain ⟨φ, hφ_meas, h_eqY⟩ : ∃ φ, Measurable φ ∧ Y' = φ ∘ Y := hY_meas.exists_eq_measurable_comp - rw [h_eqY] - exact h_indep.comp hφ_meas measurable_id - -lemma IndepFun.of_measurable_right - (h_indep : Y ⟂ᵢ[μ] Z) (hZ_meas : Measurable[mδ.comap Z] Z') : - Y ⟂ᵢ[μ] Z' := by - obtain ⟨ψ, hψ_meas, h_eqZ⟩ : ∃ ψ, Measurable ψ ∧ Z' = ψ ∘ Z := hZ_meas.exists_eq_measurable_comp - rw [h_eqZ] - exact h_indep.comp measurable_id hψ_meas - -variable [StandardBorelSpace α] [IsFiniteMeasure μ] - -lemma CondIndepFun.of_measurable (h_indep : Y ⟂ᵢ[X, hX; μ] Z) - (hY_meas : Measurable[mγ.comap Y] Y') (hZ_meas : Measurable[mδ.comap Z] Z') : - Y' ⟂ᵢ[X, hX; μ] Z' := by - obtain ⟨φ, hφ_meas, h_eqY⟩ : ∃ φ, Measurable φ ∧ Y' = φ ∘ Y := hY_meas.exists_eq_measurable_comp - obtain ⟨ψ, hψ_meas, h_eqZ⟩ : ∃ ψ, Measurable ψ ∧ Z' = ψ ∘ Z := hZ_meas.exists_eq_measurable_comp - rw [h_eqY, h_eqZ] - exact h_indep.comp hφ_meas hψ_meas - -lemma CondIndepFun.of_measurable_left - (h_indep : Y ⟂ᵢ[X, hX; μ] Z) (hY_meas : Measurable[mγ.comap Y] Y') : - Y' ⟂ᵢ[X, hX; μ] Z := by - obtain ⟨φ, hφ_meas, h_eqY⟩ : ∃ φ, Measurable φ ∧ Y' = φ ∘ Y := hY_meas.exists_eq_measurable_comp - rw [h_eqY] - exact h_indep.comp hφ_meas measurable_id - -lemma CondIndepFun.of_measurable_right - (h_indep : Y ⟂ᵢ[X, hX; μ] Z) (hZ_meas : Measurable[mδ.comap Z] Z') : - Y ⟂ᵢ[X, hX; μ] Z' := by - obtain ⟨ψ, hψ_meas, h_eqZ⟩ : ∃ ψ, Measurable ψ ∧ Z' = ψ ∘ Z := hZ_meas.exists_eq_measurable_comp - rw [h_eqZ] - exact h_indep.comp measurable_id hψ_meas - -end ProbabilityTheory diff --git a/LeanMachineLearning/ForMathlib/Probability/Independence/Conditional.lean b/LeanMachineLearning/ForMathlib/Probability/Independence/Conditional.lean new file mode 100644 index 00000000..8173c1e4 --- /dev/null +++ b/LeanMachineLearning/ForMathlib/Probability/Independence/Conditional.lean @@ -0,0 +1,267 @@ +/- +Copyright (c) 2025 Rémy Degenne. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Rémy Degenne +-/ +module + +public import LeanMachineLearning.ForMathlib.Probability.Independence.Kernel.IndepFun +public import LeanMachineLearning.ForMathlib.Probability.Kernel.CondDistrib +public import LeanMachineLearning.ForMathlib.Probability.Kernel.Composition.MeasureCompProd +public import LeanMachineLearning.ForMathlib.Probability.Kernel.RadonNikodym +public import Mathlib.Probability.Independence.Basic +public import Mathlib.Probability.Independence.Conditional + +import Mathlib.Probability.Kernel.CompProdEqIff + +/-! +# Lemmas about conditional independence + +This file contains lemmas about conditional independence of random variables and about the +relation between (conditional) independence and conditional distributions. + +## Main statements + +* `CondIndepFun.of_measurable`: if `Y` and `Z` are conditionally independent, then so are any + `Y'` measurable with respect to `σ(Y)` and any `Z'` measurable with respect to `σ(Z)`. +* `indepFun_iff_condDistrib_ae_eq_const`: `X` and `Y` are independent iff the conditional + distribution of `Y` given `X` is a.e. constant. +* `condIndepFun_of_exists_condDistrib_prod_ae_eq_prodMkRight`: `Y` is conditionally independent of + `X` given `Z` if the conditional distribution of `Y` given `(Z, X)` depends only on `Z`. +* `cond_of_condIndepFun`: if `Y` and `X` are conditionally independent given `Z`, then the law of + `Y` conditioned on `Z = ω` and `X = b` is its law conditioned on `Z = ω`. +-/ + +@[expose] public section + +open MeasureTheory ProbabilityTheory Finset +open scoped ENNReal NNReal + +namespace ProbabilityTheory + +section OfMeasurable + +variable {α β γ δ γ' δ' : Type*} + {mα : MeasurableSpace α} {mβ : MeasurableSpace β} {mγ : MeasurableSpace γ} + {mδ : MeasurableSpace δ} {mγ' : MeasurableSpace γ'} {mδ' : MeasurableSpace δ'} + {μ : Measure α} + {X : α → β} {hX : Measurable X} {Y : α → γ} {Z : α → δ} {Y' : α → γ'} {Z' : α → δ'} + +lemma CondIndepFun.of_prod_right {ε : Type*} {mε : MeasurableSpace ε} + [StandardBorelSpace α] [IsFiniteMeasure μ] + {X : α → β} {Y : α → γ} {Z : α → δ} {T : α → ε} (hZ : Measurable Z) + (h : X ⟂ᵢ[Z, hZ; μ] (fun ω ↦ (Y ω, T ω))) : + X ⟂ᵢ[Z, hZ; μ] Y := + Kernel.IndepFun.of_prod_right h + +lemma CondIndepFun.of_prod_left {ε : Type*} {mε : MeasurableSpace ε} + [StandardBorelSpace α] [IsFiniteMeasure μ] + {X : α → β} {Y : α → γ} {Z : α → δ} {T : α → ε} (hZ : Measurable Z) + (h : (fun ω ↦ (X ω, T ω)) ⟂ᵢ[Z, hZ; μ] Y) : + X ⟂ᵢ[Z, hZ; μ] Y := + Kernel.IndepFun.of_prod_left h + +variable [StandardBorelSpace α] [IsFiniteMeasure μ] + +lemma CondIndepFun.of_measurable_left + (h_indep : Y ⟂ᵢ[X, hX; μ] Z) (hY_meas : Measurable[mγ.comap Y] Y') : + Y' ⟂ᵢ[X, hX; μ] Z := by + rw [condIndepFun_iff_condIndep] at h_indep ⊢ + exact condIndep_of_condIndep_of_le_left h_indep hY_meas.comap_le + +lemma CondIndepFun.of_measurable_right + (h_indep : Y ⟂ᵢ[X, hX; μ] Z) (hZ_meas : Measurable[mδ.comap Z] Z') : + Y ⟂ᵢ[X, hX; μ] Z' := by + rw [condIndepFun_iff_condIndep] at h_indep ⊢ + exact condIndep_of_condIndep_of_le_right h_indep hZ_meas.comap_le + +lemma CondIndepFun.of_measurable (h_indep : Y ⟂ᵢ[X, hX; μ] Z) + (hY_meas : Measurable[mγ.comap Y] Y') (hZ_meas : Measurable[mδ.comap Z] Z') : + Y' ⟂ᵢ[X, hX; μ] Z' := + (h_indep.of_measurable_left (hX := hX) hY_meas).of_measurable_right (hX := hX) hZ_meas + +end OfMeasurable + +section CondDistrib + +variable {α β γ δ Ω Ω' : Type*} + {mα : MeasurableSpace α} {μ : Measure α} {mβ : MeasurableSpace β} {mγ : MeasurableSpace γ} + {mδ : MeasurableSpace δ} + [MeasurableSpace Ω] [StandardBorelSpace Ω] [Nonempty Ω] + [mΩ' : MeasurableSpace Ω'] [StandardBorelSpace Ω'] [Nonempty Ω'] + {X : α → β} {Y : α → Ω} {Z : α → Ω'} {T : α → γ} + +section IsFiniteMeasure + +variable [IsFiniteMeasure μ] + +/-- If `X` is conditionally independent of `Y` given `Z`, then it is conditionally independent of +`(Y, Z)` given `Z`. -/ +lemma CondIndepFun.prod_right [StandardBorelSpace α] [StandardBorelSpace β] [Nonempty β] + [StandardBorelSpace γ] [Nonempty γ] [StandardBorelSpace δ] [Nonempty δ] + {X : α → β} {Y : α → γ} {Z : α → δ} + (hX : Measurable X) (hY : Measurable Y) (hZ : Measurable Z) + (h : X ⟂ᵢ[Z, hZ; μ] Y) : + X ⟂ᵢ[Z, hZ; μ] (fun ω ↦ (Y ω, Z ω)) := by + rw [condIndepFun_iff_condDistrib_prod_ae_eq_prodMkRight hY hX hZ, + condDistrib_ae_eq_iff_measure_eq_compProd (by fun_prop) (by fun_prop)] at h + rw [condIndepFun_iff_condDistrib_prod_ae_eq_prodMkRight (by fun_prop) hX hZ, + condDistrib_ae_eq_iff_measure_eq_compProd (by fun_prop) (by fun_prop)] + -- Key: condDistrib (Y, Z) Z μ z = (condDistrib Y Z μ z).map (y ↦ (y, z)) + have h_cond : condDistrib (fun ω ↦ (Y ω, Z ω)) Z μ =ᵐ[μ.map Z] + fun z ↦ (condDistrib Y Z μ z).map (fun y ↦ (y, z)) := by + suffices condDistrib (fun ω ↦ (Y ω, Z ω)) Z μ =ᵐ[μ.map Z] + (condDistrib Y Z μ) ×ₖ Kernel.id by + refine this.trans (ae_of_all _ fun x ↦ ?_) + simp only + rw [Kernel.prod_apply, Kernel.id_apply] + ext s hs + rw [Measure.map_apply (by fun_prop) hs, Measure.prod_apply_symm hs, lintegral_dirac] + exact condDistrib_prod_self_left hY.aemeasurable hZ.aemeasurable + -- Main calculation + calc μ.map (fun x ↦ ((Z x, X x), (Y x, Z x))) + _ = (μ.map (fun x ↦ ((Z x, X x), Y x))).map (fun p ↦ (p.1, (p.2, p.1.1))) := by + rw [Measure.map_map (by fun_prop) (by fun_prop)]; rfl + _ = (μ.map (fun ω ↦ (Z ω, X ω)) ⊗ₘ (condDistrib Y Z μ).prodMkRight β).map + (fun p ↦ (p.1, (p.2, p.1.1))) := by rw [h] + _ = μ.map (fun ω ↦ (Z ω, X ω)) ⊗ₘ (condDistrib (fun ω ↦ (Y ω, Z ω)) Z μ).prodMkRight β := by + ext s hs + rw [Measure.map_apply (by fun_prop) hs, + Measure.compProd_apply (hs.preimage (by fun_prop)), Measure.compProd_apply hs] + have h_cond' : ∀ᵐ p ∂(μ.map (fun ω ↦ (Z ω, X ω))), + condDistrib (fun ω ↦ (Y ω, Z ω)) Z μ p.1 = + (condDistrib Y Z μ p.1).map (fun y ↦ (y, p.1)) := by + have h_fst : (μ.map (fun ω ↦ (Z ω, X ω))).map Prod.fst = μ.map Z := by + rw [Measure.map_map (by fun_prop) (by fun_prop)]; rfl + rw [← h_fst] at h_cond + exact mem_ae_of_mem_ae_map (by fun_prop) h_cond + refine lintegral_congr_ae (h_cond'.mono fun ⟨z, x⟩ hzx ↦ ?_) + simp only [Kernel.prodMkRight_apply, hzx, + Measure.map_apply (by fun_prop : Measurable fun y ↦ (y, z)) + (hs.preimage (by fun_prop : Measurable (Prod.mk (z, x))))] + congr 1 + +lemma condDistrib_ae_eq_of_indepFun (h : IndepFun X Y μ) (hX : AEMeasurable X μ) + (hY : AEMeasurable Y μ) : + condDistrib Y X μ =ᵐ[μ.map X] Kernel.const β (μ.map Y) := by + refine condDistrib_ae_eq_of_measure_eq_compProd hX hY ?_ + simp only [Measure.compProd_const] + exact (indepFun_iff_map_prod_eq_prod_map_map hX hY).mp h + +lemma indepFun_iff_condDistrib_ae_eq_const (hX : AEMeasurable X μ) (hY : AEMeasurable Y μ) : + IndepFun X Y μ ↔ condDistrib Y X μ =ᵐ[μ.map X] Kernel.const β (μ.map Y) := by + refine ⟨fun h ↦ condDistrib_ae_eq_of_indepFun h hX hY, fun h ↦ ?_⟩ + rw [indepFun_iff_map_prod_eq_prod_map_map hX hY, ← compProd_map_condDistrib hX hY, + Measure.compProd_congr h] + simp + +omit [StandardBorelSpace Ω'] [Nonempty Ω'] in +lemma condIndepFun_of_exists_condDistrib_prod_ae_eq_prodMkRight + [StandardBorelSpace α] [StandardBorelSpace β] [Nonempty β] + (hX : Measurable X) (hY : Measurable Y) (hZ : Measurable Z) {η : Kernel Ω' Ω} + [IsMarkovKernel η] + (h : condDistrib Y (fun ω ↦ (Z ω, X ω)) μ =ᵐ[μ.map (fun ω ↦ (Z ω, X ω))] η.prodMkRight _) : + Y ⟂ᵢ[Z, hZ; μ] X := by + have hη_eq : condDistrib Y Z μ =ᵐ[μ.map Z] η := by + rw [condDistrib_ae_eq_iff_measure_eq_compProd (by fun_prop) (by fun_prop)] at h ⊢ + have h_fst : μ.map Z = (μ.map (fun ω ↦ (Z ω, X ω))).fst := by + rw [Measure.fst_map_prodMk hZ hX] + rw [h_fst, ← Measure.map_prodMap_fst_compProd_prodMkRight, ← h, + Measure.map_map (by fun_prop) (by fun_prop)] + rfl + symm + rw [condIndepFun_iff_condDistrib_prod_ae_eq_prodMkRight hY hX hZ] + refine h.trans ?_ + rw [Kernel.prodMkRight_ae_eq_iff, Measure.fst_map_prodMk (by fun_prop) (by fun_prop)] + exact hη_eq.symm + +omit [StandardBorelSpace Ω'] [Nonempty Ω'] in +lemma condIndepFun_of_exists_condDistrib_prod_ae_eq_prodMkLeft + [StandardBorelSpace α] [StandardBorelSpace β] [Nonempty β] + (hX : Measurable X) (hY : Measurable Y) (hZ : Measurable Z) {η : Kernel Ω' Ω} + [IsMarkovKernel η] + (h : condDistrib Y (fun ω ↦ (X ω, Z ω)) μ =ᵐ[μ.map (fun ω ↦ (X ω, Z ω))] η.prodMkLeft _) : + Y ⟂ᵢ[Z, hZ; μ] X := by + refine condIndepFun_of_exists_condDistrib_prod_ae_eq_prodMkRight hX hY hZ ?_ (η := η) + rw [← Kernel.compProd_eq_iff, compProd_map_condDistrib (by fun_prop) (by fun_prop)] at h ⊢ + have : μ.map (fun a ↦ ((Z a, X a), Y a)) + = (μ.map (fun a ↦ ((X a, Z a), Y a))).map (fun p ↦ ((p.1.2, p.1.1), p.2)) := by + rw [Measure.map_map (by fun_prop) (by fun_prop)] + rfl + rw [this, h] + ext s hs + rw [Measure.map_apply, Measure.compProd_apply, Measure.compProd_apply, lintegral_map, + lintegral_map] + · simp only [Kernel.prodMkLeft_apply, Kernel.prodMkRight_apply] + congr + · exact Kernel.measurable_kernel_prodMk_left hs + · fun_prop + · refine Kernel.measurable_kernel_prodMk_left ?_ + exact hs.preimage (by fun_prop) + · fun_prop + · exact hs + · exact hs.preimage (by fun_prop) + · fun_prop + · exact hs + +omit [StandardBorelSpace Ω'] [Nonempty Ω'] in +/-- If `Y` and `X` are conditionally independent given `Z` under `μ`, then `Y ∘ Prod.fst` and +`X ∘ Prod.fst` are conditionally independent given `Z ∘ Prod.fst` under `μ.prod ν`. + +TODO: generalize to the image of `μ` by any measurable map, instead of `Prod.fst`. -/ +lemma condIndepFun_fst_prod [StandardBorelSpace α] [StandardBorelSpace β] [Nonempty β] + [StandardBorelSpace γ] + (hX : Measurable X) (hY : Measurable Y) (hZ : Measurable Z) + (ν : Measure γ) [IsProbabilityMeasure ν] + (h_indep : CondIndepFun (mΩ'.comap Z) hZ.comap_le Y X μ) : + CondIndepFun (mΩ'.comap (fun ω ↦ Z ω.1)) (hZ.comp measurable_fst).comap_le + (fun ω ↦ Y ω.1) (fun ω ↦ X ω.1) (μ.prod ν) := by + rw [condIndepFun_iff_map_prod_eq_prod_condDistrib_prod_condDistrib (by fun_prop) + (by fun_prop) (by fun_prop)] at h_indep ⊢ + have h1 : 𝓛[fun ω ↦ Y ω.1 | fun ω ↦ Z ω.1; μ.prod ν] =ᵐ[μ.map Z] 𝓛[Y | Z; μ] := + condDistrib_fst_prod (Y := Y) (X := Z) (ν := ν) (μ := μ) (by fun_prop) (by fun_prop) + have h2 : 𝓛[fun ω ↦ X ω.1 | fun ω ↦ Z ω.1; μ.prod ν] =ᵐ[μ.map Z] 𝓛[X | Z; μ] := + condDistrib_fst_prod (Y := X) (X := Z) (ν := ν) (μ := μ) (by fun_prop) (by fun_prop) + have h_fst1 : (μ.prod ν).map (fun ω ↦ Z ω.1) = μ.map Z := by + conv_rhs => rw [← Measure.fst_prod (μ := μ) (ν := ν), Measure.fst, + Measure.map_map (by fun_prop) (by fun_prop)] + rfl + have h_fst2 : (μ.prod ν).map (fun ω ↦ (Z ω.1, Y ω.1, X ω.1)) + = μ.map (fun ω ↦ (Z ω, Y ω, X ω)) := by + conv_rhs => rw [← Measure.fst_prod (μ := μ) (ν := ν), Measure.fst, + Measure.map_map (by fun_prop) (by fun_prop)] + rfl + rw [h_fst1, h_fst2, h_indep] + refine Measure.bind_congr_right ?_ + filter_upwards [h1, h2] with x hx1 hx2 + simp_rw [Kernel.prod_apply] + rw [hx1, ← hx2] + +end IsFiniteMeasure + +omit [Nonempty Ω'] in +lemma cond_of_condIndepFun [StandardBorelSpace α] [StandardBorelSpace β] [Nonempty β] [Countable β] + [Countable Ω'] + [IsZeroOrProbabilityMeasure μ] + (hZ : Measurable Z) + (h : CondIndepFun (MeasurableSpace.comap Z inferInstance) hZ.comap_le Y X μ) + (hX : Measurable X) (hY : Measurable Y) {b : β} {ω : Ω'} + (hμ : μ (Z ⁻¹' {ω} ∩ X ⁻¹' {b}) ≠ 0) : + (μ[|Z ⁻¹' {ω} ∩ X ⁻¹' {b}]).map Y = (μ[|Z ⁻¹' {ω}]).map Y := by + symm at h + have h := (condIndepFun_iff_condDistrib_prod_ae_eq_prodMkRight hY hX hZ).mp h + have h_left := condDistrib_ae_eq_cond (hZ.prodMk hX) hY (μ := μ) + have h_right := condDistrib_ae_eq_cond hZ hY (μ := μ) + rw [Filter.EventuallyEq, ae_iff_of_countable] at h h_left h_right + specialize h (ω, b) + specialize h_left (ω, b) + specialize h_right ω + rw [Measure.map_apply (by fun_prop) (measurableSet_singleton _)] at h h_left h_right + rw [← Set.singleton_prod_singleton, Set.mk_preimage_prod] at h h_left + have hZ_ne : μ (Z ⁻¹' {ω}) ≠ 0 := fun h ↦ hμ (measure_mono_null Set.inter_subset_left h) + rw [← h_right hZ_ne, ← h_left hμ, h hμ] + simp + +end CondDistrib + +end ProbabilityTheory diff --git a/LeanMachineLearning/ForMathlib/Probability/Independence/IndepInfinitePi.lean b/LeanMachineLearning/ForMathlib/Probability/Independence/InfinitePi.lean similarity index 53% rename from LeanMachineLearning/ForMathlib/Probability/Independence/IndepInfinitePi.lean rename to LeanMachineLearning/ForMathlib/Probability/Independence/InfinitePi.lean index 0adab54b..5d772d5e 100644 --- a/LeanMachineLearning/ForMathlib/Probability/Independence/IndepInfinitePi.lean +++ b/LeanMachineLearning/ForMathlib/Probability/Independence/InfinitePi.lean @@ -5,36 +5,29 @@ Authors: Rémy Degenne, Paulo Rauber -/ module +public import LeanMachineLearning.ForMathlib.MeasureTheory.MeasurableSpace.Constructions public import Mathlib.Probability.Independence.InfinitePi /-! # Lemmas about independence and infinite products + +## Main statements + +* `indepFun_proj_infinitePi_infinitePi`: under a product of product measures, two distinct + columns of coordinates are independent. +* `iIndepFun_map_iff`: independence of a family of random variables under an image measure. -/ @[expose] public section open MeasureTheory Measure ProbabilityTheory Set Function -namespace MeasurableSpace - -variable {δ : Type*} {X : δ → Type*} [m : ∀ a, MeasurableSpace (X a)] {α : Type*} - --- Mathlib/MeasureTheory/MeasurableSpace/Constructions.lean -lemma comap_pi {g : α → ∀ a, X a} : pi.comap g = ⨆ a, (m a).comap (fun x ↦ g x a) := by - simp_rw [pi, comap_iSup, comap_comp, comp_def] - -end MeasurableSpace - namespace ProbabilityTheory -lemma hasLaw_eval_infinitePi {ι : Type*} {X : ι → Type*} {mX : ∀ i, MeasurableSpace (X i)} - (μ : (i : ι) → Measure (X i)) [∀ i, IsProbabilityMeasure (μ i)] (i : ι) : - HasLaw (Function.eval i) (μ i) (infinitePi μ) := - (measurePreserving_eval_infinitePi μ i).hasLaw +section Proj variable {ι κ : Type*} {𝓧 : ι → κ → Type*} [m𝓧 : ∀ i j, MeasurableSpace (𝓧 i j)] {μ : (i : ι) → (j : κ) → Measure (𝓧 i j)} [∀ i j, IsProbabilityMeasure (μ i j)] --- Mathlib/Probability/Independence/InfinitePi.lean lemma indepFun_proj_infinitePi_infinitePi {a b : κ} (h : a ≠ b) : IndepFun (fun ω i ↦ ω i a) (fun ω i ↦ ω i b) (infinitePi (fun i ↦ infinitePi (μ i))) := by simp_rw [IndepFun_iff_Indep, MeasurableSpace.comap_pi] @@ -44,4 +37,22 @@ lemma indepFun_proj_infinitePi_infinitePi {a b : κ} (h : a ≠ b) : (iIndepFun_uncurry_infinitePi' (X := fun _ _ x ↦ x) μ (by fun_prop)) hd all_goals rw [iSup_range] +end Proj + +section Map + +variable {Ω Ω' E ι : Type*} [Countable ι] {mΩ : MeasurableSpace Ω} {mΩ' : MeasurableSpace Ω'} + {mE : MeasurableSpace E} {μ : Measure Ω} + +lemma iIndepFun_map_iff [IsProbabilityMeasure μ] {X : ι → Ω' → E} {f : Ω → Ω'} + (hf : AEMeasurable f μ) (hX : ∀ n, AEMeasurable (X n) (μ.map f)) : + iIndepFun X (μ.map f) ↔ iIndepFun (fun n ↦ X n ∘ f) μ := by + rw [iIndepFun_iff_map_fun_eq_infinitePi_map₀' hX, + iIndepFun_iff_map_fun_eq_infinitePi_map₀' (by fun_prop)] + rw [AEMeasurable.map_map_of_aemeasurable (by fun_prop) hf] + congr! 3 + rw [AEMeasurable.map_map_of_aemeasurable (hX _) hf] + +end Map + end ProbabilityTheory diff --git a/LeanMachineLearning/ForMathlib/Probability/Independence/Kernel/IndepFun.lean b/LeanMachineLearning/ForMathlib/Probability/Independence/Kernel/IndepFun.lean new file mode 100644 index 00000000..feda0e97 --- /dev/null +++ b/LeanMachineLearning/ForMathlib/Probability/Independence/Kernel/IndepFun.lean @@ -0,0 +1,42 @@ +/- +Copyright (c) 2026 Rémy Degenne. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Rémy Degenne +-/ +module + +public import Mathlib.Probability.Independence.Kernel.IndepFun + +/-! +# Lemmas about independence of functions with respect to a kernel + +## Main statements + +* `Kernel.IndepFun.of_prod_right`, `Kernel.IndepFun.of_prod_left`: if `X` is independent of + `(Y, T)`, then `X` is independent of `Y`. +-/ + +@[expose] public section + +open MeasureTheory + +namespace ProbabilityTheory + +variable {α β γ : Type*} {mα : MeasurableSpace α} {mβ : MeasurableSpace β} + {mγ : MeasurableSpace γ} + +lemma Kernel.IndepFun.of_prod_right {ε Ω : Type*} {mΩ : MeasurableSpace Ω} {mε : MeasurableSpace ε} + {μ : Measure Ω} {κ : Kernel Ω α} {X : α → β} {Y : α → γ} {T : α → ε} + (h : IndepFun X (fun ω ↦ (Y ω, T ω)) κ μ) : + IndepFun X Y κ μ := by + rw [Kernel.indepFun_iff_measure_inter_preimage_eq_mul] at h ⊢ + intro s t hs ht + specialize h s (t ×ˢ .univ) hs (ht.prod .univ) + simpa [Set.mk_preimage_prod] using h + +lemma Kernel.IndepFun.of_prod_left {ε Ω : Type*} {mΩ : MeasurableSpace Ω} {mε : MeasurableSpace ε} + {μ : Measure Ω} {κ : Kernel Ω α} {X : α → β} {Y : α → γ} {T : α → ε} + (h : IndepFun (fun ω ↦ (X ω, T ω)) Y κ μ) : + IndepFun X Y κ μ := h.symm.of_prod_right.symm + +end ProbabilityTheory diff --git a/LeanMachineLearning/ForMathlib/Probability/Integrable.lean b/LeanMachineLearning/ForMathlib/Probability/Integrable.lean deleted file mode 100644 index d899b999..00000000 --- a/LeanMachineLearning/ForMathlib/Probability/Integrable.lean +++ /dev/null @@ -1,29 +0,0 @@ -/- -Copyright (c) 2026 Rémy Degenne. All rights reserved. -Released under Apache 2.0 license as described in the file LICENSE. -Authors: Rémy Degenne --/ -module - -public import Mathlib.Probability.IdentDistrib - -/-! # Lemmas about integrable functions --/ - -@[expose] public section - -open ProbabilityTheory - -namespace MeasureTheory - -lemma Integrable.congr_identDistrib {Ω Ω' : Type*} - {mΩ : MeasurableSpace Ω} {mΩ' : MeasurableSpace Ω'} - {μ : Measure Ω} {μ' : Measure Ω'} {X : Ω → ℝ} {Y : Ω' → ℝ} - (hX : Integrable X μ) (hXY : IdentDistrib X Y μ μ') : - Integrable Y μ' := by - have hX' : Integrable id (μ.map X) := by - rwa [integrable_map_measure (by fun_prop) hXY.aemeasurable_fst] - rw [hXY.map_eq] at hX' - rwa [integrable_map_measure (by fun_prop) hXY.aemeasurable_snd] at hX' - -end MeasureTheory diff --git a/LeanMachineLearning/ForMathlib/Probability/Kernel/Basic.lean b/LeanMachineLearning/ForMathlib/Probability/Kernel/Basic.lean index a8e69939..2ed5d225 100644 --- a/LeanMachineLearning/ForMathlib/Probability/Kernel/Basic.lean +++ b/LeanMachineLearning/ForMathlib/Probability/Kernel/Basic.lean @@ -5,9 +5,10 @@ Authors: Rémy Degenne -/ module +public import LeanMachineLearning.ForMathlib.MeasureTheory.Measure.Dirac public import Mathlib.Probability.Kernel.Basic -/-! # Basic lemmas about Markov kernels +/-! # Basic lemmas about kernels -/ @[expose] public section @@ -25,4 +26,11 @@ lemma deterministic_inj [MeasurableSpace.SeparatesPoints β] Kernel.deterministic f hf = Kernel.deterministic g hg ↔ f = g := by simp [Kernel.ext_iff, Kernel.deterministic_apply, dirac_eq_dirac_iff, funext_iff] +/-- Every Markov kernel with a subsingleton codomain is a constant kernel at a Dirac mass. -/ +lemma eq_const_dirac_of_subsingleton [Subsingleton β] (κ : Kernel α β) [IsMarkovKernel κ] (y : β) : + κ = Kernel.const α (Measure.dirac y) := by + ext a : 1 + rw [Kernel.const_apply] + exact (κ a).eq_dirac_of_subsingleton y + end ProbabilityTheory.Kernel diff --git a/LeanMachineLearning/ForMathlib/Probability/Kernel/Composition/IntegralCompProd.lean b/LeanMachineLearning/ForMathlib/Probability/Kernel/Composition/IntegralCompProd.lean index 321da8bd..74d0a860 100644 --- a/LeanMachineLearning/ForMathlib/Probability/Kernel/Composition/IntegralCompProd.lean +++ b/LeanMachineLearning/ForMathlib/Probability/Kernel/Composition/IntegralCompProd.lean @@ -7,8 +7,6 @@ module public import Mathlib.Probability.Kernel.Composition.IntegralCompProd -import Mathlib.Analysis.Convex.Integral - /-! # Lp functions with respect to a composition of kernels and measures -/ @@ -20,49 +18,31 @@ open scoped ENNReal namespace MeasureTheory +lemma AEStronglyMeasurable.ae_of_comp {α β E : Type*} {mα : MeasurableSpace α} + {mβ : MeasurableSpace β} [TopologicalSpace E] {κ : Kernel α β} {μ : Measure α} {f : β → E} + (hf : AEStronglyMeasurable f (κ ∘ₘ μ)) : + ∀ᵐ x ∂μ, AEStronglyMeasurable f (κ x) := by + obtain ⟨g, hg, hfg⟩ := hf + filter_upwards [Measure.ae_ae_of_ae_comp hfg] with x hx using ⟨g, hg, hx⟩ + protected lemma Measure.memLp_comp_iff {α β E : Type*} {mα : MeasurableSpace α} {mβ : MeasurableSpace β} [NormedAddCommGroup E] {κ : Kernel α β} {μ : Measure α} {f : β → E} {p : ℝ≥0∞} (hp0 : p ≠ 0) (hp_top : p ≠ ∞) (hf : AEStronglyMeasurable f (κ ∘ₘ μ)) : MemLp f p (κ ∘ₘ μ) ↔ (∀ᵐ x ∂μ, MemLp f p (κ x)) ∧ Integrable (fun x ↦ ∫ y, ‖f y‖ ^ p.toReal ∂κ x) μ := by - rw [← integrable_norm_rpow_iff (by fun_prop) hp0 hp_top, Measure.integrable_comp_iff] - swap; · exact (hf.norm.aemeasurable.pow_const p.toReal).aestronglyMeasurable - -- todo extract - unfold AEStronglyMeasurable at hf - obtain ⟨g, hg, hfg⟩ := hf - obtain hfg' := Measure.ae_ae_of_ae_comp hfg - have hf' : ∀ᵐ ω ∂μ, AEStronglyMeasurable f (κ ω) := by - filter_upwards [hfg'] with ω hω using ⟨g, hg, hω⟩ - -- - congr! 1 - · suffices ∀ᵐ x ∂μ, Integrable (fun x ↦ ‖f x‖ ^ p.toReal) (κ x) ↔ MemLp f p (κ x) by - refine ⟨fun h ↦ ?_, fun h ↦ ?_⟩ - <;> filter_upwards [h, this] with x hx h_iff - · rwa [h_iff] at hx - · rwa [← h_iff] at hx - filter_upwards [hf'] with ω hω - rw [integrable_norm_rpow_iff hω hp0 hp_top] - · congr! 4 with y - simp only [Real.norm_eq_abs, abs_eq_self] - positivity - -/-- **Jensen's inequality** for the convex function `x ↦ ‖x‖ ^ p`, `1 ≤ p`. -/ -lemma norm_integral_rpow_le_integral_norm_rpow - {α E : Type*} {mα : MeasurableSpace α} {μ : Measure α} [IsProbabilityMeasure μ] - [NormedAddCommGroup E] [NormedSpace ℝ E] {f : α → E} {p : ℝ≥0∞} - (hp1 : 1 ≤ p) (hp_top : p ≠ ∞) (hf : MemLp f p μ) : - ‖∫ x, f x ∂μ‖ ^ p.toReal ≤ ∫ x, ‖f x‖ ^ p.toReal ∂μ := by - have hp0 : p ≠ 0 := by positivity - have hp1' : 1 ≤ p.toReal := by simpa using ENNReal.toReal_mono hp_top hp1 - calc ‖∫ x, f x ∂μ‖ ^ p.toReal - _ ≤ (∫ x, ‖f x‖ ∂μ) ^ p.toReal := by - gcongr - exact norm_integral_le_integral_norm _ - _ ≤ ∫ x, ‖f x‖ ^ p.toReal ∂μ := - ConvexOn.map_integral_le (convexOn_rpow hp1') - (Real.continuous_rpow_const (by positivity)).continuousOn isClosed_Ici - (ae_of_all _ fun x ↦ norm_nonneg _) (hf.integrable hp1).norm - ((integrable_norm_rpow_iff hf.aestronglyMeasurable hp0 hp_top).mpr hf) + rw [← integrable_norm_rpow_iff (by fun_prop) hp0 hp_top, Measure.integrable_comp_iff] + swap; · exact (hf.norm.aemeasurable.pow_const p.toReal).aestronglyMeasurable + congr! 1 + · suffices ∀ᵐ x ∂μ, Integrable (fun x ↦ ‖f x‖ ^ p.toReal) (κ x) ↔ MemLp f p (κ x) by + refine ⟨fun h ↦ ?_, fun h ↦ ?_⟩ + <;> filter_upwards [h, this] with x hx h_iff + · rwa [h_iff] at hx + · rwa [← h_iff] at hx + filter_upwards [hf.ae_of_comp] with ω hω + rw [integrable_norm_rpow_iff hω hp0 hp_top] + · congr! 4 with y + simp only [Real.norm_eq_abs, abs_eq_self] + positivity end MeasureTheory diff --git a/LeanMachineLearning/ForMathlib/Probability/Kernel/Composition/Lemmas.lean b/LeanMachineLearning/ForMathlib/Probability/Kernel/Composition/Lemmas.lean index 948cf66c..bd34e70c 100644 --- a/LeanMachineLearning/ForMathlib/Probability/Kernel/Composition/Lemmas.lean +++ b/LeanMachineLearning/ForMathlib/Probability/Kernel/Composition/Lemmas.lean @@ -7,12 +7,18 @@ module public import Mathlib.Probability.Kernel.Composition.Lemmas -/-! # Lemmas about composition of kernel +/-! # Lemmas about compositions of kernels and measures + +## Main statements + +* `Kernel.compProd_prodMkLeft_apply`: `(ξ ⊗ₖ κ.prodMkLeft α) a = ξ a ⊗ₘ κ`. +* `Measure.map_compProd_comap`: transporting `μ ⊗ₘ η.comap f` along `f` in the first coordinate + gives `μ.map f ⊗ₘ η`. -/ @[expose] public section -open MeasureTheory +open MeasureTheory ProbabilityTheory namespace ProbabilityTheory.Kernel @@ -26,3 +32,18 @@ lemma compProd_prodMkLeft_apply (ξ : Kernel α β) [IsSFiniteKernel ξ] simp [Kernel.prodMkLeft_apply] end ProbabilityTheory.Kernel + +namespace MeasureTheory.Measure + +variable {α β γ : Type*} {mα : MeasurableSpace α} {mβ : MeasurableSpace β} {mγ : MeasurableSpace γ} + +/-- Transporting `μ ⊗ₘ η.comap f` along `f` in the first coordinate gives `μ.map f ⊗ₘ η`. -/ +lemma map_compProd_comap (μ : Measure α) [SFinite μ] + (η : Kernel β γ) [IsSFiniteKernel η] {f : α → β} (hf : Measurable f) : + (μ ⊗ₘ η.comap f hf).map (fun p : α × γ ↦ (f p.1, p.2)) = μ.map f ⊗ₘ η := by + ext s hs + rw [Measure.map_apply (by fun_prop) hs, Measure.compProd_apply (hs.preimage (by fun_prop)), + Measure.compProd_apply hs, lintegral_map (Kernel.measurable_kernel_prodMk_left hs) hf] + rfl + +end MeasureTheory.Measure diff --git a/LeanMachineLearning/ForMathlib/Probability/Kernel/Composition/MeasureCompProd.lean b/LeanMachineLearning/ForMathlib/Probability/Kernel/Composition/MeasureCompProd.lean index e2f2aec7..d0be18c2 100644 --- a/LeanMachineLearning/ForMathlib/Probability/Kernel/Composition/MeasureCompProd.lean +++ b/LeanMachineLearning/ForMathlib/Probability/Kernel/Composition/MeasureCompProd.lean @@ -5,7 +5,7 @@ Authors: Paulo Rauber -/ module -public import Mathlib.Probability.Kernel.Composition.MeasureCompProd +public import Mathlib.Probability.Kernel.Composition.MeasureComp /-! # Lemmas about measure composition-product -/ @@ -18,6 +18,60 @@ namespace MeasureTheory.Measure variable {α β : Type*} {mα : MeasurableSpace α} {mβ : MeasurableSpace β} {κ η : Kernel α β} +lemma dirac_compProd [IsSFiniteKernel κ] (a : α) : + Measure.dirac a ⊗ₘ κ = (κ a).map (Prod.mk a) := by + ext s hs + rw [Measure.compProd_apply hs, lintegral_dirac' _ (Kernel.measurable_kernel_prodMk_left hs), + Measure.map_apply measurable_prodMk_left hs] + +section Prod + +variable {γ : Type*} {mγ : MeasurableSpace γ} + +lemma snd_compProd_prodMkLeft {μ : Measure (α × β)} [SFinite μ] {κ : Kernel β γ} + [IsSFiniteKernel κ] : + (μ ⊗ₘ (κ.prodMkLeft α)).snd = κ ∘ₘ μ.snd := by + ext s hs + rw [Measure.snd_apply hs, Measure.compProd_apply (hs.preimage (by fun_prop)), + Measure.bind_apply hs (by fun_prop), Measure.snd, + lintegral_map (κ.measurable_coe hs) (by fun_prop)] + simp only [Kernel.prodMkLeft_apply] + congr + +lemma snd_compProd_prodMkRight {μ : Measure (α × β)} [SFinite μ] {κ : Kernel α γ} + [IsSFiniteKernel κ] : + (μ ⊗ₘ (κ.prodMkRight β)).snd = κ ∘ₘ μ.fst := by + ext s hs + rw [Measure.snd_apply hs, Measure.compProd_apply (hs.preimage (by fun_prop)), + Measure.bind_apply hs (by fun_prop), Measure.fst, + lintegral_map (κ.measurable_coe hs) (by fun_prop)] + simp only [Kernel.prodMkRight_apply] + congr + +lemma snd_map_prodAssoc_compProd_prodMkLeft {μ : Measure (α × β)} [SFinite μ] + {κ : Kernel β γ} [IsSFiniteKernel κ] : + ((μ ⊗ₘ (κ.prodMkLeft α)).map MeasurableEquiv.prodAssoc).snd = μ.snd ⊗ₘ κ := by + ext s hs + rw [Measure.snd_apply hs, Measure.map_apply (by fun_prop) (hs.preimage (by fun_prop)), + Measure.compProd_apply, Measure.compProd_apply hs, Measure.snd, lintegral_map _ (by fun_prop)] + · simp only [Kernel.prodMkLeft_apply] + congr + · exact Kernel.measurable_kernel_prodMk_left hs + · exact hs.preimage (by fun_prop) + +/-- Forgetting the second coordinate of the first component of `μ ⊗ₘ κ.prodMkRight β` gives +`μ.fst ⊗ₘ κ`. -/ +lemma map_prodMap_fst_compProd_prodMkRight {μ : Measure (α × β)} [SFinite μ] {κ : Kernel α γ} + [IsSFiniteKernel κ] : + (μ ⊗ₘ (κ.prodMkRight β)).map (Prod.map Prod.fst id) = μ.fst ⊗ₘ κ := by + ext s hs + rw [Measure.map_apply (by fun_prop) hs, Measure.compProd_apply hs, + Measure.compProd_apply (hs.preimage (by fun_prop)), Measure.fst, + lintegral_map (Kernel.measurable_kernel_prodMk_left hs) (by fun_prop)] + rfl + +end Prod + section AbsolutelyContinuous lemma AbsolutelyContinuous.compProd_left_apply {γ : Type*} {mγ : MeasurableSpace γ} diff --git a/LeanMachineLearning/ForMathlib/Probability/Kernel/Composition/WithDensity.lean b/LeanMachineLearning/ForMathlib/Probability/Kernel/Composition/WithDensity.lean new file mode 100644 index 00000000..f6713ce9 --- /dev/null +++ b/LeanMachineLearning/ForMathlib/Probability/Kernel/Composition/WithDensity.lean @@ -0,0 +1,50 @@ +/- +Copyright (c) 2026 Paulo Rauber. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Paulo Rauber +-/ +module + +public import Mathlib.Probability.Kernel.Composition.WithDensity + +/-! +# Composition-product with a kernel with density + +## Main statements + +* `Measure.compProd_eq_compProd_withDensity_comp_snd`: if `κ` is a.e. equal to `η` with density + `f` (a function of the second coordinate only), then `μ ⊗ₘ κ` is `μ ⊗ₘ η` with density + `fun ab ↦ f ab.2`. +-/ + +@[expose] public section + +open ProbabilityTheory +open scoped ENNReal + +namespace MeasureTheory.Measure + +variable {α β : Type*} {mα : MeasurableSpace α} {mβ : MeasurableSpace β} {μ : Measure α} + +lemma compProd_eq_compProd_withDensity_comp_snd [SFinite μ] {κ η : Kernel α β} [IsSFiniteKernel κ] + [IsSFiniteKernel η] {f : β → ℝ≥0∞} (hf : Measurable f) + (h : κ =ᵐ[μ] η.withDensity (fun _ b ↦ f b)) : + μ ⊗ₘ κ = (μ ⊗ₘ η).withDensity (fun ab ↦ f ab.2) := by + /- A proof based on `compProd_congr` requires `IsSFiniteKernel (η.withDensity fun _ b ↦ f b)`. -/ + refine ext_of_lintegral _ fun g hg ↦ ?_ + calc ∫⁻ ab, g ab ∂(μ ⊗ₘ κ) + = ∫⁻ a, ∫⁻ b, g (a, b) ∂κ a ∂μ := + lintegral_compProd hg + _ = ∫⁻ a, ∫⁻ b, g (a, b) ∂((η a).withDensity f) ∂μ := by + apply lintegral_congr_ae + filter_upwards [h] with a ha + rw [ha, Kernel.withDensity_apply _ (by fun_prop)] + _ = ∫⁻ a, ∫⁻ b, f b * g (a, b) ∂η a ∂μ := by + congr with a + exact lintegral_withDensity_eq_lintegral_mul _ hf (by fun_prop) + _ = ∫⁻ ab, f ab.2 * g ab ∂(μ ⊗ₘ η) := + (lintegral_compProd ((hf.comp measurable_snd).mul hg)).symm + _ = ∫⁻ ab, g ab ∂((μ ⊗ₘ η).withDensity (fun ab ↦ f ab.2)) := + (lintegral_withDensity_eq_lintegral_mul _ (hf.comp measurable_snd) hg).symm + +end MeasureTheory.Measure diff --git a/LeanMachineLearning/ForMathlib/Probability/Kernel/CondDistrib.lean b/LeanMachineLearning/ForMathlib/Probability/Kernel/CondDistrib.lean new file mode 100644 index 00000000..ec1d1609 --- /dev/null +++ b/LeanMachineLearning/ForMathlib/Probability/Kernel/CondDistrib.lean @@ -0,0 +1,264 @@ +/- +Copyright (c) 2025 Rémy Degenne. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Rémy Degenne +-/ +module + +public import LeanMachineLearning.ForMathlib.MeasureTheory.Measure.AEMeasurable +public import LeanMachineLearning.ForMathlib.Probability.ConditionalProbability +public import LeanMachineLearning.ForMathlib.Probability.Kernel.RadonNikodym +public import Mathlib.Probability.Kernel.CondDistrib + +/-! +# Lemmas about conditional distributions + +This file contains lemmas about `condDistrib`: its behavior with respect to products and +compositions of the random variables, and its expression as a conditioned measure when +conditioning on a random variable with countably many values. + +## Main statements + +* `condDistrib_prod_left`: chain rule for `condDistrib`. +* `ae_eq_of_condDistrib_eq_deterministic`: if the conditional distribution of `Y` given `X` is + a.e. the deterministic kernel of `f`, then `Y = f ∘ X` almost surely. +* `condDistrib_ae_eq_cond`: for `X` with countably many values, `condDistrib Y X μ` is given by + the laws of `Y` under the conditioned measures `μ[|X ⁻¹' {b}]`. +* `condDistrib_prod_of_forall_condDistrib_cond`: for `Z` with countably many values, the + conditional distribution of `Y` given `(X, Z)` can be computed from the conditional + distributions of `Y` given `X` under the conditioned measures `μ[|Z ⁻¹' {b}]`. + +## Notation + +* `𝓛[Y | X; μ]`: the conditional distribution `condDistrib Y X μ`, scoped in `ProbabilityTheory`. +-/ + +@[expose] public section + +open MeasureTheory ProbabilityTheory Finset +open scoped ENNReal NNReal + +variable {α β γ δ Ω Ω' : Type*} + {mα : MeasurableSpace α} {μ : Measure α} {mβ : MeasurableSpace β} {mγ : MeasurableSpace γ} + {mδ : MeasurableSpace δ} + [MeasurableSpace Ω] [StandardBorelSpace Ω] [Nonempty Ω] + [mΩ' : MeasurableSpace Ω'] [StandardBorelSpace Ω'] [Nonempty Ω'] + {X : α → β} {Y : α → Ω} {Z : α → Ω'} {T : α → γ} + +namespace ProbabilityTheory + +/-- Law of `Y` conditioned on `X`. -/ +scoped notation "𝓛[" Y " | " X "; " μ "]" => condDistrib Y X μ + +section CondDistrib + +variable [IsFiniteMeasure μ] + +lemma map_swap_compProd_map_condDistrib (hX : AEMeasurable X μ) (hY : AEMeasurable Y μ) : + (μ.map X ⊗ₘ condDistrib Y X μ).map Prod.swap = μ.map (fun a ↦ (Y a, X a)) := by + rw [compProd_map_condDistrib hX hY, + AEMeasurable.map_map_of_aemeasurable measurable_swap.aemeasurable (hX.prodMk hY)] + rfl + +lemma condDistrib_prod_left [StandardBorelSpace β] [Nonempty β] + (hX : AEMeasurable X μ) (hY : AEMeasurable Y μ) (hT : AEMeasurable T μ) : + condDistrib (fun ω ↦ (X ω, Y ω)) T μ + =ᵐ[μ.map T] condDistrib X T μ ⊗ₖ condDistrib Y (fun ω ↦ (T ω, X ω)) μ := by + refine condDistrib_ae_eq_of_measure_eq_compProd hT (by fun_prop) ?_ + rw [← Measure.compProd_assoc', compProd_map_condDistrib hT hX, + compProd_map_condDistrib (hT.prodMk hX) hY, + AEMeasurable.map_map_of_aemeasurable (by fun_prop) (by fun_prop)] + rfl + +lemma condDistrib_condDistrib_ae_eq_sectR_condDistrib [StandardBorelSpace β] [Nonempty β] + {f : Ω' → β} {g : Ω' → Ω} (hf : Measurable f) (hg : Measurable g) (hZ : AEMeasurable Z μ) + (hT : AEMeasurable T μ) : + ∀ᵐ t ∂(μ.map T), + condDistrib g f (condDistrib Z T μ t) =ᵐ[(condDistrib Z T μ t).map f] + (condDistrib (g ∘ Z) (fun a ↦ (T a, (f ∘ Z) a)) μ).sectR t := by + filter_upwards [ + condDistrib_prod_left (hf.comp_aemeasurable hZ) (hg.comp_aemeasurable hZ) hT, + condDistrib_comp hT hZ (hf.prodMk hg), condDistrib_comp hT hZ hf] with t h_prod h_pair h_fst + rw [condDistrib_ae_eq_iff_measure_eq_compProd hf.aemeasurable hg.aemeasurable] + calc (condDistrib Z T μ t).map (fun ω' ↦ (f ω', g ω')) + _ = condDistrib (fun a ↦ ((f ∘ Z) a, (g ∘ Z) a)) T μ t := by + rw [← Kernel.map_apply _ (hf.prodMk hg)] + exact h_pair.symm + _ = (condDistrib Z T μ t).map f + ⊗ₘ (condDistrib (g ∘ Z) (fun a ↦ (T a, (f ∘ Z) a)) μ).sectR t := by + rw [h_prod, Kernel.compProd_apply_eq_compProd_sectR, h_fst, Kernel.map_apply _ hf] + +lemma condDistrib_prod_self_left [StandardBorelSpace β] [Nonempty β] [StandardBorelSpace γ] + [Nonempty γ] + (hX : AEMeasurable X μ) (hT : AEMeasurable T μ) : + condDistrib (fun ω ↦ (X ω, T ω)) T μ =ᵐ[μ.map T] condDistrib X T μ ×ₖ Kernel.id := by + have h_prod := condDistrib_prod_left hX hT hT (μ := μ) + have h_fst := condDistrib_comp_self (μ := μ) (X := fun ω ↦ (T ω, X ω)) (f := Prod.fst) + (hT.prodMk hX) measurable_fst + rw [(compProd_map_condDistrib hT hX).symm] at h_fst + have h_fst' := (Measure.ae_compProd_iff (Kernel.measurableSet_eq _ _)).mp h_fst + filter_upwards [h_prod, h_fst'] with z hz1 hz2 + rw [hz1] + simp only [Kernel.deterministic_apply, Function.comp_def] at hz2 + ext t ht + rw [Kernel.compProd_apply ht] + calc ∫⁻ y, condDistrib T (fun ω ↦ (T ω, X ω)) μ (z, y) (Prod.mk y ⁻¹' t) ∂condDistrib X T μ z + _ = ∫⁻ y, (Measure.dirac z) (Prod.mk y ⁻¹' t) ∂condDistrib X T μ z := + lintegral_congr_ae (hz2.mono fun y hy ↦ by simp only [hy]) + _ = ∫⁻ y, (Prod.mk y ⁻¹' t).indicator 1 z ∂condDistrib X T μ z := + lintegral_congr fun y ↦ Measure.dirac_apply' _ (ht.preimage (by fun_prop)) + _ = (condDistrib X T μ z) ((fun y ↦ (y, z)) ⁻¹' t) := by + rw [← lintegral_indicator_one (ht.preimage (by fun_prop : Measurable fun y ↦ (y, z)))] + exact lintegral_congr fun _ ↦ rfl + _ = ((condDistrib X T μ ×ₖ Kernel.id) z) t := by + rw [Kernel.prod_apply, Kernel.id_apply, Measure.prod_apply_symm ht, lintegral_dirac] + +lemma fst_condDistrib_prod [StandardBorelSpace β] [Nonempty β] + (hX : AEMeasurable X μ) (hY : AEMeasurable Y μ) (hT : AEMeasurable T μ) : + (condDistrib (fun ω ↦ (X ω, Y ω)) T μ).fst =ᵐ[μ.map T] condDistrib X T μ := by + filter_upwards [condDistrib_prod_left hX hY hT] with c hc + rw [Kernel.fst_apply, hc, ← Kernel.fst_apply, Kernel.fst_compProd] + +lemma ae_eq_of_condDistrib_eq_deterministic {f : β → Ω} (hf : Measurable f) (hX : AEMeasurable X μ) + (hY : AEMeasurable Y μ) (h : condDistrib Y X μ =ᵐ[μ.map X] Kernel.deterministic f hf) : + Y =ᵐ[μ] f ∘ X := by + have hfX := condDistrib_comp_self hX hf + rw [condDistrib_ae_eq_iff_measure_eq_compProd hX (by fun_prop)] at h hfX + exact ae_eq_of_map_prodMk_eq hf hX hY (hfX ▸ h) + +end CondDistrib + +section Cond + +lemma condDistrib_ae_eq_cond [Countable β] [MeasurableSingletonClass β] + [IsFiniteMeasure μ] + (hX : Measurable X) (hY : Measurable Y) : + condDistrib Y X μ =ᵐ[μ.map X] fun b ↦ (μ[|X ⁻¹' {b}]).map Y := by + rw [Filter.EventuallyEq, ae_iff_of_countable] + intro b hb + ext s hs + rw [condDistrib_apply_of_ne_zero hX hY, + Measure.map_apply hX (measurableSet_singleton _), Measure.map_apply hY hs, + Measure.map_apply (hX.prodMk hY) ((measurableSet_singleton _).prod hs), + cond_apply (hX (measurableSet_singleton _))] + · congr + · exact hb + +omit [Nonempty Ω'] in +/-- Let `Z` be a random variable with countably many values. If for every value `b` of `Z` with +positive probability, the conditional distribution of `Y` given `X` under `μ[|Z ⁻¹' {b}]` is +`κ (·, b)`, then the conditional distribution of `Y` given `(X, Z)` under `μ` is `κ`. -/ +lemma condDistrib_prod_of_forall_condDistrib_cond [Countable Ω'] [IsFiniteMeasure μ] + (hX : Measurable X) (hY : Measurable Y) (hZ : Measurable Z) + (κ : Kernel (β × Ω') Ω) [IsFiniteKernel κ] + (h_cond : ∀ b, μ (Z ⁻¹' {b}) ≠ 0 → condDistrib Y X μ[|Z ⁻¹' {b}] =ᵐ[μ[|Z ⁻¹' {b}].map X] + (κ.comap (fun ω ↦ (ω, b)) (by fun_prop) : Kernel β Ω)) : + condDistrib Y (fun ω ↦ (X ω, Z ω)) μ =ᵐ[μ.map (fun ω ↦ (X ω, Z ω))] κ := by + refine condDistrib_ae_eq_of_measure_eq_compProd (by fun_prop) (by fun_prop) ?_ + ext s hs + -- It suffices to prove the equality of the two measures on the sets where `Z` is constant, + -- since those sets form a countable partition. + suffices ∀ b, (Measure.map (fun x ↦ ((X x, Z x), Y x)) μ) (s ∩ {p | p.1.2 = b}) = + (Measure.map (fun ω ↦ (X ω, Z ω)) μ ⊗ₘ κ) (s ∩ {p | p.1.2 = b}) by + have hs_iUnion : s = ⋃ b, s ∩ {p | p.1.2 = b} := by + ext p + simp only [Set.mem_iUnion, Set.mem_inter_iff, Set.mem_ofPred_eq] + grind + have h_disj : Pairwise (Function.onFun Disjoint fun b ↦ s ∩ {p | p.1.2 = b}) := by + intro i j hij + simp only [Set.disjoint_iff_inter_eq_empty] + ext + grind + have h_meas (b : Ω') : MeasurableSet (s ∩ {p | p.1.2 = b}) := + hs.inter ((measurableSet_singleton _).preimage (by fun_prop)) + rw [hs_iUnion, measure_iUnion h_disj h_meas, measure_iUnion h_disj h_meas] + congr with b + exact this b + intro b + by_cases hb : μ (Z ⁻¹' {b}) = 0 + -- If `Z = b` has probability zero, both measures vanish on `{p | p.1.2 = b}`. + · have h_left : (Measure.map (fun x ↦ ((X x, Z x), Y x)) μ) (s ∩ {p | p.1.2 = b}) = 0 := by + suffices (Measure.map (fun x ↦ ((X x, Z x), Y x)) μ) {p | p.1.2 = b} = 0 from + measure_mono_null Set.inter_subset_right this + rw [Measure.map_apply (by fun_prop)] + · simpa + · exact (measurableSet_singleton _).preimage (by fun_prop) + have h_right : (Measure.map (fun ω ↦ (X ω, Z ω)) μ ⊗ₘ κ) (s ∩ {p | p.1.2 = b}) = 0 := by + suffices (Measure.map (fun ω ↦ (X ω, Z ω)) μ ⊗ₘ κ) {p | p.1.2 = b} = 0 from + measure_mono_null Set.inter_subset_right this + rw [Measure.compProd_apply, lintegral_map] + rotate_left + · exact Kernel.measurable_kernel_prodMk_left + ((measurableSet_singleton _).preimage (by fun_prop)) + · fun_prop + · exact (measurableSet_singleton _).preimage (by fun_prop) + simp only [Set.preimage_ofPred_eq] + classical + have h_le : ∫⁻ a, (κ (X a, Z a)) {a_1 | Z a = b} ∂μ ≤ + ∫⁻ a, {a' | Z a' = b}.indicator (fun _ ↦ κ.bound) a ∂μ := by + gcongr with a + by_cases hZ : Z a = b + · simp only [hZ, Set.ofPred_true, Set.mem_ofPred_eq, Set.indicator_of_mem] + exact κ.measure_le_bound _ _ + · simp [hZ] + refine le_antisymm (h_le.trans ?_) zero_le + rw [lintegral_indicator] + swap; · exact (measurableSet_singleton _).preimage (by fun_prop) + simp only [lintegral_const, MeasurableSet.univ, Measure.restrict_apply, Set.univ_inter, + nonpos_iff_eq_zero, mul_eq_zero] + exact .inr hb + rw [h_left, h_right] + -- Otherwise, we use the hypothesis on `μ[|Z ⁻¹' {b}]` and unfold the definition of `cond`. + specialize h_cond b hb + rw [condDistrib_ae_eq_iff_measure_eq_compProd (by fun_prop) (by fun_prop)] at h_cond + rw [Measure.ext_iff] at h_cond + have hs' : MeasurableSet {p : β × Ω | ((p.1, b), p.2) ∈ s} := hs.preimage (by fun_prop) + have h1 := h_cond {p | ((p.1, b), p.2) ∈ s} hs' + have h_indicator : Measurable ({ω' | Z ω' = b}.indicator (fun x ↦ 1)) := + Measurable.indicator (by fun_prop) ((measurableSet_singleton _).preimage (by fun_prop)) + rw [Measure.map_apply] at h1 ⊢ + rotate_left + · fun_prop + · exact hs.inter ((measurableSet_singleton _).preimage (by fun_prop)) + · fun_prop + · exact hs' + rw [cond_apply] at h1 + swap; · exact (measurableSet_singleton _).preimage (by fun_prop) + have h1' : μ (Z ⁻¹' {b} ∩ (fun x ↦ (X x, Y x)) ⁻¹' {p | ((p.1, b), p.2) ∈ s}) = + (μ (Z ⁻¹' {b})) * + (Measure.map X μ[|Z ⁻¹' {b}] ⊗ₘ κ.comap (fun ω ↦ (ω, b)) (by fun_prop)) + {p | ((p.1, b), p.2) ∈ s} := by + rw [← h1, ← mul_assoc, ENNReal.mul_inv_cancel hb (by simp), one_mul] + convert h1' + · ext x + simp only [Set.preimage_inter, Set.preimage_ofPred_eq, Set.mem_inter_iff, Set.mem_preimage, + Set.mem_ofPred_eq] + grind + · rw [Measure.compProd_apply, Measure.compProd_apply, lintegral_map, lintegral_map] + rotate_left + · exact Kernel.measurable_kernel_prodMk_left hs' + · fun_prop + · apply Kernel.measurable_kernel_prodMk_left + exact hs.inter ((measurableSet_singleton _).preimage (by fun_prop)) + · fun_prop + · exact hs' + · exact hs.inter ((measurableSet_singleton _).preimage (by fun_prop)) + rw [lintegral_cond, ← mul_assoc, ENNReal.mul_inv_cancel hb (by simp), one_mul] + simp only [Set.preimage_inter, Set.preimage_ofPred_eq, Kernel.coe_comap, Function.comp_apply] + classical + have h_eq : (fun a ↦ κ (X a, Z a) (Prod.mk (X a, Z a) ⁻¹' s ∩ {a_1 | Z a = b})) = + {a | Z a = b}.indicator + (fun a ↦ κ (X a, b) (Prod.mk (X a, b) ⁻¹' s ∩ {a_1 | Z a = b})) := by + ext a + by_cases hZ : Z a = b <;> simp [hZ] + simp_rw [h_eq] + rw [lintegral_indicator] + swap; · exact (measurableSet_singleton _).preimage (by fun_prop) + refine setLIntegral_congr_fun ((measurableSet_singleton _).preimage (by fun_prop)) fun a ha ↦ ?_ + congr 1 with ω + simp only [Set.mem_inter_iff, Set.mem_preimage, Set.mem_ofPred_eq, and_iff_left_iff_imp] + grind + +end Cond + +end ProbabilityTheory diff --git a/LeanMachineLearning/ForMathlib/Probability/Kernel/IonescuTulcea/Traj.lean b/LeanMachineLearning/ForMathlib/Probability/Kernel/IonescuTulcea/Traj.lean index 53df791c..b32437d4 100644 --- a/LeanMachineLearning/ForMathlib/Probability/Kernel/IonescuTulcea/Traj.lean +++ b/LeanMachineLearning/ForMathlib/Probability/Kernel/IonescuTulcea/Traj.lean @@ -6,11 +6,24 @@ Authors: Rémy Degenne, Paulo Rauber module public import LeanMachineLearning.ForMathlib.MeasureTheory.MeasurableSpace.Embedding +public import LeanMachineLearning.ForMathlib.Order.Interval.Finset.Nat public import LeanMachineLearning.ForMathlib.Probability.HasCondDistrib public import Mathlib.Probability.Kernel.IonescuTulcea.Traj public import Mathlib.Probability.Process.FiniteDimensionalLaws /-! # Lemmas about `traj` and `trajMeasure` + +## Main definitions + +* `Kernel.trajMeasureFin κ'`: the measure on trajectories `Π n, X n` built from kernels + `κ' n : Kernel (Π i : Fin n, X i) (X n)` giving the law of each coordinate given the previous + ones. + +## Main statements + +* `Kernel.hasLaw_trajMeasure`, `Kernel.hasLaw_trajMeasureFin`: uniqueness of `trajMeasure` and + `trajMeasureFin`: a process with the right initial law and conditional distributions has law + `trajMeasure μ₀ κ` (resp. `trajMeasureFin κ'`). -/ @[expose] public section @@ -35,7 +48,6 @@ lemma traj_zero_map_eval_zero : rw [← Kernel.traj_map_frestrictLe, ← Kernel.map_comp_right _ (by fun_prop) (by fun_prop)] rfl -set_option backward.isDefEq.respectTransparency false in lemma hasLaw_Iic_of_forall_hasCondDistrib' {Y : (n : ℕ) → Ω → X n} (h0 : HasLaw (Y 0) μ₀ P) {N n : ℕ} (h_condDistrib : ∀ n < N, HasCondDistrib (Y (n + 1)) (fun ω ↦ fun i : Iic n ↦ Y i ω) (κ n) P) @@ -66,7 +78,7 @@ lemma hasLaw_Iic_of_forall_hasCondDistrib' intro hn_le specialize h_condDistrib n (by grind) specialize hn (by grind) - have h_law := hn.prod_of_hasCondDistrib h_condDistrib + have h_law := hn.prodMk_of_hasCondDistrib h_condDistrib have : (fun ω (i : Iic (n + 1)) ↦ Y i ω) = (MeasurableEquiv.IicSuccProd X n).symm ∘ (fun ω ↦ (fun i : Iic n ↦ Y i ω, Y (n + 1) ω)) := by @@ -83,7 +95,7 @@ lemma hasLaw_Iic_of_forall_hasCondDistrib' congr 1 rw [← Kernel.comp_assoc] congr - rw [Kernel.deterministic_comp_eq_map, partialTraj_succ_self, symm_IicSuccProd] + rw [Kernel.deterministic_comp_eq_map, partialTraj_succ_self, IicSuccProd_symm] rw [MeasurableEquiv.coe_trans, MeasurableEquiv.coe_prodCongr] rw [Kernel.map_comp_right _ (by fun_prop) (by fun_prop), ← Kernel.map_prod_map _ _ (by fun_prop) (by fun_prop)] @@ -110,14 +122,16 @@ lemma eq_trajMeasure_map_frestrictLe {Y : (n : ℕ) → Ω → X n} (h0 : HasLaw rw [(hasLaw_Iic_of_forall_hasCondDistrib' h0 h_condDistrib le_rfl).map_eq, trajMeasure_map_frestrictLe] -/-- Uniqueness of `trajMeasure`. -/ -lemma hasLaw_trajMeasure [IsFiniteMeasure P] +/-- Uniqueness of `trajMeasure`: a process whose initial law is `μ₀` and whose conditional +distribution at time `n + 1` given the past is `κ n` has law `trajMeasure μ₀ κ`. -/ +lemma hasLaw_trajMeasure {Y : (n : ℕ) → Ω → X n} (hY_meas : ∀ n, Measurable (Y n)) (h0 : HasLaw (Y 0) μ₀ P) (h_condDistrib : ∀ n, HasCondDistrib (Y (n + 1)) (fun ω ↦ fun i : Iic n ↦ Y i ω) (κ n) P) : HasLaw (fun ω n ↦ Y n ω) (trajMeasure μ₀ κ) P where aemeasurable := by fun_prop map_eq := by + have := h0.isProbabilityMeasure refine IsProjectiveLimit.unique (P := fun (J : Finset ℕ) ↦ P.map (fun ω (i : J) ↦ Y i ω)) ?_ ?_ · exact isProjectiveLimit_map (by fun_prop) rw [isProjectiveLimit_nat_iff] diff --git a/LeanMachineLearning/ForMathlib/Probability/Kernel/KernelSub.lean b/LeanMachineLearning/ForMathlib/Probability/Kernel/RadonNikodym.lean similarity index 72% rename from LeanMachineLearning/ForMathlib/Probability/Kernel/KernelSub.lean rename to LeanMachineLearning/ForMathlib/Probability/Kernel/RadonNikodym.lean index 2bd57160..a04ff2bb 100644 --- a/LeanMachineLearning/ForMathlib/Probability/Kernel/KernelSub.lean +++ b/LeanMachineLearning/ForMathlib/Probability/Kernel/RadonNikodym.lean @@ -1,16 +1,29 @@ /- Copyright (c) 2025 Rémy Degenne. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. -Authors: Rémy Degenne +Authors: Rémy Degenne, Paulo Rauber -/ module -public import Mathlib.MeasureTheory.Measure.SubFinite +public import LeanMachineLearning.ForMathlib.MeasureTheory.Measure.Decomposition.Lebesgue public import Mathlib.Probability.Kernel.RadonNikodym /-! -# Kernel substraction +# Consequences of the Radon-Nikodym theorem for kernels +For s-finite kernels `κ η : Kernel α β`, we define the subtraction `κ - η` as +`η.withDensity (κ.rnDeriv η - 1) + κ.singularPart η`, and set it to `0` otherwise. For finite +kernels, `(κ - η) a = κ a - η a` (`Kernel.sub_apply`). We deduce that the set of points at which +two finite kernels agree is measurable. + +## Main statements + +* `Kernel.sub_apply`: for finite kernels, `(κ - η) a = κ a - η a`. +* `Kernel.measurableSet_eq`: the set of points at which two finite kernels agree is measurable. +* `Kernel.prodMkLeft_ae_eq_iff`, `Kernel.prodMkRight_ae_eq_iff`: `κ.prodMkLeft γ` and + `η.prodMkLeft γ` are a.e. equal iff `κ` and `η` are a.e. equal for the marginal measure. +* `Kernel.withDensity_rnDeriv_eq'`: if `κ a ≪ η a` for all `a`, then + `η.withDensity (κ.rnDeriv η) = κ`. -/ @[expose] public section @@ -18,31 +31,10 @@ public import Mathlib.Probability.Kernel.RadonNikodym open MeasureTheory MeasurableSpace open scoped ENNReal -namespace MeasureTheory.Measure - -variable {α β : Type*} {mα : MeasurableSpace α} {mβ : MeasurableSpace β} {μ ν ξ : Measure α} - -lemma sub_apply_eq_rnDeriv_add_singularPart [IsFiniteMeasure μ] [IsFiniteMeasure ν] (s : Set α) : - (μ - ν) s = ν.withDensity (fun a ↦ μ.rnDeriv ν a - 1) s + μ.singularPart ν s := by - have hμ : μ = ν.withDensity (fun a ↦ μ.rnDeriv ν a) + μ.singularPart ν := by - rw [rnDeriv_add_singularPart] - have hν : ν = ν.withDensity 1 := by rw [withDensity_one] - conv_lhs => rw [hν, hμ, add_comm _ (μ.singularPart ν)] - rw [← add_sub_of_mutuallySingular] - swap - · simp only [withDensity_one] - exact mutuallySingular_singularPart μ ν - simp only [coe_add, Pi.add_apply] - have : IsFiniteMeasure (ν.withDensity 1) := by simp only [withDensity_one]; infer_instance - rw [add_comm, ← withDensity_sub (by fun_prop) (by fun_prop)] - congr - -end MeasureTheory.Measure - namespace ProbabilityTheory.Kernel -variable {α β : Type*} {mα : MeasurableSpace α} {mβ : MeasurableSpace β} - [CountableOrCountablyGenerated α β] {κ η : Kernel α β} +variable {α β γ : Type*} {mα : MeasurableSpace α} {mβ : MeasurableSpace β} + {mγ : MeasurableSpace γ} [CountableOrCountablyGenerated α β] {κ η : Kernel α β} noncomputable instance [∀ η : Kernel α β, Decidable (IsSFiniteKernel η)] : @@ -77,7 +69,6 @@ lemma sub_of_isSFiniteKernel [IsSFiniteKernel κ] [IsSFiniteKernel η] rw [sub_def, dite_eq_left] exact ⟨inferInstance, inferInstance⟩ --- todo name lemma sub_apply_eq_rnDeriv_add_singularPart [∀ η : Kernel α β, Decidable (IsSFiniteKernel η)] [IsSFiniteKernel κ] [IsSFiniteKernel η] (a : α) : (κ - η) a = η.withDensity (fun a ↦ κ.rnDeriv η a - 1) a + κ.singularPart η a := by @@ -156,4 +147,22 @@ lemma measurableSet_eq (κ η : Kernel α β) [IsFiniteKernel κ] [IsFiniteKerne · exact measurableSet_eq_zero _ · exact measurableSet_eq_zero _ +lemma prodMkLeft_ae_eq_iff [IsFiniteKernel κ] [IsFiniteKernel η] {μ : Measure (γ × α)} : + κ.prodMkLeft γ =ᵐ[μ] η.prodMkLeft γ ↔ κ =ᵐ[μ.snd] η := by + rw [Measure.snd, Filter.EventuallyEq, Filter.EventuallyEq, ae_map_iff (by fun_prop)] + · simp + · classical + exact Kernel.measurableSet_eq κ η + +lemma prodMkRight_ae_eq_iff [IsFiniteKernel κ] [IsFiniteKernel η] {μ : Measure (α × γ)} : + κ.prodMkRight γ =ᵐ[μ] η.prodMkRight γ ↔ κ =ᵐ[μ.fst] η := by + rw [Measure.fst, Filter.EventuallyEq, Filter.EventuallyEq, ae_map_iff (by fun_prop)] + · simp + · classical + exact Kernel.measurableSet_eq κ η + +lemma withDensity_rnDeriv_eq' [IsFiniteKernel κ] [IsFiniteKernel η] (h : ∀ a, κ a ≪ η a) : + η.withDensity (κ.rnDeriv η) = κ := + Kernel.ext fun a ↦ withDensity_rnDeriv_eq (h a) + end ProbabilityTheory.Kernel diff --git a/LeanMachineLearning/ForMathlib/Probability/Kernel/Sigma.lean b/LeanMachineLearning/ForMathlib/Probability/Kernel/Sigma.lean index 373f7b64..c78e96fb 100644 --- a/LeanMachineLearning/ForMathlib/Probability/Kernel/Sigma.lean +++ b/LeanMachineLearning/ForMathlib/Probability/Kernel/Sigma.lean @@ -25,7 +25,7 @@ variable {α γ : Type*} {β : α → Type*} [∀ a, MeasurableSpace (β a)] {m /-- The kernel on `Σ a, β a` which is `κ a` on the fiber `β a`. -/ def sigma (κ : (a : α) → Kernel (β a) γ) : Kernel (Σ a, β a) γ where toFun x := κ x.1 x.2 - measurable' := measurable_sigma_of_measurable_comp_mk fun a ↦ (κ a).measurable + measurable' := measurable_sigma fun a ↦ (κ a).measurable @[simp] lemma sigma_apply (κ : (a : α) → Kernel (β a) γ) (x : Σ a, β a) : sigma κ x = κ x.1 x.2 := rfl @@ -33,8 +33,8 @@ lemma sigma_apply (κ : (a : α) → Kernel (β a) γ) (x : Σ a, β a) : sigma lemma sigma_apply_mk (κ : (a : α) → Kernel (β a) γ) (a : α) (b : β a) : sigma κ ⟨a, b⟩ = κ a b := rfl -lemma comap_sigma_mk (κ : (a : α) → Kernel (β a) γ) (a : α) : - (sigma κ).comap (Sigma.mk a) (measurable_sigma_mk a) = κ a := by +lemma comap_sigmaMk (κ : (a : α) → Kernel (β a) γ) (a : α) : + (sigma κ).comap (Sigma.mk a) (measurable_sigmaMk a) = κ a := by ext b : 1 rw [comap_apply, sigma_apply_mk] diff --git a/LeanMachineLearning/ForMathlib/Probability/Moments/SubExponential.lean b/LeanMachineLearning/ForMathlib/Probability/Moments/SubExponential.lean index a54d82b6..accf5f51 100644 --- a/LeanMachineLearning/ForMathlib/Probability/Moments/SubExponential.lean +++ b/LeanMachineLearning/ForMathlib/Probability/Moments/SubExponential.lean @@ -5,6 +5,7 @@ Authors: Rémy Degenne -/ module +public import LeanMachineLearning.ForMathlib.Analysis.Complex.Exponential public import Mathlib.Probability.Moments.SubGaussian public import Mathlib.Probability.Moments.MGFAnalytic @@ -61,6 +62,11 @@ least `1` (with the convention `x / 0 = 0`) and the bound holds trivially. As in `Kernel.HasSubgaussianMGF`, the integrability condition of the kernel version is integrability with respect to `κ ∘ₘ ν`, not almost-everywhere integrability with respect to `κ ω'`. + +## References + +* [M. J. Wainwright, *High-Dimensional Statistics: A Non-Asymptotic Viewpoint*][wainwright2019], + Section 2.1.3 (sub-exponential variables and Bernstein-type bounds) -/ @[expose] public section @@ -326,8 +332,7 @@ lemma of_map {Ω'' : Type*} {mΩ'' : MeasurableSpace Ω''} {κ : Kernel Ω' Ω'' lemma id_map_iff (hX : Measurable X) : HasSubexponentialMGF id V b (κ.map X) ν ↔ HasSubexponentialMGF X V b κ ν := by refine ⟨fun h ↦ ?_, fun h ↦ ⟨fun t ht ↦ ?_, ?_⟩⟩ - · change HasSubexponentialMGF (id ∘ X) V b κ ν - exact .of_map hX h + · exact .of_map (X := id) hX h · rw [← Kernel.deterministic_comp_eq_map hX, ← Measure.comp_assoc, Measure.deterministic_comp_eq_map, integrable_map_measure (by fun_prop) hX.aemeasurable] exact h.integrable_exp_mul t ht @@ -1161,13 +1166,6 @@ lemma Kernel.HasSubexponentialMGF.ae_eq_zero_of_hasSubexponentialMGF_zero {Ω' : section Bounded -/-- Second-order bound on the exponential on `[-1, 1]`, from `Real.exp_bound`. -/ -lemma exp_le_one_add_add_of_abs_le_one {x : ℝ} (hx : |x| ≤ 1) : - exp x ≤ 1 + x + 3 / 4 * x ^ 2 := by - have h := Real.exp_bound hx (n := 2) two_pos - norm_num [Finset.sum_range_succ, Nat.factorial] at h - linarith [(abs_le.1 h).2] - /-- If `|X| ≤ M` almost surely, `X` is centered and `μ[X ^ 2] ≤ v`, then `X` has a sub-exponential mgf with parameters `(3 * v / 2, M)`. -/ lemma hasSubexponentialMGF_of_abs_le_of_integral_eq_zero [IsProbabilityMeasure μ] {M v : ℝ} diff --git a/LeanMachineLearning/ForMathlib/Probability/Moments/SubGaussian.lean b/LeanMachineLearning/ForMathlib/Probability/Moments/SubGaussian.lean index c4d63dbc..af186692 100644 --- a/LeanMachineLearning/ForMathlib/Probability/Moments/SubGaussian.lean +++ b/LeanMachineLearning/ForMathlib/Probability/Moments/SubGaussian.lean @@ -8,6 +8,13 @@ module public import Mathlib.Probability.Moments.SubGaussian /-! # Lemmas about sub-Gaussian random variables + +## Main statements + +* `HasSubgaussianMGF.measure_le_le`, `HasSubgaussianMGF.measure_sum_le_le_of_iIndepFun`: lower + tail bounds (**Hoeffding's inequality** for the lower tail). +* `HasSubgaussianMGF.measure_sum_le_sum_le`: bound on the probability that a sum of independent + sub-Gaussian variables is smaller than another one, when its mean is larger. -/ @[expose] public section @@ -96,7 +103,7 @@ section Sum variable {ι ι' : Type*} {X : ι → Ω → ℝ} {cX : ι → ℝ≥0} {s : Finset ι} {Y : ι' → Ω → ℝ} {cY : ι' → ℝ≥0} {t : Finset ι'} -lemma measure_sum_le_sum_le [IsFiniteMeasure μ] +lemma measure_sum_le_sum_le (hX_indep : iIndepFun X μ) (hY_indep : iIndepFun Y μ) (hX_subG : ∀ i ∈ s, HasSubgaussianMGF (fun ω ↦ X i ω - μ[X i]) (cX i) μ) (hY_subG : ∀ j ∈ t, HasSubgaussianMGF (fun ω ↦ Y j ω - μ[Y j]) (cY j) μ) @@ -105,6 +112,7 @@ lemma measure_sum_le_sum_le [IsFiniteMeasure μ] μ.real {ω | ∑ i ∈ s, X i ω ≤ ∑ j ∈ t, Y j ω} ≤ exp (- (∑ j ∈ t, μ[Y j] - ∑ i ∈ s, μ[X i]) ^ 2 / (2 * (∑ i ∈ s, cX i + ∑ j ∈ t, cY j))) := by + have := hX_indep.isProbabilityMeasure have hX_int i (his : i ∈ s) : Integrable (X i) μ := by have h_int := (hX_subG i his).integrable simp_rw [sub_eq_add_neg, integrable_add_const_iff] at h_int @@ -130,7 +138,7 @@ lemma measure_sum_le_sum_le [IsFiniteMeasure μ] · rw [integral_finsetSum _ hY_int] · rw [integral_finsetSum _ hX_int] -lemma measure_sum_le_sum_le' [IsFiniteMeasure μ] +lemma measure_sum_le_sum_le' (hX_indep : iIndepFun X μ) (hY_indep : iIndepFun Y μ) (hX_subG : ∀ i ∈ s, HasSubgaussianMGF (fun ω ↦ X i ω - μ[X i]) (cX i) μ) (hY_subG : ∀ j ∈ t, HasSubgaussianMGF (fun ω ↦ Y j ω - μ[Y j]) (cY j) μ) diff --git a/LeanMachineLearning/ForMathlib/Probability/Process/HittingTime.lean b/LeanMachineLearning/ForMathlib/Probability/Process/HittingTime.lean index 516b38ac..6c7b6e13 100644 --- a/LeanMachineLearning/ForMathlib/Probability/Process/HittingTime.lean +++ b/LeanMachineLearning/ForMathlib/Probability/Process/HittingTime.lean @@ -9,6 +9,8 @@ public import Mathlib.Probability.Process.HittingTime /-! # Hitting times + +Characterization of the event `hittingAfter u s n ω = i`. -/ @[expose] public section diff --git a/LeanMachineLearning/ForMathlib/Probability/WithDensity.lean b/LeanMachineLearning/ForMathlib/Probability/WithDensity.lean deleted file mode 100644 index 98050883..00000000 --- a/LeanMachineLearning/ForMathlib/Probability/WithDensity.lean +++ /dev/null @@ -1,79 +0,0 @@ -/- -Copyright (c) 2026 Paulo Rauber. All rights reserved. -Released under Apache 2.0 license as described in the file LICENSE. -Authors: Paulo Rauber --/ -module - -public import Mathlib.Probability.Kernel.CompProdEqIff -public import Mathlib.Probability.Kernel.Composition.MeasureComp -public import Mathlib.Probability.Kernel.Composition.WithDensity - -/-! # Lemmas about kernels and measures with density --/ - -@[expose] public section - -open MeasureTheory ProbabilityTheory - -open scoped ENNReal - -variable {α β γ : Type*} {mα : MeasurableSpace α} {mβ : MeasurableSpace β} {mγ : MeasurableSpace γ} -variable {μ : Measure α} - -namespace MeasureTheory - -lemma map_withDensity_comp {g : α → γ} {f : γ → ℝ≥0∞} (hg : Measurable g) (hf : Measurable f) : - (μ.withDensity (f ∘ g)).map g = (μ.map g).withDensity f := by - ext s hs - rw [Measure.map_apply hg hs, withDensity_apply _ (hg hs), withDensity_apply _ hs, - setLIntegral_map hs hf hg] - rfl - -lemma map_equiv_withDensity {e : α ≃ᵐ β} {f : α → ℝ≥0∞} (hf : Measurable f) : - (μ.withDensity f).map e = (μ.map e).withDensity (f ∘ e.symm) := by - simp_rw [← map_withDensity_comp e.measurable (hf.comp e.symm.measurable), - Function.comp_assoc, MeasurableEquiv.symm_comp_self] - rfl - -lemma map_swap_withDensity_comp_snd {μ : Measure (α × β)} {f : β → ℝ≥0∞} (hf : Measurable f) : - (μ.withDensity (fun ab ↦ f ab.2)).map Prod.swap = - (μ.map Prod.swap).withDensity (fun ba ↦ f ba.1) := by - rw [← map_withDensity_comp measurable_swap (by fun_prop)] - rfl - -end MeasureTheory - -namespace MeasureTheory.Measure - -lemma compProd_eq_compProd_withDensity_comp_snd [SFinite μ] {κ η : Kernel α β} [IsSFiniteKernel κ] - [IsSFiniteKernel η] {f : β → ℝ≥0∞} (hf : Measurable f) - (h : κ =ᵐ[μ] η.withDensity (fun _ b ↦ f b)) : - μ ⊗ₘ κ = (μ ⊗ₘ η).withDensity (fun ab ↦ f ab.2) := by - /- A proof based on `compProd_congr` requires `IsSFiniteKernel (η.withDensity fun _ b ↦ f b)`. -/ - refine ext_of_lintegral _ fun g hg ↦ ?_ - calc ∫⁻ ab, g ab ∂(μ ⊗ₘ κ) - = ∫⁻ a, ∫⁻ b, g (a, b) ∂κ a ∂μ := - lintegral_compProd hg - _ = ∫⁻ a, ∫⁻ b, g (a, b) ∂((η a).withDensity f) ∂μ := by - apply lintegral_congr_ae - filter_upwards [h] with a ha - rw [ha, Kernel.withDensity_apply _ (by fun_prop)] - _ = ∫⁻ a, ∫⁻ b, f b * g (a, b) ∂η a ∂μ := by - congr with a - exact lintegral_withDensity_eq_lintegral_mul _ hf (by fun_prop) - _ = ∫⁻ ab, f ab.2 * g ab ∂(μ ⊗ₘ η) := - (lintegral_compProd ((hf.comp measurable_snd).mul hg)).symm - _ = ∫⁻ ab, g ab ∂((μ ⊗ₘ η).withDensity (fun ab ↦ f ab.2)) := - (lintegral_withDensity_eq_lintegral_mul _ (hf.comp measurable_snd) hg).symm - -end MeasureTheory.Measure - -namespace ProbabilityTheory.Kernel - -lemma withDensity_rnDeriv_eq' {κ η : Kernel α β} [MeasurableSpace.CountableOrCountablyGenerated α β] - [IsFiniteKernel κ] [IsFiniteKernel η] (h : ∀ a, κ a ≪ η a) : - η.withDensity (κ.rnDeriv η) = κ := - Kernel.ext fun a ↦ withDensity_rnDeriv_eq (h a) - -end ProbabilityTheory.Kernel diff --git a/LeanMachineLearning/ForMathlib/Topology/Instances/ENNReal/Lemmas.lean b/LeanMachineLearning/ForMathlib/Topology/Instances/ENNReal/Lemmas.lean deleted file mode 100644 index ec179e6d..00000000 --- a/LeanMachineLearning/ForMathlib/Topology/Instances/ENNReal/Lemmas.lean +++ /dev/null @@ -1,28 +0,0 @@ -/- -Copyright (c) 2026 Gaëtan Serré. All rights reserved. -Released under Apache 2.0 license as described in the file LICENSE. -Authors: Gaëtan Serré --/ -module - -public import Mathlib.Topology.Order.Real - -/-! -# Lemmas about topology on `ℝ≥0∞`. --/ - -@[expose] public section - -open Filter - -open scoped Topology - -namespace ENNReal - -lemma tendsto_zero_of_le {α : Type*} {f g : α → ℝ≥0∞} {ι : Filter α} - (hg : Tendsto g ι (𝓝 0)) (h : f ≤ g) : Tendsto f ι (𝓝 0) := by - refine tendsto_of_tendsto_of_tendsto_of_le_of_le (g := fun _ ↦ 0) tendsto_const_nhds hg ?_ h - intro - simp - -end ENNReal diff --git a/LeanMachineLearning/Online/Bandit/Algorithms/ETC.lean b/LeanMachineLearning/Online/Bandit/Algorithms/ETC.lean index 6a28cc8f..cdee9e56 100644 --- a/LeanMachineLearning/Online/Bandit/Algorithms/ETC.lean +++ b/LeanMachineLearning/Online/Bandit/Algorithms/ETC.lean @@ -12,6 +12,27 @@ public import LeanMachineLearning.ForMathlib.MeasureTheory.Order.MeasurableArg /-! # The Explore-Then-Commit Algorithm +The Explore-Then-Commit (ETC) algorithm with parameter `m` for a bandit with `K` arms pulls each arm +`m` times in a round-robin fashion (exploration phase, up to time `K * m`), then pulls the arm with +the highest empirical mean at time `K * m` for all remaining rounds (commit phase). + +## Main definitions + +* `ETC.nextArm K m n h`: the arm pulled by ETC at time `n`, given the history `h` before `n`. +* `etcAlgorithm K m`: the ETC algorithm. + +## Main statements + +* `ETC.pullCount_of_ge`: for `n ≥ K * m`, the number of pulls of arm `a` at time `n` is `m`, plus + `n - K * m` if `a` is the arm chosen at time `K * m`. +* `ETC.sumRewards_bestArm_le_of_arm_mul_eq`: if arm `a` is chosen at time `K * m`, its sum of + rewards in the exploration phase is at least that of the best arm. + +## References + +* T. Lattimore and C. Szepesvári, *Bandit Algorithms*, Cambridge University Press, 2020, + Chapter 6. + -/ @[expose] public section @@ -59,12 +80,13 @@ variable [NeZero K] {m : ℕ} {ν : Kernel (Fin K) ℝ} [IsMarkovKernel ν] {P : Measure Ω} [IsProbabilityMeasure P] {O : ℕ → Ω → Unit} {A : ℕ → Ω → Fin K} {R : ℕ → Ω → ℝ} +omit [IsProbabilityMeasure P] in /-- Before round `K * m`, the ETC algorithm behaves like the Round-Robin algorithm. -/ -lemma isAlgEnvSeqUntil_roundRobinAlgorithm +lemma isAlgEnvSeqUntil_roundRobin (h : IsAlgEnvSeq O A R (etcAlgorithm K m) (Environment.bandit ν) P) : - IsAlgEnvSeqUntil O A R (roundRobinAlgorithm K) (Environment.bandit ν) P (K * m) := by + IsAlgEnvSeqUntil O A R (Algorithm.roundRobin K) (Environment.bandit ν) P (K * m) := by refine h.isAlgEnvSeqUntil_of_policy_eq fun n hn ↦ ?_ - simp only [roundRobinAlgorithm, Algorithm.deterministic_policy, etcAlgorithm] + simp only [Algorithm.roundRobin, Algorithm.deterministic_policy, etcAlgorithm] congr 1 with p simp [ETC.nextArm, hn] @@ -73,13 +95,13 @@ section AlgorithmBehavior lemma arm_ae_eq_nextArm (h : IsAlgEnvSeq O A R (etcAlgorithm K m) (Environment.bandit ν) P) (n : ℕ) : A n =ᵐ[P] fun ω ↦ nextArm K m n (history O A R n ω) := - h.action_deterministic_ae_eq n + h.action_ae_eq_deterministic n /-- For `n < K * m`, the arm pulled at time `n` is the arm `n % K`. -/ lemma arm_of_lt (h : IsAlgEnvSeq O A R (etcAlgorithm K m) (Environment.bandit ν) P) {n : ℕ} (hn : n < K * m) : A n =ᵐ[P] fun _ ↦ RoundRobin.nextAction K n := - RoundRobin.action_ae_eq n ((isAlgEnvSeqUntil_roundRobinAlgorithm h).mono hn) + RoundRobin.action_ae_eq n ((isAlgEnvSeqUntil_roundRobin h).mono hn) /-- The arm pulled at time `K * m` is the arm with the highest empirical mean after the exploration phase. -/ @@ -112,7 +134,7 @@ lemma arm_of_ge (h : IsAlgEnvSeq O A R (etcAlgorithm K m) (Environment.bandit ν lemma pullCount_mul (h : IsAlgEnvSeq O A R (etcAlgorithm K m) (Environment.bandit ν) P) (a : Fin K) : pullCount A a (K * m) =ᵐ[P] fun _ ↦ m := - RoundRobin.pullCount_mul m (isAlgEnvSeqUntil_roundRobinAlgorithm h) a + RoundRobin.pullCount_mul m (isAlgEnvSeqUntil_roundRobin h) a lemma pullCount_add_one_of_ge (h : IsAlgEnvSeq O A R (etcAlgorithm K m) (Environment.bandit ν) P) (a : Fin K) {n : ℕ} (hn : K * m ≤ n) : @@ -123,7 +145,8 @@ lemma pullCount_add_one_of_ge (h : IsAlgEnvSeq O A R (etcAlgorithm K m) (Environ congr 3 /-- For `n ≥ K * m`, the number of pulls of each arm `a` at time `n` is equal to `m` plus -`n - K * m` if arm `a` is the best arm after the exploration phase. -/ +`n - K * m` if arm `a` is the arm chosen at time `K * m` (the arm with the highest empirical mean +after the exploration phase). -/ lemma pullCount_of_ge (h : IsAlgEnvSeq O A R (etcAlgorithm K m) (Environment.bandit ν) P) (a : Fin K) {n : ℕ} (hn : K * m ≤ n) : pullCount A a n @@ -142,14 +165,17 @@ lemma pullCount_of_ge (h : IsAlgEnvSeq O A R (etcAlgorithm K m) (Environment.ban grind /-- If at time `K * m` the algorithm chooses arm `a`, then the total reward obtained by pulling -arm `a` is at least the total reward obtained by pulling the best arm. -/ +arm `a` before time `K * m` is at least the total reward obtained by pulling the best arm. -/ lemma sumRewards_bestArm_le_of_arm_mul_eq - (h : IsAlgEnvSeq O A R (etcAlgorithm K m) (Environment.bandit ν) P) (a : Fin K) (hm : m ≠ 0) : + (h : IsAlgEnvSeq O A R (etcAlgorithm K m) (Environment.bandit ν) P) (a : Fin K) : ∀ᵐ ω ∂P, A (K * m) ω = a → sumRewards A R (bestArm ν) (K * m) ω ≤ sumRewards A R a (K * m) ω := by + rcases eq_or_ne m 0 with rfl | hm + · simp [sumRewards] filter_upwards [arm_mul h, pullCount_mul h a, pullCount_mul h (bestArm ν)] with ω h_arm ha h_best h_eq - have h_max := isMaxOn_argmax (empMean' (K * m) (history O A R (K * m) ω)) (bestArm ν) + have h_max := isMaxOn_univ_iff.1 + (isMaxOn_argmax (empMean' (K * m) (history O A R (K * m) ω))) (bestArm ν) rw [← h_arm, h_eq] at h_max rw [sumRewards_eq_pullCount_mul_empMean, sumRewards_eq_pullCount_mul_empMean, ha, h_best] · gcongr diff --git a/LeanMachineLearning/Online/Bandit/Algorithms/Regret/BayesRegretTS.lean b/LeanMachineLearning/Online/Bandit/Algorithms/Regret/BayesRegretTS.lean index 9b7617ef..adaf07f5 100644 --- a/LeanMachineLearning/Online/Bandit/Algorithms/Regret/BayesRegretTS.lean +++ b/LeanMachineLearning/Online/Bandit/Algorithms/Regret/BayesRegretTS.lean @@ -1,12 +1,12 @@ /- Copyright (c) 2026 Paulo Rauber. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. -Authors: Paulo Rauber +Authors: Paulo Rauber, Rémy Degenne -/ module public import LeanMachineLearning.Online.Bandit.Algorithms.TS -public import LeanMachineLearning.Online.Bandit.SumRewards +public import LeanMachineLearning.Online.Bandit.Concentration /-! # Bayesian regret of Thompson sampling @@ -21,35 +21,159 @@ and properties are also given in this file. * `ucb A R l u σ2 δ a n` : clipped upper confidence bound used in the regret analysis of Thompson sampling for a sequence of actions `A : ℕ → Ω → Fin K`, rewards `R : ℕ → Ω → ℝ`, reward lower - bound `l : ℝ`, reward upper bound `u : ℝ`, sub-Gaussian variance proxy `σ2 : ℝ`, confidence + bound `l : ℝ`, reward upper bound `u : ℝ`, sub-Gaussian variance proxy `σ2 : ℝ≥0`, confidence parameter `δ : ℝ`, action `a : Fin K`, and time `n : ℕ`. * `ucb' n h l u σ2 δ a`: clipped upper confidence bound for action `a : Fin K` at time `n : ℕ` given - the history `h : Fin n → Fin K × ℝ` (rather than the entire sequences of actions and rewards). + the history `h : Hist Unit (Fin K) ℝ n` (rather than the entire sequences of actions and + rewards). -## Main results +## Main statements -* `integral_regret_le`: if Thompson sampling has the correct prior over environments and every - environment has `K` actions, each of which has a corresponding reward between `l` and `u` that - is sub-Gaussian with variance proxy `σ2` after its mean is subtracted, then the Bayesian regret at - time `n` is at most `(2 * K + 1) * (u - l) + 8 * √(σ2 * K * n * Real.log n)`. +* `IsBayesAlgEnvSeq.prob_empMean_sub_actionMean_ge_le`, + `IsBayesAlgEnvSeq.prob_empMean_bestAction_sub_actionMean_le_le`: for sub-Gaussian rewards, the + empirical means of the actions are close to their means with high probability, uniformly in + time. +* `TS.integral_regret_le`: if Thompson sampling has the correct prior over environments, in every + environment each of the `K` actions has a mean reward between `l` and `u`, and in almost every + environment (under the prior) the reward distribution of each action is sub-Gaussian with + variance proxy `σ2` after its mean is subtracted, then the Bayesian regret at time `n` is at most + `(2 * K + 1) * (u - l) + 8 * √(σ2 * K * n * log n)`. + +## Implementation notes + +The proof follows the upper confidence bound argument of Russo and Van Roy. Since the action played +and the best action have the same conditional law given the history, the upper confidence bounds +of the two actions have the same expectation, and the Bayesian regret is the sum of the expected +differences between the mean of the best action and its upper confidence bound, and between the +upper confidence bound and the mean of the action played (`TS.integral_regret_eq_add`). The first +sum is controlled by concentration, the second one by the widths of the confidence intervals. + +## References + +* D. Russo and B. Van Roy, *Learning to optimize via posterior sampling*, Mathematics of + Operations Research, 2014. +* T. Lattimore and C. Szepesvári, *Bandit Algorithms*, Cambridge University Press, 2020, + Theorem 36.1. -/ @[expose] public section open MeasureTheory ProbabilityTheory Finset Learning +open scoped NNReal + +/-! ### Concentration of the empirical means in a Bayesian bandit -/ + +namespace Learning.IsBayesAlgEnvSeq + +variable {𝓔 Ω : Type*} [MeasurableSpace 𝓔] [MeasurableSpace Ω] +variable {K : ℕ} [Nonempty (Fin K)] +variable {Q : Measure 𝓔} [IsProbabilityMeasure Q] {κ : Kernel (𝓔 × Fin K) ℝ} [IsMarkovKernel κ] +variable {alg : Algorithm Unit (Fin K) ℝ} +variable {E : Ω → 𝓔} {A : ℕ → Ω → (Fin K)} {R : ℕ → Ω → ℝ} +variable {P : Measure Ω} [IsProbabilityMeasure P] + +/-- Auxiliary lemma for `prob_empMean_sub_actionMean_ge_le`. -/ +private lemma sqrt_two_mul_le_sub {k : ℕ} (hk : k ≠ 0) {s μ σ l : ℝ} + (h : √(2 * σ * l / k) ≤ s / k - μ) : √(2 * k * σ * l) ≤ s - k * μ := by + have hkp : (0 : ℝ) < k := by positivity + calc √(2 * k * σ * l) + _ = √(2 * σ * l / k * k ^ 2) := by + field_simp + _ = √(2 * σ * l / k) * k := by + rw [Real.sqrt_mul' _ (sq_nonneg _), Real.sqrt_sq hkp.le] + _ ≤ (s / k - μ) * k := by + nlinarith + _ = s - k * μ := by + field_simp + +lemma prob_empMean_sub_actionMean_ge_le (h : IsBayesAlgEnvSeq Q κ alg E A R P) {σ2 : ℝ≥0} + (hs : ∀ᵐ e ∂Q, ∀ a, HasSubgaussianMGF (fun x ↦ x - (κ (e, a))[id]) σ2 (κ (e, a))) + (hσ2 : σ2 ≠ 0) {δ : ℝ} (hδ : 0 < δ) (n : ℕ) : + P {ω | ∃ t < n, ∃ a, pullCount A a t ω ≠ 0 ∧ + √(2 * σ2 * Real.log (1 / δ) / pullCount A a t ω) ≤ empMean A R a t ω - actionMean κ E a ω} + ≤ ENNReal.ofReal (K * (n - 1) * δ) := by + have := h.measurable_param + have := h.measurable_action + have := h.measurable_feedback + let S : Set (𝓔 × (ℕ → Round Unit (Fin K) ℝ)) := + {(e, τ) | ∃ a, ∃ t < n, pullCount IT.action a t τ ≠ 0 ∧ + √(2 * pullCount IT.action a t τ * σ2 * Real.log (1 / δ)) ≤ + sumRewards IT.action IT.feedback a t τ - pullCount IT.action a t τ * actionMean κ id a e} + calc + _ ≤ (P.map (fun ω ↦ (E ω, trajectory (noObs Ω) A R ω))) S := by + rw [Measure.map_apply (by fun_prop) (by measurability)] + apply measure_mono + intro ω ⟨t, ht, a, hpc, hle⟩ + rw [empMean] at hle + exact ⟨a, t, ht, hpc, sqrt_two_mul_le_sub hpc hle⟩ + _ = (P.map E ⊗ₘ condDistrib (trajectory (noObs Ω) A R) E P) S := by + rw [← compProd_map_condDistrib (by fun_prop) (by fun_prop)] + _ = ∫⁻ e, condDistrib (trajectory (noObs Ω) A R) E P e (Prod.mk e ⁻¹' S) ∂(P.map E) := + Measure.compProd_apply (by measurability) + _ ≤ ∫⁻ e, ENNReal.ofReal (Fintype.card (Fin K) * (n - 1) * δ) ∂(P.map E) := by + apply lintegral_mono_ae + rw [h.hasLaw_env.map_eq] + filter_upwards [h.ae_isAlgEnvSeq, hs] with e he hse + exact Bandits.prob_exists_sumRewards_sub_pullCount_mul_ge_le he hse hσ2 hδ + _ = ENNReal.ofReal (K * (n - 1) * δ) := by + simp [Measure.map_apply h.measurable_param] + +/-- Auxiliary lemma for `prob_empMean_bestAction_sub_actionMean_le_le`. -/ +private lemma sub_le_neg_sqrt_two_mul {k : ℕ} (hk : k ≠ 0) {s μ σ l : ℝ} + (h : s / k - μ ≤ -√(2 * σ * l / k)) : s - k * μ ≤ -√(2 * k * σ * l) := by + have : √(2 * k * σ * l) ≤ -s - k * -μ := sqrt_two_mul_le_sub hk (by grind) + linarith + +lemma prob_empMean_bestAction_sub_actionMean_le_le (h : IsBayesAlgEnvSeq Q κ alg E A R P) + {σ2 : ℝ≥0} (hs : ∀ᵐ e ∂Q, ∀ a, HasSubgaussianMGF (fun x ↦ x - (κ (e, a))[id]) σ2 (κ (e, a))) + (hσ2 : σ2 ≠ 0) {δ : ℝ} (hδ : 0 < δ) (n : ℕ) : + P {ω | ∃ t < n, pullCount A (bestAction κ E ω) t ω ≠ 0 ∧ + empMean A R (bestAction κ E ω) t ω - actionMean κ E (bestAction κ E ω) ω ≤ + -√(2 * σ2 * Real.log (1 / δ) / (pullCount A (bestAction κ E ω) t ω))} + ≤ ENNReal.ofReal ((n - 1) * δ) := by + have := h.measurable_param + have := h.measurable_action + have := h.measurable_feedback + let S : Set (𝓔 × (ℕ → Round Unit (Fin K) ℝ)) := + {(e, τ) | ∃ t < n, pullCount IT.action (bestAction κ id e) t τ ≠ 0 ∧ + sumRewards IT.action IT.feedback (bestAction κ id e) t τ - + pullCount IT.action (bestAction κ id e) t τ * actionMean κ id (bestAction κ id e) e ≤ + -√(2 * pullCount IT.action (bestAction κ id e) t τ * σ2 * Real.log (1 / δ))} + calc + _ ≤ (P.map (fun ω ↦ (E ω, trajectory (noObs Ω) A R ω))) S := by + rw [Measure.map_apply (by fun_prop) (by measurability)] + apply measure_mono + intro ω ⟨t, ht, hpc, hle⟩ + rw [empMean] at hle + exact ⟨t, ht, hpc, sub_le_neg_sqrt_two_mul hpc hle⟩ + _ = (P.map E ⊗ₘ condDistrib (trajectory (noObs Ω) A R) E P) S := by + rw [← compProd_map_condDistrib (by fun_prop) (by fun_prop)] + _ = ∫⁻ e, condDistrib (trajectory (noObs Ω) A R) E P e (Prod.mk e ⁻¹' S) ∂(P.map E) := + Measure.compProd_apply (by measurability) + _ ≤ ∫⁻ e, ENNReal.ofReal ((n - 1) * δ) ∂(P.map E) := by + apply lintegral_mono_ae + rw [h.hasLaw_env.map_eq] + filter_upwards [h.ae_isAlgEnvSeq, hs] with e he hse + exact Bandits.prob_sumRewards_sub_pullCount_mul_le_le (ν := κ.sectR e) he (hse _) hσ2 hδ + _ = ENNReal.ofReal ((n - 1) * δ) := by + simp [Measure.map_apply h.measurable_param] + +end Learning.IsBayesAlgEnvSeq + open IsBayesAlgEnvSeq (bestAction actionMean) namespace Bandits namespace ClippedUCB -variable {K : ℕ} {l u σ2 δ : ℝ} +variable {K : ℕ} {l u δ : ℝ} {σ2 : ℝ≥0} variable {Ω : Type*} {A : ℕ → Ω → Fin K} {R : ℕ → Ω → ℝ} /-- Clipped upper confidence bound used in the regret analysis of Thompson sampling. -/ noncomputable -def ucb (A : ℕ → Ω → Fin K) (R : ℕ → Ω → ℝ) (l u σ2 δ : ℝ) (a : Fin K) (n : ℕ) (ω : Ω) : ℝ := +def ucb (A : ℕ → Ω → Fin K) (R : ℕ → Ω → ℝ) (l u : ℝ) (σ2 : ℝ≥0) (δ : ℝ) (a : Fin K) (n : ℕ) + (ω : Ω) : ℝ := if pullCount A a n ω = 0 then u else max l (min u (empMean A R a n ω + √(2 * σ2 * Real.log (1 / δ) / (pullCount A a n ω)))) @@ -71,6 +195,7 @@ lemma measurable_ucb [MeasurableSpace Ω] {a : Fin K} {n : ℕ} (hA : ∀ t, Mea lemma measurable_uncurry_ucb_comp [MeasurableSpace Ω] (hA : ∀ t, Measurable (A t)) (hR : ∀ t, Measurable (R t)) {f : Ω → Fin K} (hf : Measurable f) {g : Ω → ℕ} (hg : Measurable g) : Measurable (fun ω ↦ ucb A R l u σ2 δ (f ω) (g ω) ω) := by + -- write the function as a composition with `fun ω ↦ (f ω, ω)`, then with `fun ω ↦ (g ω, ω)` change Measurable ((fun aω ↦ ucb A R l u σ2 δ aω.1 (g aω.2) aω.2) ∘ fun ω ↦ (f ω, ω)) apply Measurable.comp _ (by fun_prop) apply measurable_from_prod_countable_right @@ -93,7 +218,7 @@ lemma integrable_uncurry_ucb_comp [MeasurableSpace Ω] (hA : ∀ t, Measurable ( /-- Clipped upper confidence bound (history-based version). -/ noncomputable -def ucb' (n : ℕ) (h : Hist Unit (Fin K) ℝ n) (l u σ2 δ : ℝ) (a : Fin K) : ℝ := +def ucb' (n : ℕ) (h : Hist Unit (Fin K) ℝ n) (l u : ℝ) (σ2 : ℝ≥0) (δ : ℝ) (a : Fin K) : ℝ := if pullCount' n h a = 0 then u else max l (min u (empMean' n h a + √(2 * σ2 * Real.log (1 / δ) / (pullCount' n h a)))) @@ -133,11 +258,18 @@ private lemma sum_inv_sqrt_le {n : ℕ} (h : 0 < n) : ∑ k ∈ range (n + 1), 1 have : √n * √n = n := Real.mul_self_sqrt (by positivity) nlinarith -lemma sum_ucb_sub_mean_le {n : ℕ} {ω : Ω} (μ : Fin K → ℝ) (hμ : ∀ a, μ a ∈ Set.Icc l u) (hi : l ≤ u) +lemma sum_ucb_sub_mean_le {n : ℕ} {ω : Ω} (μ : Fin K → ℝ) (hμ : ∀ a, μ a ∈ Set.Icc l u) (hc : ∀ s < n, pullCount A (A s ω) s ω ≠ 0 → empMean A R (A s ω) s ω - μ (A s ω) < √(2 * σ2 * Real.log (1 / δ) / (pullCount A (A s ω) s ω))) : ∑ s ∈ range n, (ucb A R l u σ2 δ (A s ω) s ω - μ (A s ω)) ≤ (u - l) * K + 4 * √(2 * σ2 * Real.log (1 / δ) * K * n) := by + -- if `n = 0` both sides are `0` when `K = 0`, and otherwise `l ≤ u` follows from `hμ` + obtain hK | hK := K.eq_zero_or_pos + · subst hK + cases n with + | zero => simp + | succ n => exact (A 0 ω).elim0 + have hi : l ≤ u := Set.nonempty_Icc.mp ⟨_, hμ ⟨0, hK⟩⟩ let S₀ := {s ∈ range n | pullCount A (A s ω) s ω = 0} let S₁ := {s ∈ range n | pullCount A (A s ω) s ω ≠ 0} have hu : S₀ ∪ S₁ = range n := filter_union_filter_not_eq _ _ @@ -205,14 +337,19 @@ variable {P : Measure Ω} [IsProbabilityMeasure P] lemma integral_sum_range_actionMean_bestAction_sub_ucb_bestAction_le {alg : Algorithm Unit (Fin K) ℝ} (h : IsBayesAlgEnvSeq Q κ alg E A R P) - (hlu : l ≤ u) (hm : ∀ e a, (κ (e, a))[id] ∈ (Set.Icc l u)) (hσ2 : 0 < σ2) - (hs : ∀ e a, HasSubgaussianMGF (fun x ↦ x - (κ (e, a))[id]) ⟨σ2, hσ2.le⟩ (κ (e, a))) - (hδ : 0 < δ) (n : ℕ) : + (hm : ∀ e a, (κ (e, a))[id] ∈ (Set.Icc l u)) + (hs : ∀ᵐ e ∂Q, ∀ a, HasSubgaussianMGF (fun x ↦ x - (κ (e, a))[id]) σ2 (κ (e, a))) + (hσ2 : σ2 ≠ 0) (hδ : 0 < δ) (n : ℕ) : P[fun ω ↦ ∑ t ∈ range n, (actionMean κ E (bestAction κ E ω) ω - ucb A R l u σ2 δ (bestAction κ E ω) t ω)] ≤ (u - l) * (n - 1) * n * δ := by + obtain ⟨ω₀⟩ := nonempty_of_isProbabilityMeasure P + have hlu : l ≤ u := Set.nonempty_Icc.mp ⟨_, hm (E ω₀) (Classical.arbitrary _)⟩ by_cases hn : n = 0 · simp [hn] + -- `F` is the event on which the confidence interval of the best action fails at some time + -- `t < n`. On its complement, each term of the sum is nonpositive. On `F`, each term is at most + -- `u - l`, and `F` has probability at most `(n - 1) * δ`. let F := {ω | ∃ t < n, pullCount A (bestAction κ E ω) t ω ≠ 0 ∧ empMean A R (bestAction κ E ω) t ω - actionMean κ E (bestAction κ E ω) ω ≤ -√(2 * σ2 * Real.log (1 / δ) / (pullCount A (bestAction κ E ω) t ω))} @@ -247,19 +384,24 @@ lemma integral_sum_range_actionMean_bestAction_sub_ucb_bestAction_le gcongr have : (1 : ℝ) ≤ n := by simp [Nat.one_le_iff_ne_zero, hn] apply ENNReal.toReal_le_of_le_ofReal (by nlinarith) - exact h.prob_empMean_bestAction_sub_actionMean_le_le hσ2 hs hδ n + exact h.prob_empMean_bestAction_sub_actionMean_le_le hs hσ2 hδ n _ = _ := by ring lemma integral_sum_range_ucb_action_sub_actionMean_action_le {alg : Algorithm Unit (Fin K) ℝ} (h : IsBayesAlgEnvSeq Q κ alg E A R P) - (hlu : l ≤ u) (hm : ∀ e a, (κ (e, a))[id] ∈ (Set.Icc l u)) (hσ2 : 0 < σ2) - (hs : ∀ e a, HasSubgaussianMGF (fun x ↦ x - (κ (e, a))[id]) ⟨σ2, hσ2.le⟩ (κ (e, a))) - (hδ : 0 < δ) (n : ℕ) : + (hm : ∀ e a, (κ (e, a))[id] ∈ (Set.Icc l u)) + (hs : ∀ᵐ e ∂Q, ∀ a, HasSubgaussianMGF (fun x ↦ x - (κ (e, a))[id]) σ2 (κ (e, a))) + (hσ2 : σ2 ≠ 0) (hδ : 0 < δ) (n : ℕ) : P[fun ω ↦ ∑ t ∈ range n, (ucb A R l u σ2 δ (A t ω) t ω - actionMean κ E (A t ω) ω)] ≤ (u - l) * K + 4 * √(2 * σ2 * Real.log (1 / δ) * K * n) + (u - l) * K * (n - 1) * n * δ := by + obtain ⟨ω₀⟩ := nonempty_of_isProbabilityMeasure P + have hlu : l ≤ u := Set.nonempty_Icc.mp ⟨_, hm (E ω₀) (Classical.arbitrary _)⟩ by_cases hn : n = 0 · simp [hn, hlu, mul_nonneg] + -- `F` is the event on which the confidence interval of some action fails at some time `t < n`. + -- On `F`, each term of the sum is at most `u - l`, and `F` has probability at most + -- `K * (n - 1) * δ`. On its complement, the sum is bounded by `sum_ucb_sub_mean_le`. let F := {ω | ∃ t < n, ∃ a, pullCount A a t ω ≠ 0 ∧ √(2 * σ2 * Real.log (1 / δ) / pullCount A a t ω) ≤ empMean A R a t ω - actionMean κ E a ω} have := h.measurable_action @@ -284,7 +426,7 @@ lemma integral_sum_range_ucb_action_sub_actionMean_action_le {alg : Algorithm Un intro ω hω rw [Set.mem_compl_iff, Set.mem_ofPred_eq] at hω push Not at hω - exact sum_ucb_sub_mean_le (fun a ↦ (κ (E ω, a))[id]) (hm (E ω)) hlu + exact sum_ucb_sub_mean_le (fun a ↦ (κ (E ω, a))[id]) (hm (E ω)) (fun t ht hpc ↦ hω t ht (A t ω) hpc) _ = P.real F * (n * (u - l)) + P.real Fᶜ * ((u - l) * K + 4 * √(2 * σ2 * Real.log (1 / δ) * K * n)) := by @@ -295,7 +437,7 @@ lemma integral_sum_range_ucb_action_sub_actionMean_action_le {alg : Algorithm Un gcongr · have : (0 : ℝ) ≤ n - 1 := by simp [Nat.one_le_iff_ne_zero, hn] apply ENNReal.toReal_le_of_le_ofReal (by positivity) - exact h.prob_empMean_sub_actionMean_ge_le hσ2 hs hδ n + exact h.prob_empMean_sub_actionMean_ge_le hs hσ2 hδ n · exact measureReal_le_one _ = _ := by ring @@ -307,7 +449,7 @@ namespace TS open ClippedUCB variable {K : ℕ} [NeZero K] -variable {l u σ2 δ : ℝ} +variable {l u δ : ℝ} {σ2 : ℝ≥0} variable {Ω : Type*} [MeasurableSpace Ω] variable {𝓔 : Type*} [MeasurableSpace 𝓔] [StandardBorelSpace 𝓔] [Nonempty 𝓔] variable {Q : Measure 𝓔} [IsProbabilityMeasure Q] {κ : Kernel (𝓔 × Fin K) ℝ} [IsMarkovKernel κ] @@ -330,7 +472,7 @@ lemma integral_ucb_action_eq_integral_ucb_bestAction _ = ∫ ha, uc ha ∂P.map (fun ω ↦ (history (noObs Ω) A R n ω, bestAction κ E ω)) := by rw [← compProd_map_condDistrib (by fun_prop) (by fun_prop), ← compProd_map_condDistrib (by fun_prop) (by fun_prop), - Measure.compProd_congr (hasCondDistrib_action h n).condDistrib_eq] + Measure.compProd_congr (hasCondDistrib_action h n).condDistrib_ae_eq] _ = P[fun ω ↦ ucb A R l u σ2 δ (bestAction κ E ω) n ω] := by rw [integral_map (by fun_prop) (by fun_prop)] simp_rw [uc, ucb_eq_ucb' (O := noObs Ω)] @@ -374,15 +516,18 @@ lemma integral_regret_eq_add (h : IsBayesAlgEnvSeq Q κ (tsAlgorithm Q κ) E A R _ = _ := by rw [← integral_finsetSum _ (by fun_prop), ← integral_finsetSum _ (by fun_prop)] -/-- If Thompson sampling has the correct prior over environments and every environment has `K` -actions, each of which has a corresponding reward between `l` and `u` that is sub-Gaussian with -variance proxy `σ2` after its mean is subtracted, then the Bayesian regret at time `n` is at most -`(2 * K + 1) * (u - l) + 8 * √(σ2 * K * n * Real.log n)`. -/ +/-- **Bayesian regret of Thompson sampling.** If Thompson sampling has the correct prior over +environments, in every environment each of the `K` actions has a mean reward between `l` and `u`, +and in almost every environment (under the prior) the reward distribution of each action is +sub-Gaussian with variance proxy `σ2` after its mean is subtracted, then the Bayesian regret at +time `n` is at most `(2 * K + 1) * (u - l) + 8 * √(σ2 * K * n * Real.log n)`. -/ theorem integral_regret_le (h : IsBayesAlgEnvSeq Q κ (tsAlgorithm Q κ) E A R P) - (hlu : l ≤ u) (hm : ∀ e a, (κ (e, a))[id] ∈ (Set.Icc l u)) (hσ2 : 0 < σ2) - (hs : ∀ e a, HasSubgaussianMGF (fun x ↦ x - (κ (e, a))[id]) ⟨σ2, hσ2.le⟩ (κ (e, a))) (n : ℕ) : + (hm : ∀ e a, (κ (e, a))[id] ∈ (Set.Icc l u)) + (hs : ∀ᵐ e ∂Q, ∀ a, HasSubgaussianMGF (fun x ↦ x - (κ (e, a))[id]) σ2 (κ (e, a))) + (hσ2 : σ2 ≠ 0) (n : ℕ) : P[IsBayesAlgEnvSeq.regret κ E A n] ≤ (2 * K + 1) * (u - l) + 8 * √(σ2 * K * n * Real.log n) := by + have hlu : l ≤ u := Set.nonempty_Icc.mp ⟨_, hm (Classical.arbitrary 𝓔) 0⟩ by_cases hn : n = 0 · simp [hn, IsBayesAlgEnvSeq.regret, Bandits.regret] nlinarith @@ -392,8 +537,8 @@ theorem integral_regret_le (h : IsBayesAlgEnvSeq Q κ (tsAlgorithm Q κ) E A R P integral_regret_eq_add h hm n _ ≤ _ := add_le_add - (integral_sum_range_actionMean_bestAction_sub_ucb_bestAction_le h hlu hm hσ2 hs hδ n) - (integral_sum_range_ucb_action_sub_actionMean_action_le h hlu hm hσ2 hs hδ n) + (integral_sum_range_actionMean_bestAction_sub_ucb_bestAction_le h hm hs hσ2 hδ n) + (integral_sum_range_ucb_action_sub_actionMean_action_le h hm hs hσ2 hδ n) _ = K * (u - l) + (K + 1) * (u - l) * ((n - 1) / n) + 4 * √((2 : ℝ) ^ 2 * (σ2 * K * n * Real.log n)) := by field_simp diff --git a/LeanMachineLearning/Online/Bandit/Algorithms/Regret/ETC.lean b/LeanMachineLearning/Online/Bandit/Algorithms/Regret/ETC.lean index c5a40cfc..f321c879 100644 --- a/LeanMachineLearning/Online/Bandit/Algorithms/Regret/ETC.lean +++ b/LeanMachineLearning/Online/Bandit/Algorithms/Regret/ETC.lean @@ -6,10 +6,21 @@ Authors: Rémy Degenne module public import LeanMachineLearning.Online.Bandit.Algorithms.ETC -public import LeanMachineLearning.Online.Bandit.SumRewards +public import LeanMachineLearning.Online.Bandit.Concentration /-! # Regret bound for the Explore-Then-Commit algorithm +## Main statements + +* `ETC.regret_le`: for `σ2`-sub-Gaussian rewards and `K * m ≤ n`, the expected regret of ETC with + parameter `m` at time `n` is at most + `∑ a, Δₐ * (m + (n - K * m) * exp (- m * Δₐ ^ 2 / (4 * σ2)))`, where `Δₐ = gap ν a`. + +## References + +* T. Lattimore and C. Szepesvári, *Bandit Algorithms*, Cambridge University Press, 2020, + Theorem 6.1. + -/ @[expose] public section @@ -30,7 +41,7 @@ lemma probReal_sumRewards_le_sumRewards_le (hν : ∀ a, HasSubgaussianMGF (fun x ↦ x - (ν a)[id]) σ2 (ν a)) (a : Fin K) : P.real {ω | sumRewards A R (bestArm ν) (K * m) ω ≤ sumRewards A R a (K * m) ω} ≤ Real.exp (-↑m * gap ν a ^ 2 / (4 * σ2)) := by - have h1 := Bandits.probReal_sumRewards_le_sumRewards_le h a (K * m) m m + have h1 := Bandits.probReal_sumRewards_le_sumRewards_le h (bestArm ν) a (K * m) m m have h2 := probReal_sum_le_sum_streamMeasure hν a m refine le_trans (le_of_eq ?_) (h1.trans h2) simp_rw [measureReal_def] @@ -43,23 +54,21 @@ lemma probReal_sumRewards_le_sumRewards_le /-- The probability that at time `K * m` the ETC algorithm chooses arm `a` is at most `exp(- m * Δ_a^2 / (4 * σ2))`. -/ lemma prob_arm_mul_eq_le (h : IsAlgEnvSeq O A R (etcAlgorithm K m) (Environment.bandit ν) P) - (hν : ∀ a, HasSubgaussianMGF (fun x ↦ x - (ν a)[id]) σ2 (ν a)) (a : Fin K) - (hm : m ≠ 0) : + (hν : ∀ a, HasSubgaussianMGF (fun x ↦ x - (ν a)[id]) σ2 (ν a)) (a : Fin K) : P.real {ω | A (K * m) ω = a} ≤ Real.exp (- (m : ℝ) * gap ν a ^ 2 / (4 * σ2)) := by - have h_pos : 0 < K * m := Nat.mul_pos (Nat.pos_of_neZero K) hm.bot_lt have h_le : P.real {ω | A (K * m) ω = a} ≤ P.real {ω | sumRewards A R (bestArm ν) (K * m) ω ≤ sumRewards A R a (K * m) ω} := by simp_rw [measureReal_def] gcongr 1 · simp refine measure_mono_ae ?_ - exact sumRewards_bestArm_le_of_arm_mul_eq h a hm + exact sumRewards_bestArm_le_of_arm_mul_eq h a exact h_le.trans (probReal_sumRewards_le_sumRewards_le h hν a) /-- Bound on the expectation of the number of pulls of each arm by the ETC algorithm. -/ -lemma expectation_pullCount_le (h : IsAlgEnvSeq O A R (etcAlgorithm K m) (Environment.bandit ν) P) +lemma integral_pullCount_le (h : IsAlgEnvSeq O A R (etcAlgorithm K m) (Environment.bandit ν) P) (hν : ∀ a, HasSubgaussianMGF (fun x ↦ x - (ν a)[id]) σ2 (ν a)) - (a : Fin K) (hm : m ≠ 0) {n : ℕ} (hn : K * m ≤ n) : + (a : Fin K) {n : ℕ} (hn : K * m ≤ n) : P[fun ω ↦ (pullCount A a n ω : ℝ)] ≤ m + (n - K * m) * Real.exp (- (m : ℝ) * gap ν a ^ 2 / (4 * σ2)) := by have hA := h.measurable_action @@ -81,16 +90,17 @@ lemma expectation_pullCount_le (h : IsAlgEnvSeq O A R (etcAlgorithm K m) (Enviro simp rw [integral_indicator_one] · rw [← neg_mul] - exact prob_arm_mul_eq_le h hν a hm + exact prob_arm_mul_eq_le h hν a · exact (measurableSet_singleton _).preimage (by fun_prop) -/-- Regret bound for the ETC algorithm. -/ +/-- Regret bound for the ETC algorithm with parameter `m`, for `σ2`-sub-Gaussian rewards and +`K * m ≤ n`. -/ theorem regret_le (h : IsAlgEnvSeq O A R (etcAlgorithm K m) (Environment.bandit ν) P) - (hν : ∀ a, HasSubgaussianMGF (fun x ↦ x - (ν a)[id]) σ2 (ν a)) (hm : m ≠ 0) + (hν : ∀ a, HasSubgaussianMGF (fun x ↦ x - (ν a)[id]) σ2 (ν a)) (n : ℕ) (hn : K * m ≤ n) : P[regret ν A n] ≤ ∑ a, gap ν a * (m + (n - K * m) * Real.exp (- (m : ℝ) * gap ν a ^ 2 / (4 * σ2))) := - integral_regret_le_of_forall_integral_pullCount_le h - (fun a _ ↦ expectation_pullCount_le h hν a hm hn) + integral_regret_le_of_forall_integral_pullCount_le h.measurable_action + (fun a _ ↦ integral_pullCount_le h hν a hn) end Bandits.ETC diff --git a/LeanMachineLearning/Online/Bandit/Algorithms/Regret/UCB.lean b/LeanMachineLearning/Online/Bandit/Algorithms/Regret/UCB.lean index 275e3dba..5ac5c0b0 100644 --- a/LeanMachineLearning/Online/Bandit/Algorithms/Regret/UCB.lean +++ b/LeanMachineLearning/Online/Bandit/Algorithms/Regret/UCB.lean @@ -8,11 +8,28 @@ module public import Mathlib.Analysis.SpecialFunctions.Integrals.Basic public import Mathlib.Analysis.SumIntegralComparisons public import LeanMachineLearning.Online.Bandit.Algorithms.UCB -public import LeanMachineLearning.Online.Bandit.SumRewards +public import LeanMachineLearning.Online.Bandit.Concentration /-! # Regret bounds for the UCB algorithm +## Main statements + +* `UCB.integral_pullCount_le`: for `σ2`-sub-Gaussian rewards, the expected number of pulls at time + `n` of an arm `a` with positive gap `Δₐ` by UCB with exploration parameter `c * σ2` is at most + `8 * c * σ2 * log (n + 1) / Δₐ ^ 2 + 2 + 2 * constSum c n`. +* `UCB.regret_le_of_gt_two`: for `σ2`-sub-Gaussian rewards and an exploration parameter + `c > 2 * σ2`, the expected regret of UCB at time `n` is at most + `∑ a, (8 * c * log (n + 1) / Δₐ + Δₐ * (4 + 2 * σ2 / (c - 2 * σ2)))`. The term of an arm with + gap `0` is `0` (by the convention `x / 0 = 0`). + +## References + +* P. Auer, N. Cesa-Bianchi and P. Fischer, *Finite-time analysis of the multiarmed bandit problem*, + Machine Learning, 2002. +* T. Lattimore and C. Szepesvári, *Bandit Algorithms*, Cambridge University Press, 2020, + Chapter 7. + -/ @[expose] public section @@ -149,6 +166,7 @@ lemma pullCount_le_add_three (a : Fin K) (n C : ℕ) (ω : Ω) : let C' := {s | C < pullCount A a s ω ∧ empMean A R (bestArm ν) s ω + ucbWidth A c (bestArm ν) s ω < (ν (bestArm ν))[id]} let D := {s | C < pullCount A a s ω ∧ (ν a)[id] < empMean A R a s ω - ucbWidth A c a s ω} + -- fold the sets `A'`, `B`, `C'` and `D` change ∑ s ∈ range n, A'.indicator 1 s ≤ ∑ s ∈ range n, B.indicator 1 s + ∑ s ∈ range n, C'.indicator 1 s + ∑ s ∈ range n, D.indicator 1 s @@ -296,18 +314,16 @@ lemma constSum_le {c : ℝ} (hc : 2 < c) (n : ℕ) : constSum c n ≤ 1 + 1 / (c _ ≤ 1 + 1 / (c - 2) := by gcongr; linarith /-- Bound on the expectation of the number of pulls of each arm by the UCB algorithm. -/ -lemma expectation_pullCount_le' +lemma lintegral_pullCount_le (h : IsAlgEnvSeq O A R (ucbAlgorithm K (c * σ2)) (Environment.bandit ν) P) (hν : ∀ a, HasSubgaussianMGF (fun x ↦ x - (ν a)[id]) σ2 (ν a)) - (hσ2 : σ2 ≠ 0) (hc : 0 < c) (a : Fin K) (h_gap : 0 < gap ν a) (n : ℕ) : + (hσ2 : σ2 ≠ 0) (hc : 0 ≤ c) (a : Fin K) (h_gap : 0 < gap ν a) (n : ℕ) : ∫⁻ ω, pullCount A a n ω ∂P ≤ ENNReal.ofReal (8 * c * σ2 * log (n + 1) / gap ν a ^ 2 + 1) + 1 + 2 * ENNReal.ofReal (constSum c n) := by have hA := h.measurable_action have hR := h.measurable_feedback - by_cases hn_zero : n = 0 - · simp [hn_zero] - let C a : ℕ := ⌈8 * c * σ2 * log (n + 1) / gap ν a ^ 2⌉₊ + let C a : ℕ := max 1 ⌈8 * c * σ2 * log (n + 1) / gap ν a ^ 2⌉₊ have h_set_1 b : MeasurableSet {ω | 0 < pullCount A a b ω ∧ (ν a)[id] < empMean A R a b ω - ucbWidth A (c * σ2) a b ω} := by simp only [measurableSet_setOfPred] @@ -335,11 +351,10 @@ lemma expectation_pullCount_le' {s | 0 < pullCount A a s ω ∧ (ν a)[id] < empMean A R a s ω - ucbWidth A (c * σ2) a s ω}.indicator (1 : ℕ → ℕ) s ∂P := by refine lintegral_mono_ae ?_ - have hCa : C a ≠ 0 := by - simp only [ne_eq, Nat.ceil_eq_zero, not_le, C] - have : 0 < log (n + 1) := log_pos (by simp; grind) - positivity - filter_upwards [pullCount_ae_le_add_two h hc.le a h_gap n (C a) hCa (Nat.le_ceil _)] with ω hω + have hCa : C a ≠ 0 := (zero_lt_one.trans_le (le_max_left _ _)).ne' + have hC_le : 8 * c * σ2 * log (n + 1) / gap ν a ^ 2 ≤ C a := + (Nat.le_ceil _).trans (Nat.cast_le.mpr (le_max_right _ _)) + filter_upwards [pullCount_ae_le_add_two h hc a h_gap n (C a) hCa hC_le] with ω hω simp only [id_eq, Nat.cast_sum] norm_cast _ ≤ (C a : ℝ≥0∞) + 1 + @@ -377,19 +392,21 @@ lemma expectation_pullCount_le' simp only [C] rw [← ENNReal.ofReal_natCast] refine ENNReal.ofReal_le_ofReal ?_ - refine (Nat.ceil_lt_add_one ?_).le - have : 0 ≤ log (n + 1) := log_nonneg (by simp) - positivity + have : 0 ≤ 8 * c * σ2 * log (n + 1) / gap ν a ^ 2 := by + have : 0 ≤ log (n + 1) := log_nonneg (by simp) + positivity + rw [Nat.cast_max, Nat.cast_one] + exact max_le (by linarith) (Nat.ceil_lt_add_one this).le /-- Bound on the expectation of the number of pulls of each arm by the UCB algorithm. -/ -lemma expectation_pullCount_le +lemma integral_pullCount_le (h : IsAlgEnvSeq O A R (ucbAlgorithm K (c * σ2)) (Environment.bandit ν) P) (hν : ∀ a, HasSubgaussianMGF (fun x ↦ x - (ν a)[id]) σ2 (ν a)) - (hσ2 : σ2 ≠ 0) (hc : 0 < c) (a : Fin K) (h_gap : 0 < gap ν a) (n : ℕ) : + (hσ2 : σ2 ≠ 0) (hc : 0 ≤ c) (a : Fin K) (h_gap : 0 < gap ν a) (n : ℕ) : P[fun ω ↦ (pullCount A a n ω : ℝ)] ≤ 8 * c * σ2 * log (n + 1) / gap ν a ^ 2 + 2 + 2 * constSum c n := by have hA := h.measurable_action - have h := expectation_pullCount_le' h hν hσ2 hc a h_gap n + have h := lintegral_pullCount_le h hν hσ2 hc a h_gap n simp_rw [← ENNReal.ofReal_natCast] at h rw [← ofReal_integral_eq_lintegral_ofReal] at h rotate_left @@ -404,49 +421,52 @@ lemma expectation_pullCount_le refine h.trans_eq ?_ ring -/-- Regret bound for the UCB algorithm. -/ -lemma regret_le (h : IsAlgEnvSeq O A R (ucbAlgorithm K (c * σ2)) (Environment.bandit ν) P) +/-- Regret bound for the UCB algorithm with exploration parameter `c * σ2`, for `σ2`-sub-Gaussian +rewards. -/ +lemma regret_le' (h : IsAlgEnvSeq O A R (ucbAlgorithm K (c * σ2)) (Environment.bandit ν) P) (hν : ∀ a, HasSubgaussianMGF (fun x ↦ x - (ν a)[id]) σ2 (ν a)) - (hσ2 : σ2 ≠ 0) (hc : 0 < c) (n : ℕ) : + (hσ2 : σ2 ≠ 0) (hc : 0 ≤ c) (n : ℕ) : P[regret ν A n] ≤ ∑ a, (8 * c * σ2 * log (n + 1) / gap ν a + gap ν a * (2 + 2 * constSum c n)) := by - refine (integral_regret_le_of_forall_integral_pullCount_le h - (fun a h_gap ↦ expectation_pullCount_le h hν hσ2 hc a + refine (integral_regret_le_of_forall_integral_pullCount_le h.measurable_action + (fun a h_gap ↦ integral_pullCount_le h hν hσ2 hc a (lt_of_le_of_ne' gap_nonneg h_gap) n)).trans_eq ?_ congr with a by_cases h_gap : gap ν a = 0 · simp [h_gap] · field -/-- Regret bound for the UCB algorithm with an explicit constant, for `c > 2`. -/ -lemma regret_le_of_gt_two (h : IsAlgEnvSeq O A R (ucbAlgorithm K (c * σ2)) (Environment.bandit ν) P) +/-- Regret bound for the UCB algorithm with exploration parameter `c * σ2`, for `σ2`-sub-Gaussian +rewards and `c > 2`, with an explicit constant. -/ +lemma regret_le_of_gt_two' + (h : IsAlgEnvSeq O A R (ucbAlgorithm K (c * σ2)) (Environment.bandit ν) P) (hν : ∀ a, HasSubgaussianMGF (fun x ↦ x - (ν a)[id]) σ2 (ν a)) (hσ2 : σ2 ≠ 0) (hc : 2 < c) (n : ℕ) : P[regret ν A n] ≤ ∑ a, (8 * c * σ2 * log (n + 1) / gap ν a + gap ν a * (4 + 2 / (c - 2))) := by - refine (regret_le h hν hσ2 (by linarith) n).trans (Finset.sum_le_sum fun a _ ↦ ?_) + refine (regret_le' h hν hσ2 (by linarith) n).trans (Finset.sum_le_sum fun a _ ↦ ?_) have h_le : 2 + 2 * constSum c n ≤ 4 + 2 / (c - 2) := by have := constSum_le hc n rw [show (4 : ℝ) + 2 / (c - 2) = 2 + 2 * (1 + 1 / (c - 2)) by ring] gcongr exact add_le_add le_rfl (mul_le_mul_of_nonneg_left h_le (gap_nonneg (ν := ν) (a := a))) -/-- Regret bound for the UCB algorithm with exploration constant `c`, -for `σ2`-subgaussian rewards. -/ -lemma regret_le' (h : IsAlgEnvSeq O A R (ucbAlgorithm K c) (Environment.bandit ν) P) +/-- Regret bound for the UCB algorithm with exploration parameter `c`, for `σ2`-sub-Gaussian +rewards. -/ +lemma regret_le (h : IsAlgEnvSeq O A R (ucbAlgorithm K c) (Environment.bandit ν) P) (hν : ∀ a, HasSubgaussianMGF (fun x ↦ x - (ν a)[id]) σ2 (ν a)) - (hσ2 : σ2 ≠ 0) (hc : 0 < c) (n : ℕ) : + (hσ2 : σ2 ≠ 0) (hc : 0 ≤ c) (n : ℕ) : P[regret ν A n] ≤ ∑ a, (8 * c * log (n + 1) / gap ν a + gap ν a * (2 + 2 * constSum (c / σ2) n)) := by have hσ2' : (0 : ℝ) < σ2 := NNReal.coe_pos.mpr (pos_iff_ne_zero.mpr hσ2) have h' : IsAlgEnvSeq O A R (ucbAlgorithm K (c / σ2 * σ2)) (Environment.bandit ν) P := by rwa [div_mul_cancel₀ _ hσ2'.ne'] - refine (regret_le h' hν hσ2 (div_pos hc hσ2') n).trans_eq ?_ + refine (regret_le' h' hν hσ2 (div_nonneg hc hσ2'.le) n).trans_eq ?_ rw [show (8 : ℝ) * (c / σ2) * σ2 = 8 * c by rw [mul_assoc, div_mul_cancel₀ _ hσ2'.ne']] -/-- Regret bound for the UCB algorithm with exploration constant `c > 2 * σ2`, for `σ2`-subgaussian -rewards, with an explicit constant. -/ -theorem regret_le_of_gt_two' (h : IsAlgEnvSeq O A R (ucbAlgorithm K c) (Environment.bandit ν) P) +/-- Regret bound for the UCB algorithm with exploration parameter `c > 2 * σ2`, for +`σ2`-sub-Gaussian rewards, with an explicit constant. -/ +theorem regret_le_of_gt_two (h : IsAlgEnvSeq O A R (ucbAlgorithm K c) (Environment.bandit ν) P) (hν : ∀ a, HasSubgaussianMGF (fun x ↦ x - (ν a)[id]) σ2 (ν a)) (hσ2 : σ2 ≠ 0) (hc : 2 * σ2 < c) (n : ℕ) : P[regret ν A n] ≤ @@ -455,7 +475,7 @@ theorem regret_le_of_gt_two' (h : IsAlgEnvSeq O A R (ucbAlgorithm K c) (Environm have h' : IsAlgEnvSeq O A R (ucbAlgorithm K (c / σ2 * σ2)) (Environment.bandit ν) P := by rwa [div_mul_cancel₀ _ hσ2'.ne'] have hc' : 2 < c / σ2 := by rwa [lt_div_iff₀ hσ2'] - refine (regret_le_of_gt_two h' hν hσ2 hc' n).trans_eq ?_ + refine (regret_le_of_gt_two' h' hν hσ2 hc' n).trans_eq ?_ rw [show (8 : ℝ) * (c / σ2) * σ2 = 8 * c by rw [mul_assoc, div_mul_cancel₀ _ hσ2'.ne'], show c / σ2 - 2 = (c - 2 * σ2) / σ2 by rw [sub_div, mul_div_assoc, div_self hσ2'.ne', mul_one], div_div_eq_mul_div] diff --git a/LeanMachineLearning/Online/Bandit/Algorithms/TS.lean b/LeanMachineLearning/Online/Bandit/Algorithms/TS.lean index 12a46b0f..842f8f68 100644 --- a/LeanMachineLearning/Online/Bandit/Algorithms/TS.lean +++ b/LeanMachineLearning/Online/Bandit/Algorithms/TS.lean @@ -20,14 +20,23 @@ probability of being optimal under the posterior over environments given the his * `tsAlgorithm Q κ`: a Thompson sampling algorithm with actions in `Fin K` (for `K ≠ 0`), given a prior distribution over parameters `Q : Measure 𝓔` and a Markov kernel `κ : Kernel (𝓔 × Fin K) ℝ`. This kernel defines how a parameter `e : 𝓔` gives rise to - a stationary environment: `Environment.bandit (κ.sectR e) : Environment (Fin K) ℝ`. + a stationary environment: `Environment.bandit (κ.sectR e) : Environment Unit (Fin K) ℝ`. -## Main results +## Main statements -* `hasCondDistrib_action` : if Thompson sampling has the correct prior over environments, then +* `TS.hasCondDistrib_action`: if Thompson sampling has the correct prior over environments, then the conditional distribution of the next action given the history so far is equal to the conditional distribution of the best action given the history so far. +## References + +* W. R. Thompson, *On the likelihood that one unknown probability exceeds another in view of the + evidence of two samples*, Biometrika, 1933. +* D. Russo and B. Van Roy, *Learning to optimize via posterior sampling*, Mathematics of + Operations Research, 2014. +* T. Lattimore and C. Szepesvári, *Bandit Algorithms*, Cambridge University Press, 2020, + Chapter 36. + -/ @[expose] public section @@ -48,23 +57,23 @@ The posterior under a uniform algorithm is used to avoid a circular definition. noncomputable def TS.policy [NeZero K] (Q : Measure 𝓔) [IsProbabilityMeasure Q] (κ : Kernel (𝓔 × Fin K) ℝ) [IsMarkovKernel κ] (n : ℕ) : Kernel (Hist Unit (Fin K) ℝ n × Unit) (Fin K) := - (((IT.bayesTrajMeasurePosterior Q κ uniformAlgorithm n).map + (((IT.bayesTrajMeasurePosterior Q κ Algorithm.uniform n).map (bestAction κ id)).prodMkRight Unit) instance [NeZero K] {Q : Measure 𝓔} [IsProbabilityMeasure Q] {κ : Kernel (𝓔 × Fin K) ℝ} [IsMarkovKernel κ] {n : ℕ} : IsMarkovKernel (TS.policy Q κ n) := by - have : IsMarkovKernel ((IT.bayesTrajMeasurePosterior Q κ uniformAlgorithm n).map + have : IsMarkovKernel ((IT.bayesTrajMeasurePosterior Q κ Algorithm.uniform n).map (bestAction κ id)) := Kernel.IsMarkovKernel.map _ (by fun_prop) unfold TS.policy infer_instance /-- The Thompson sampling algorithm with actions in `Fin K`, where `Q : Measure 𝓔` is a prior - distribution over parameters, and `κ : Kernel (𝓔 × Fin K) ℝ` is a Markov kernel that defines the - stationary environment `Environment.bandit (κ.sectR e)` that corresponds to a parameter `e : 𝓔`. +distribution over parameters, and `κ : Kernel (𝓔 × Fin K) ℝ` is a Markov kernel that defines the +stationary environment `Environment.bandit (κ.sectR e)` that corresponds to a parameter `e : 𝓔`. - At every time `n`, the Thompson sampling policy uses the posterior over the parameters given the - history up to time `n` to derive the probability of each action being optimal. The action for time - `n` is sampled according to these probabilities. -/ +At every time `n`, the Thompson sampling policy uses the posterior over the parameters given the +history up to time `n` to derive the probability of each action being optimal. The action for time +`n` is sampled according to these probabilities. -/ noncomputable def tsAlgorithm [NeZero K] (Q : Measure 𝓔) [IsProbabilityMeasure Q] (κ : Kernel (𝓔 × Fin K) ℝ) [IsMarkovKernel κ] : Algorithm Unit (Fin K) ℝ where @@ -105,12 +114,12 @@ lemma TS.hasCondDistrib_action (h : IsBayesAlgEnvSeq Q κ (tsAlgorithm Q κ) E A refine Measure.compProd_congr ?_ calc _ =ᵐ[P.map (history (noObs Ω) A R n)] - (IT.bayesTrajMeasurePosterior Q κ uniformAlgorithm n).map (bestAction κ id) := by rfl + (IT.bayesTrajMeasurePosterior Q κ Algorithm.uniform n).map (bestAction κ id) := by rfl _ =ᵐ[P.map (history (noObs Ω) A R n)] (condDistrib E (history (noObs Ω) A R n) P).map (bestAction κ id) := by filter_upwards [(h.hasCondDistrib_env_history - (IT.isBayesAlgEnvSeq_bayesTrajMeasure Q κ uniformAlgorithm) - absolutelyContinuous_uniformAlgorithm n).condDistrib_eq] with _ hc + (IT.isBayesAlgEnvSeq_bayesTrajMeasure Q κ Algorithm.uniform) + (Algorithm.absolutelyContinuous_uniform _) n).condDistrib_ae_eq] with _ hc simp_rw [Kernel.map_apply _ hm, IT.bayesTrajMeasurePosterior, hc] _ =ᵐ[P.map (history (noObs Ω) A R n)] condDistrib (bestAction κ E) (history (noObs Ω) A R n) P := diff --git a/LeanMachineLearning/Online/Bandit/Algorithms/UCB.lean b/LeanMachineLearning/Online/Bandit/Algorithms/UCB.lean index 38ca7461..f03bb1b0 100644 --- a/LeanMachineLearning/Online/Bandit/Algorithms/UCB.lean +++ b/LeanMachineLearning/Online/Bandit/Algorithms/UCB.lean @@ -13,6 +13,29 @@ public import LeanMachineLearning.ForMathlib.MeasureTheory.Order.MeasurableArg /-! # UCB algorithm +The Upper Confidence Bound (UCB) algorithm with exploration parameter `c` for a bandit with `K` +arms pulls each arm once (in rounds `0` to `K - 1`), then at each time `n ≥ K` pulls an arm that +maximizes the index `empMean A R a n + √(2 * c * log (n + 1) / pullCount A a n)`: the empirical +mean of the arm plus an exploration bonus, which is the width of a confidence interval for the mean. + +## Main definitions + +* `UCB.ucbWidth' c n h a`: exploration bonus of arm `a` at time `n`, given the history `h`. +* `UCB.nextArm K c n h`: arm pulled by UCB at time `n`, given the history `h` before `n`. +* `ucbAlgorithm K c`: the UCB algorithm. + +## Main statements + +* `UCB.ucbIndex_le_ucbIndex_arm`: for `n ≥ K`, the index of the arm pulled at time `n` is at least + the index of any other arm. + +## References + +* P. Auer, N. Cesa-Bianchi and P. Fischer, *Finite-time analysis of the multiarmed bandit problem*, + Machine Learning, 2002. +* T. Lattimore and C. Szepesvári, *Bandit Algorithms*, Cambridge University Press, 2020, + Chapters 7 and 8. + -/ @[expose] public section @@ -65,12 +88,13 @@ variable [NeZero K] {c : ℝ} {ν : Kernel (Fin K) ℝ} [IsMarkovKernel ν] {O : ℕ → Ω → Unit} {A : ℕ → Ω → Fin K} {R : ℕ → Ω → ℝ} {σ2 : ℝ≥0} {n : ℕ} {ω : Ω} +omit [IsProbabilityMeasure P] in /-- Before round `K`, the UCB algorithm behaves like the Round-Robin algorithm. -/ -lemma isAlgEnvSeqUntil_roundRobinAlgorithm +lemma isAlgEnvSeqUntil_roundRobin (h : IsAlgEnvSeq O A R (ucbAlgorithm K c) (Environment.bandit ν) P) : - IsAlgEnvSeqUntil O A R (roundRobinAlgorithm K) (Environment.bandit ν) P K := by + IsAlgEnvSeqUntil O A R (Algorithm.roundRobin K) (Environment.bandit ν) P K := by refine h.isAlgEnvSeqUntil_of_policy_eq fun n hn ↦ ?_ - simp only [roundRobinAlgorithm, Algorithm.deterministic_policy, ucbAlgorithm] + simp only [Algorithm.roundRobin, Algorithm.deterministic_policy, ucbAlgorithm] congr 1 with p simp [UCB.nextArm, hn] @@ -95,12 +119,12 @@ lemma ucbWidth_eq_ucbWidth' (c : ℝ) (a : Fin K) (n : ℕ) (ω : Ω) : lemma arm_zero (h : IsAlgEnvSeq O A R (ucbAlgorithm K c) (Environment.bandit ν) P) : A 0 =ᵐ[P] fun _ ↦ 0 := - RoundRobin.action_zero ((isAlgEnvSeqUntil_roundRobinAlgorithm h).mono (Nat.pos_of_neZero K)) + RoundRobin.action_zero ((isAlgEnvSeqUntil_roundRobin h).mono (Nat.pos_of_neZero K)) lemma arm_ae_eq_nextArm (h : IsAlgEnvSeq O A R (ucbAlgorithm K c) (Environment.bandit ν) P) (n : ℕ) : A n =ᵐ[P] fun ω ↦ nextArm K c n (history O A R n ω) := - h.action_deterministic_ae_eq n + h.action_ae_eq_deterministic n lemma ucbIndex_le_ucbIndex_arm (h : IsAlgEnvSeq O A R (ucbAlgorithm K c) (Environment.bandit ν) P) (a : Fin K) (hn : K ≤ n) : @@ -110,8 +134,8 @@ lemma ucbIndex_le_ucbIndex_arm have h_not_lt : ¬ n < K := by grind simp only [nextArm, h_not_lt, ↓reduceIte] at h_arm simp_rw [h_arm, empMean_eq_empMean' (O := O), ucbWidth_eq_ucbWidth' (O := O) (A := A) (R := R)] - exact isMaxOn_argmax (fun a ↦ empMean' n (history O A R n ω) a - + ucbWidth' c n (history O A R n ω) a) _ + exact isMaxOn_univ_iff.1 (isMaxOn_argmax (fun a ↦ empMean' n (history O A R n ω) a + + ucbWidth' c n (history O A R n ω) a)) _ lemma forall_arm_eq_mod_of_lt (h : IsAlgEnvSeq O A R (ucbAlgorithm K c) (Environment.bandit ν) P) : ∀ᵐ ω ∂P, ∀ n < K, A n ω = RoundRobin.nextAction K n := by @@ -132,12 +156,12 @@ lemma forall_ucbIndex_le_ucbIndex_arm lemma time_gt_of_pullCount_gt_one (h : IsAlgEnvSeq O A R (ucbAlgorithm K c) (Environment.bandit ν) P) (a : Fin K) : ∀ᵐ ω ∂P, ∀ n, 1 < pullCount A a n ω → K < n := - RoundRobin.time_gt_of_pullCount_gt_one (isAlgEnvSeqUntil_roundRobinAlgorithm h) a + RoundRobin.time_gt_of_pullCount_gt_one (isAlgEnvSeqUntil_roundRobin h) a lemma pullCount_pos_of_pullCount_gt_one (h : IsAlgEnvSeq O A R (ucbAlgorithm K c) (Environment.bandit ν) P) (a : Fin K) : ∀ᵐ ω ∂P, ∀ n, 1 < pullCount A a n ω → ∀ b : Fin K, 0 < pullCount A b n ω := - RoundRobin.pullCount_pos_of_pullCount_gt_one (isAlgEnvSeqUntil_roundRobinAlgorithm h) a + RoundRobin.pullCount_pos_of_pullCount_gt_one (isAlgEnvSeqUntil_roundRobin h) a end AlgorithmBehavior diff --git a/LeanMachineLearning/Online/Bandit/ArrayProbSpace.lean b/LeanMachineLearning/Online/Bandit/ArrayProbSpace.lean index 55061bff..84010b2a 100644 --- a/LeanMachineLearning/Online/Bandit/ArrayProbSpace.lean +++ b/LeanMachineLearning/Online/Bandit/ArrayProbSpace.lean @@ -5,10 +5,10 @@ Authors: Rémy Degenne, Paulo Rauber -/ module -public import LeanMachineLearning.ForMathlib.Probability.Independence.CondIndepFun -public import LeanMachineLearning.ForMathlib.Probability.Independence.IndepFun -public import LeanMachineLearning.ForMathlib.Probability.Independence.IndepInfinitePi -public import LeanMachineLearning.ForMathlib.Probability.Integrable +public import LeanMachineLearning.ForMathlib.Probability.Independence.Basic +public import LeanMachineLearning.ForMathlib.Probability.Independence.Conditional +public import LeanMachineLearning.ForMathlib.Probability.Independence.InfinitePi +public import LeanMachineLearning.ForMathlib.Probability.HasLaw public import LeanMachineLearning.SequentialLearning.SumRewards public import LeanMachineLearning.SequentialLearning.StationaryEnv public import Mathlib.Probability.Kernel.Representation @@ -28,10 +28,24 @@ arms and rewards specified in the bandit model determine their laws uniquely. * `streamMeasure ν`: probability measure on the space of infinite arrays of rewards, where the rewards in each row are i.i.d. according to `ν`. -* `probSpace 𝓐 𝓡`: probability space for the array model of stochastic bandits with action space `𝓐` - and reward space `𝓡`. -* `arrayMeasure ν`: probability measure on `probSpace 𝓐 𝓡` for the array model of stochastic bandits - with reward kernel `ν`. +* `ProbSpace 𝓐 𝓡`: probability space for the array model of stochastic bandits with action + space `𝓐` and reward space `𝓡`. +* `arrayMeasure ν`: probability measure on `ProbSpace 𝓐 𝓡` for the array model of stochastic + bandits with reward kernel `ν`. +* `action alg n`, `reward alg n`, `hist alg · n`: action, reward and history at time `n` in the + array model, for the algorithm `alg`. + +## Main statements + +* `isAlgEnvSeq_arrayMeasure`: the actions and rewards of the array model form an + algorithm-environment sequence for `alg` and the stochastic bandit `Environment.bandit ν`. +* `hasCondDistrib_reward_hist_action_pullCount`: the conditional distribution of the reward at time + `n` given the history, the action at time `n` and its number of pulls is `ν` (of that action). + +## References + +* T. Lattimore and C. Szepesvári, *Bandit Algorithms*, Cambridge University Press, 2020, + Section 4.6 (the "stack of rewards" model). -/ @@ -85,7 +99,7 @@ lemma identDistrib_eval_eval_id_streamMeasure (ν : Kernel 𝓐 𝓡) [IsMarkovK lemma integrable_eval_streamMeasure (ν : Kernel 𝓐 ℝ) [IsMarkovKernel ν] (n : ℕ) (a : 𝓐) (h_int : Integrable id (ν a)) : Integrable (fun h : ℕ → 𝓐 → ℝ ↦ h n a) (streamMeasure ν) := - Integrable.congr_identDistrib h_int (identDistrib_eval_eval_id_streamMeasure ν n a).symm + (identDistrib_eval_eval_id_streamMeasure ν n a).symm.integrable_snd h_int lemma integral_eval_streamMeasure (ν : Kernel 𝓐 ℝ) [IsMarkovKernel ν] (n : ℕ) (a : 𝓐) : ∫ h, h n a ∂(streamMeasure ν) = (ν a)[id] := by @@ -105,10 +119,8 @@ lemma iIndepFun_eval_streamMeasure (ν : Kernel 𝓐 𝓡) [IsMarkovKernel ν] : lemma indepFun_eval_streamMeasure (ν : Kernel 𝓐 𝓡) [IsMarkovKernel ν] {n m : ℕ} {a b : 𝓐} (h : n ≠ m ∨ a ≠ b) : - IndepFun (fun ω ↦ ω n a) (fun ω ↦ ω m b) (streamMeasure ν) := by - change IndepFun (fun ω ↦ ω (n, a).1 (n, a).2) (fun ω ↦ ω (m, b).1 (m, b).2) - (streamMeasure ν) - exact (iIndepFun_eval_streamMeasure ν).indepFun (by grind) + IndepFun (fun ω ↦ ω n a) (fun ω ↦ ω m b) (streamMeasure ν) := + (iIndepFun_eval_streamMeasure ν).indepFun (i := (n, a)) (j := (m, b)) (by grind) lemma indepFun_eval_streamMeasure' (ν : Kernel 𝓐 𝓡) [IsMarkovKernel ν] {a b : 𝓐} (h : a ≠ b) : IndepFun (fun ω n ↦ ω n a) (fun ω n ↦ ω n b) (streamMeasure ν) := @@ -175,22 +187,22 @@ section ProbabilitySpace variable (𝓐 𝓡) in /-- Probability space for the array model of stochastic bandits. -/ -abbrev probSpace : Type _ := (ℕ → I) × (ℕ → 𝓐 → 𝓡) +abbrev ProbSpace : Type _ := (ℕ → I) × (ℕ → 𝓐 → 𝓡) /-- Probability measure for the array model of stochastic bandits. -/ noncomputable -def arrayMeasure (ν : Kernel 𝓐 𝓡) : Measure (probSpace 𝓐 𝓡) := +def arrayMeasure (ν : Kernel 𝓐 𝓡) : Measure (ProbSpace 𝓐 𝓡) := (Measure.infinitePi fun _ ↦ volume).prod (streamMeasure ν) instance (ν : Kernel 𝓐 𝓡) [IsMarkovKernel ν] : IsProbabilityMeasure (arrayMeasure ν) := Measure.prod.instIsProbabilityMeasure _ _ lemma hasLaw_fst_apply_arrayMeasure (ν : Kernel 𝓐 𝓡) [IsMarkovKernel ν] (n : ℕ) : - HasLaw (fun ω : probSpace 𝓐 𝓡 ↦ ω.1 n) volume (arrayMeasure ν) := + HasLaw (fun ω : ProbSpace 𝓐 𝓡 ↦ ω.1 n) volume (arrayMeasure ν) := (hasLaw_eval_infinitePi (fun _ ↦ volume) n).comp (hasLaw_fst_prod _ _) lemma hasLaw_snd_apply_arrayMeasure (ν : Kernel 𝓐 𝓡) [IsMarkovKernel ν] (n : ℕ) (a : 𝓐) : - HasLaw (fun ω : probSpace 𝓐 𝓡 ↦ ω.2 n a) (ν a) (arrayMeasure ν) := + HasLaw (fun ω : ProbSpace 𝓐 𝓡 ↦ ω.2 n a) (ν a) (arrayMeasure ν) := hasLaw_snd_apply_prod_streamMeasure _ ν n a lemma map_snd_apply_arrayMeasure {ν : Kernel 𝓐 𝓡} [IsMarkovKernel ν] (n : ℕ) (a : 𝓐) : @@ -201,12 +213,12 @@ lemma map_snd_apply_arrayMeasure {ν : Kernel 𝓐 𝓡} [IsMarkovKernel ν] (n in row `a` of the reward array, the entry at index `i` is kept if `i < m` and replaced by the entry at index `m + 1 + i` otherwise. The result does not depend on the coordinate `(m, a)` of the array. -/ -def truncRow [DecidableEq 𝓐] (a : 𝓐) (m : ℕ) (ω : probSpace 𝓐 𝓡) : probSpace 𝓐 𝓡 := +def truncRow [DecidableEq 𝓐] (a : 𝓐) (m : ℕ) (ω : ProbSpace 𝓐 𝓡) : ProbSpace 𝓐 𝓡 := (ω.1, fun i b ↦ if b = a then ω.2 (if i < m then i else m + 1 + i) b else ω.2 i b) @[fun_prop] lemma measurable_truncRow [DecidableEq 𝓐] (a : 𝓐) (m : ℕ) : - Measurable (truncRow a m : probSpace 𝓐 𝓡 → probSpace 𝓐 𝓡) := by + Measurable (truncRow a m : ProbSpace 𝓐 𝓡 → ProbSpace 𝓐 𝓡) := by refine Measurable.prodMk measurable_fst (.of_eval fun i ↦ .of_eval fun b ↦ ?_) by_cases hb : b = a <;> simp only [hb, ↓reduceIte] <;> fun_prop @@ -241,7 +253,7 @@ section HistoryActionReward /-- History of actions and rewards before time `n` in the array model. -/ noncomputable -def hist [DecidableEq 𝓐] (alg : Algorithm Unit 𝓐 𝓡) (ω : probSpace 𝓐 𝓡) : +def hist [DecidableEq 𝓐] (alg : Algorithm Unit 𝓐 𝓡) (ω : ProbSpace 𝓐 𝓡) : (n : ℕ) → Hist Unit 𝓐 𝓡 n | 0 => default | n + 1 => @@ -250,17 +262,17 @@ def hist [DecidableEq 𝓐] (alg : Algorithm Unit 𝓐 𝓡) (ω : probSpace Fin.snoc hn ((), a, ω.2 (pullCount' n hn a) a) @[simp] -lemma hist_zero [DecidableEq 𝓐] (alg : Algorithm Unit 𝓐 𝓡) (ω : probSpace 𝓐 𝓡) : +lemma hist_zero [DecidableEq 𝓐] (alg : Algorithm Unit 𝓐 𝓡) (ω : ProbSpace 𝓐 𝓡) : hist alg ω 0 = default := rfl -lemma hist_add_one [DecidableEq 𝓐] (alg : Algorithm Unit 𝓐 𝓡) (ω : probSpace 𝓐 𝓡) (n : ℕ) : +lemma hist_add_one [DecidableEq 𝓐] (alg : Algorithm Unit 𝓐 𝓡) (ω : ProbSpace 𝓐 𝓡) (n : ℕ) : hist alg ω (n + 1) = Fin.snoc (hist alg ω n) ((), algFunction alg n (hist alg ω n) (ω.1 n), ω.2 (pullCount' n (hist alg ω n) (algFunction alg n (hist alg ω n) (ω.1 n))) (algFunction alg n (hist alg ω n) (ω.1 n))) := rfl lemma hist_add_one_eq_finSuccProd' [DecidableEq 𝓐] (alg : Algorithm Unit 𝓐 𝓡) - (ω : probSpace 𝓐 𝓡) (n : ℕ) : + (ω : ProbSpace 𝓐 𝓡) (n : ℕ) : hist alg ω (n + 1) = (MeasurableEquiv.finSuccProd (Round Unit 𝓐 𝓡) n).symm (hist alg ω n, ((), algFunction alg n (hist alg ω n) (ω.1 n), @@ -271,7 +283,7 @@ lemma hist_add_one_eq_finSuccProd' [DecidableEq 𝓐] (alg : Algorithm Unit 𝓐 /-- Action taken at time `n` in the array model. -/ noncomputable -def action [DecidableEq 𝓐] (alg : Algorithm Unit 𝓐 𝓡) (n : ℕ) (ω : probSpace 𝓐 𝓡) : 𝓐 := +def action [DecidableEq 𝓐] (alg : Algorithm Unit 𝓐 𝓡) (n : ℕ) (ω : ProbSpace 𝓐 𝓡) : 𝓐 := algFunction alg n (hist alg ω n) (ω.1 n) lemma action_eq [DecidableEq 𝓐] (alg : Algorithm Unit 𝓐 𝓡) (n : ℕ) : @@ -282,32 +294,31 @@ lemma action_zero [DecidableEq 𝓐] (alg : Algorithm Unit 𝓐 𝓡) : /-- Reward received at time `n` in the array model. -/ noncomputable -def reward [DecidableEq 𝓐] (alg : Algorithm Unit 𝓐 𝓡) (n : ℕ) (ω : probSpace 𝓐 𝓡) : 𝓡 := +def reward [DecidableEq 𝓐] (alg : Algorithm Unit 𝓐 𝓡) (n : ℕ) (ω : ProbSpace 𝓐 𝓡) : 𝓡 := (hist alg ω (n + 1) (Fin.last n)).feedback -lemma reward_eq' [DecidableEq 𝓐] (alg : Algorithm Unit 𝓐 𝓡) (n : ℕ) (ω : probSpace 𝓐 𝓡) : +lemma reward_eq' [DecidableEq 𝓐] (alg : Algorithm Unit 𝓐 𝓡) (n : ℕ) (ω : ProbSpace 𝓐 𝓡) : reward alg n ω = ω.2 (pullCount' n (hist alg ω n) (action alg n ω)) (action alg n ω) := by - change (hist alg ω (n + 1) (Fin.last n)).feedback = _ - rw [hist_add_one, Fin.snoc_last] + rw [reward, hist_add_one, Fin.snoc_last] rfl -lemma hist_succ [DecidableEq 𝓐] (alg : Algorithm Unit 𝓐 𝓡) (ω : probSpace 𝓐 𝓡) (n : ℕ) : +lemma hist_succ [DecidableEq 𝓐] (alg : Algorithm Unit 𝓐 𝓡) (ω : ProbSpace 𝓐 𝓡) (n : ℕ) : hist alg ω (n + 1) = Fin.snoc (hist alg ω n) ((), action alg n ω, reward alg n ω) := by rw [hist_add_one, reward_eq'] rfl -lemma hist_succ_eq_finSuccProd [DecidableEq 𝓐] (alg : Algorithm Unit 𝓐 𝓡) (ω : probSpace 𝓐 𝓡) +lemma hist_succ_eq_finSuccProd [DecidableEq 𝓐] (alg : Algorithm Unit 𝓐 𝓡) (ω : ProbSpace 𝓐 𝓡) (n : ℕ) : hist alg ω (n + 1) = (MeasurableEquiv.finSuccProd (Round Unit 𝓐 𝓡) n).symm (hist alg ω n, ((), action alg n ω, reward alg n ω)) := by rw [MeasurableEquiv.finSuccProd_symm_apply, hist_succ] -lemma hist_apply_last [DecidableEq 𝓐] (alg : Algorithm Unit 𝓐 𝓡) (ω : probSpace 𝓐 𝓡) (n : ℕ) : +lemma hist_apply_last [DecidableEq 𝓐] (alg : Algorithm Unit 𝓐 𝓡) (ω : ProbSpace 𝓐 𝓡) (n : ℕ) : hist alg ω (n + 1) (Fin.last n) = ((), action alg n ω, reward alg n ω) := by rw [hist_succ, Fin.snoc_last] -lemma hist_eq [DecidableEq 𝓐] (alg : Algorithm Unit 𝓐 𝓡) (ω : probSpace 𝓐 𝓡) (n : ℕ) : +lemma hist_eq [DecidableEq 𝓐] (alg : Algorithm Unit 𝓐 𝓡) (ω : ProbSpace 𝓐 𝓡) (n : ℕ) : hist alg ω n = fun i : Fin n ↦ ((), action alg i ω, reward alg i ω) := by induction n with | zero => exact Subsingleton.elim _ _ @@ -320,11 +331,11 @@ lemma hist_eq [DecidableEq 𝓐] (alg : Algorithm Unit 𝓐 𝓡) (ω : probSpac simp /-- The history in the array model is the history of the action and reward processes. -/ -lemma hist_eq_history [DecidableEq 𝓐] (alg : Algorithm Unit 𝓐 𝓡) (ω : probSpace 𝓐 𝓡) (n : ℕ) : +lemma hist_eq_history [DecidableEq 𝓐] (alg : Algorithm Unit 𝓐 𝓡) (ω : ProbSpace 𝓐 𝓡) (n : ℕ) : hist alg ω n = history (noObs _) (action alg) (reward alg) n ω := hist_eq alg ω n lemma pullCount_action_eq [DecidableEq 𝓐] (alg : Algorithm Unit 𝓐 𝓡) (a : 𝓐) (n : ℕ) - (ω : probSpace 𝓐 𝓡) : + (ω : ProbSpace 𝓐 𝓡) : pullCount (action alg) a n ω = pullCount' n (hist alg ω n) a := by rw [pullCount_eq_pullCount' (O := noObs _) (R' := reward alg), hist_eq] rfl @@ -340,7 +351,7 @@ lemma reward_eq [DecidableEq 𝓐] (alg : Algorithm Unit 𝓐 𝓡) (n : ℕ) : rw [reward_eq', pullCount_action_eq] lemma sumRewards_eq [DecidableEq 𝓐] (alg : Algorithm Unit 𝓐 ℝ) (a : 𝓐) (n : ℕ) - (ω : probSpace 𝓐 ℝ) : + (ω : ProbSpace 𝓐 ℝ) : sumRewards (action alg) (reward alg) a n ω = ∑ i ∈ range (pullCount (action alg) a n ω), ω.2 i a := by induction n with @@ -352,11 +363,11 @@ lemma sumRewards_eq [DecidableEq 𝓐] (alg : Algorithm Unit 𝓐 ℝ) (a : 𝓐 section Measurability -lemma measurable_action' [DecidableEq 𝓐] {alg : Algorithm Unit 𝓐 𝓡} +private lemma measurable_action' [DecidableEq 𝓐] {alg : Algorithm Unit 𝓐 𝓡} (n : ℕ) (h : Measurable (hist alg · n)) : Measurable (fun x ↦ algFunction alg n (hist alg x n) (x.1 n)) := by fun_prop -lemma measurable_pullCount'_action [DecidableEq 𝓐] {alg : Algorithm Unit 𝓐 𝓡} +private lemma measurable_pullCount'_action [DecidableEq 𝓐] {alg : Algorithm Unit 𝓐 𝓡} (n : ℕ) (h_hist : Measurable (hist alg · n)) : Measurable (fun x ↦ pullCount' n (hist alg x n) (algFunction alg n (hist alg x n) (x.1 n))) := by @@ -382,6 +393,7 @@ lemma measurable_hist [DecidableEq 𝓐] [Countable 𝓐] (alg : Algorithm Unit rw [h_eq] refine (MeasurableEquiv.measurable _).comp (hn.prodMk ?_) refine Measurable.prodMk measurable_const (Measurable.prodMk (measurable_action' n hn) ?_) + -- write the reward as the evaluation of the array at a measurable index change Measurable ((fun (x : (ℕ → 𝓐 → 𝓡) × ℕ × 𝓐) ↦ x.1 x.2.1 x.2.2) ∘ (fun x ↦ (x.2, pullCount' n (hist alg x n) (algFunction alg n (hist alg x n) (x.1 n)), (algFunction alg n (hist alg x n) (x.1 n))))) @@ -402,8 +414,9 @@ lemma measurable_reward [DecidableEq 𝓐] [Countable 𝓐] (alg : Algorithm Uni lemma measurable_pullCount_action [DecidableEq 𝓐] [Countable 𝓐] (alg : Algorithm Unit 𝓐 𝓡) (n : ℕ) : Measurable (fun ω ↦ pullCount (action alg) (action alg n ω) n ω) := by - change Measurable ((fun p : (probSpace 𝓐 𝓡) × 𝓐 ↦ pullCount (action alg) p.2 n p.1) ∘ - (fun ω : probSpace 𝓐 𝓡 ↦ (ω, action alg n ω))) + -- write the function as a composition with `fun ω ↦ (ω, action alg n ω)` + change Measurable ((fun p : (ProbSpace 𝓐 𝓡) × 𝓐 ↦ pullCount (action alg) p.2 n p.1) ∘ + (fun ω : ProbSpace 𝓐 𝓡 ↦ (ω, action alg n ω))) exact (measurable_uncurry_pullCount (by fun_prop) _).comp (by fun_prop) end Measurability @@ -415,7 +428,7 @@ variable [DecidableEq 𝓐] section Congruence -- very useful to prove measurability -lemma hist_congr (alg : Algorithm Unit 𝓐 𝓡) (n : ℕ) {ω ω' : probSpace 𝓐 𝓡} +lemma hist_congr (alg : Algorithm Unit 𝓐 𝓡) (n : ℕ) {ω ω' : ProbSpace 𝓐 𝓡} (hω1 : ∀ i < n, ω.1 i = ω'.1 i) (hω2 : ∀ i a, i < pullCount (action alg) a n ω → ω.2 i a = ω'.2 i a) : hist alg ω n = hist alg ω' n := by @@ -434,8 +447,8 @@ lemma hist_congr (alg : Algorithm Unit 𝓐 𝓡) (n : ℕ) {ω ω' : probSpace exact Nat.lt_succ_self _ rw [hist_succ, hist_succ, h_hist, h_action, h_reward] -lemma action_eq_and_pullCount_eq_congr_aux (alg : Algorithm Unit 𝓐 𝓡) - (a : 𝓐) (m n : ℕ) {ω ω' : probSpace 𝓐 𝓡} +private lemma action_eq_and_pullCount_eq_congr_aux (alg : Algorithm Unit 𝓐 𝓡) + (a : 𝓐) (m n : ℕ) {ω ω' : ProbSpace 𝓐 𝓡} (hω1 : ∀ i, ω.1 i = ω'.1 i) (hω2_ne : ∀ i b, b ≠ a → ω.2 i b = ω'.2 i b) (hω2_eq : ∀ i, i + 1 ≤ m → ω.2 i a = ω'.2 i a) (h_eq : action alg n ω = a ∧ pullCount (action alg) a n ω = m) : @@ -453,7 +466,7 @@ lemma action_eq_and_pullCount_eq_congr_aux (alg : Algorithm Unit 𝓐 𝓡) · rw [← h_pc, pullCount_action_eq, pullCount_action_eq, h_hist] lemma action_eq_and_pullCount_eq_congr (alg : Algorithm Unit 𝓐 𝓡) (a : 𝓐) (m n : ℕ) - {ω ω' : probSpace 𝓐 𝓡} + {ω ω' : ProbSpace 𝓐 𝓡} (hω1 : ∀ i, ω.1 i = ω'.1 i) (hω2_ne : ∀ i b, b ≠ a → ω.2 i b = ω'.2 i b) (hω2_eq : ∀ i, i + 1 ≤ m → ω.2 i a = ω'.2 i a) : (action alg n ω = a ∧ pullCount (action alg) a n ω = m) ↔ @@ -462,7 +475,7 @@ lemma action_eq_and_pullCount_eq_congr (alg : Algorithm Unit 𝓐 𝓡) (a : action_eq_and_pullCount_eq_congr_aux alg a m n (by grind) (by grind) (by grind)⟩ lemma indicator_action_eq_and_pullCount_eq_congr (alg : Algorithm Unit 𝓐 𝓡) (a : 𝓐) (m n : ℕ) - {ω ω' : probSpace 𝓐 𝓡} + {ω ω' : ProbSpace 𝓐 𝓡} (hω1 : ∀ i, ω.1 i = ω'.1 i) (hω2_ne : ∀ i b, b ≠ a → ω.2 i b = ω'.2 i b) (hω2_eq : ∀ i, i + 1 ≤ m → ω.2 i a = ω'.2 i a) : {ω | action alg n ω = a ∧ pullCount (action alg) a n ω = m}.indicator (fun _ ↦ 1) ω = @@ -498,8 +511,8 @@ not been observed before time `n` are replaced. The history before time `n` is m respect to this function (see `measurable_hist_truncRowPullCount`), and on the event `pullCount (action alg) a n = m` it coincides with `truncRow a m`. -/ noncomputable -def truncRowPullCount (alg : Algorithm Unit 𝓐 𝓡) (a : 𝓐) (n : ℕ) (ω : probSpace 𝓐 𝓡) : - probSpace 𝓐 𝓡 := +def truncRowPullCount (alg : Algorithm Unit 𝓐 𝓡) (a : 𝓐) (n : ℕ) (ω : ProbSpace 𝓐 𝓡) : + ProbSpace 𝓐 𝓡 := truncRow a (pullCount (action alg) a n ω) ω lemma measurable_hist_truncRowPullCount [Countable 𝓐] (alg : Algorithm Unit 𝓐 𝓡) (a : 𝓐) @@ -515,12 +528,6 @@ lemma measurable_hist_truncRowPullCount [Countable 𝓐] (alg : Algorithm Unit rw [h_eq] exact (measurable_hist alg n).comp (Measurable.of_comap_le le_rfl) -lemma measurableSet_action_eq_and_pullCount_eq [Countable 𝓐] (alg : Algorithm Unit 𝓐 𝓡) (a : 𝓐) - (n m : ℕ) : - MeasurableSet {ω | action alg n ω = a ∧ pullCount (action alg) a n ω = m} := - MeasurableSet.inter ((measurableSet_singleton _).preimage (by fun_prop)) - ((measurableSet_singleton _).preimage (by fun_prop)) - lemma preimage_action_pullCount_eq (alg : Algorithm Unit 𝓐 𝓡) (a : 𝓐) (n m : ℕ) : (fun ω ↦ (action alg n ω, pullCount (action alg) (action alg n ω) n ω)) ⁻¹' {(a, m)} = {ω | action alg n ω = a ∧ pullCount (action alg) a n ω = m}.indicator (fun _ ↦ 1) @@ -541,15 +548,18 @@ lemma measurable_indicator_action_eq_and_pullCount_eq [Countable 𝓐] (alg : Al ext ω exact indicator_action_eq_and_pullCount_eq_congr alg a m n (fun _ ↦ rfl) (fun _ _ hb ↦ by simp [truncRow, hb]) (fun i hi ↦ by simp [truncRow, show i < m by omega]) + -- fold `f` change Measurable[MeasurableSpace.comap (truncRow a m) inferInstance] f rw [h_eq] exact (Measurable.indicator (by fun_prop) - (measurableSet_action_eq_and_pullCount_eq alg a n m)).comp (Measurable.of_comap_le le_rfl) + (measurableSet_action_eq_and_pullCount_eq (measurable_action alg) n a m)).comp + (Measurable.of_comap_le le_rfl) lemma measurable_pullCount_action_hist (alg : Algorithm Unit 𝓐 𝓡) (n : ℕ) : Measurable[MeasurableSpace.comap (fun ω ↦ (hist alg ω n, action alg n ω)) inferInstance] (fun ω ↦ pullCount (action alg) (action alg n ω) n ω) := by simp_rw [pullCount_action_eq] + -- write the function as a composition with `fun ω ↦ (hist alg ω n, action alg n ω)` change Measurable[MeasurableSpace.comap (fun ω ↦ (hist alg ω n, action alg n ω)) inferInstance] ((fun p : Hist Unit 𝓐 𝓡 n × 𝓐 ↦ pullCount' n p.1 p.2) ∘ (fun ω ↦ (hist alg ω n, action alg n ω))) @@ -571,7 +581,7 @@ lemma indepFun_fst_zero_snd_zero_action (ν : Kernel 𝓐 𝓡) [IsMarkovKernel (by fun_prop) (by fun_prop) omit [Nonempty 𝓐] [StandardBorelSpace 𝓐] [DecidableEq 𝓐] in -lemma indepFun_fst_aux (ν : Kernel 𝓐 𝓡) [IsMarkovKernel ν] (n : ℕ) : +private lemma indepFun_fst_aux (ν : Kernel 𝓐 𝓡) [IsMarkovKernel ν] (n : ℕ) : (fun ω ↦ ω.1 n) ⟂ᵢ[arrayMeasure ν] (fun ω ↦ (fun (i : Fin n) ↦ ω.1 i, ω.2)) := by have h : IndepFun (fun ω : ℕ → I ↦ ω n) (fun ω (i : Fin n) ↦ ω i) (Measure.infinitePi fun _ ↦ volume) := by @@ -581,14 +591,12 @@ lemma indepFun_fst_aux (ν : Kernel 𝓐 𝓡) [IsMarkovKernel ν] (n : ℕ) : exact iSup_le fun i ↦ le_iSup₂_of_le (i : ℕ) (Set.mem_Iio.2 i.2) le_rfl exact h.fst_prod (ν := streamMeasure ν) (by fun_prop) (by fun_prop) -variable [StandardBorelSpace 𝓡] [Nonempty 𝓡] - lemma indepFun_fst_hist [Countable 𝓐] (alg : Algorithm Unit 𝓐 𝓡) (ν : Kernel 𝓐 𝓡) [IsMarkovKernel ν] (n : ℕ) : IndepFun (fun ω ↦ ω.1 n) (hist alg · n) (arrayMeasure ν) := (indepFun_fst_aux ν n).of_measurable_right (measurable_hist_comap alg n) -omit [Nonempty 𝓐] [StandardBorelSpace 𝓐] [StandardBorelSpace 𝓡] [Nonempty 𝓡] in +omit [Nonempty 𝓐] [StandardBorelSpace 𝓐] in /-- The reward `ω.2 m a` is independent of `truncRow a m`, which reads only other coordinates. -/ lemma indepFun_snd_apply_truncRow (ν : Kernel 𝓐 𝓡) [IsMarkovKernel ν] (a : 𝓐) (m : ℕ) : (fun ω ↦ ω.2 m a) ⟂ᵢ[arrayMeasure ν] (truncRow a m) := by @@ -613,7 +621,6 @@ lemma indepFun_snd_apply_truncRow (ν : Kernel 𝓐 𝓡) [IsMarkovKernel ν] (a (fun _ ↦ by fun_prop) (i := (m, a)) (by simp) hT exact h.snd_prod (μ := Measure.infinitePi fun _ ↦ volume) (by fun_prop) hTm -omit [StandardBorelSpace 𝓡] [Nonempty 𝓡] in lemma indepFun_snd_apply_pullCount_action [Countable 𝓐] (alg : Algorithm Unit 𝓐 𝓡) (ν : Kernel 𝓐 𝓡) [IsMarkovKernel ν] (a : 𝓐) (m n : ℕ) : (fun ω ↦ ω.2 m a) ⟂ᵢ[arrayMeasure ν] @@ -650,6 +657,7 @@ section Laws variable [Countable 𝓐] [StandardBorelSpace 𝓡] [Nonempty 𝓡] +omit [StandardBorelSpace 𝓡] [Nonempty 𝓡] in lemma hasCondDistrib_action' (alg : Algorithm Unit 𝓐 𝓡) (ν : Kernel 𝓐 𝓡) [IsMarkovKernel ν] (n : ℕ) : HasCondDistrib (action alg n) (hist alg · n) ((alg.policy n).sectL ()) (arrayMeasure ν) := by @@ -657,7 +665,7 @@ lemma hasCondDistrib_action' (alg : Algorithm Unit 𝓐 𝓡) (ν : Kernel 𝓐 (Kernel.const _ volume) (arrayMeasure ν) := ((indepFun_fst_hist alg ν n).symm.comp (measurable_id.prodMk measurable_id) measurable_id).hasCondDistrib_const (by fun_prop) (hasLaw_fst_apply_arrayMeasure ν n) - have h := ((hasCondDistrib_self (X := (hist alg · n)) (by fun_prop)).prod hU).comp_left + have h := ((hasCondDistrib_self (X := (hist alg · n)) (by fun_prop)).compProd hU).comp_left (measurable_algFunction alg n) have h_ker : (alg.policy n).sectL () = (Kernel.id ⊗ₖ Kernel.const _ volume).map (Function.uncurry (algFunction alg n)) := by @@ -690,19 +698,21 @@ lemma hasCondDistrib_reward_hist_action_pullCount HasCondDistrib (reward alg n) (fun ω ↦ (hist alg ω n, action alg n ω, pullCount (action alg) (action alg n ω) n ω)) ((ν.prodMkRight _).prodMkLeft _) (arrayMeasure ν) := by - refine hasCondDistrib_of_condDistrib_eq (by fun_prop) (by fun_prop) ?_ + refine hasCondDistrib_of_condDistrib_ae_eq (by fun_prop) (by fun_prop) ?_ refine condDistrib_prod_of_forall_condDistrib_cond (by fun_prop) (by fun_prop) (by fun_prop) _ ?_ intro (a, m) ham have h_eq : ((ν.prodMkRight _).prodMkLeft _).comap (fun ω : Hist Unit 𝓐 𝓡 n ↦ (ω, a, m)) (by fun_prop) = Kernel.const _ (ν a) := by ext; simp rw [h_eq, condDistrib_congr_left (reward_ae_eq_cond alg ν a n m)] - refine (condDistrib_of_indepFun ?_ (by fun_prop) (by fun_prop)).trans (ae_of_all _ fun ω ↦ ?_) + refine (condDistrib_ae_eq_of_indepFun ?_ (by fun_prop) (by fun_prop)).trans + (ae_of_all _ fun ω ↦ ?_) · exact (indepFun_snd_hist_cond alg ν a n m).symm · simp only [Kernel.const_apply] rw [preimage_action_pullCount_eq, cond_of_indepFun, map_snd_apply_arrayMeasure m a] · exact (indepFun_snd_apply_pullCount_action alg ν a m n).symm - · exact Measurable.indicator (by fun_prop) (measurableSet_action_eq_and_pullCount_eq alg a n m) + · exact Measurable.indicator (by fun_prop) + (measurableSet_action_eq_and_pullCount_eq (measurable_action alg) n a m) · fun_prop · simp · rwa [preimage_action_pullCount_eq] at ham @@ -718,7 +728,7 @@ lemma condIndepFun_reward_hist (alg : Algorithm Unit 𝓐 𝓡) (ν : Kernel (hist alg · n) := by have h_cond := hasCondDistrib_reward_hist_action_pullCount alg ν n refine condIndepFun_of_exists_condDistrib_prod_ae_eq_prodMkLeft (by fun_prop) (by fun_prop) ?_ - h_cond.condDistrib_eq + h_cond.condDistrib_ae_eq exact Measurable.prodMk (by fun_prop) (measurable_pullCount_action alg n) /-- The conditional distribution of the reward at time `n`, given the history before time `n` @@ -743,6 +753,7 @@ lemma hasCondDistrib_reward' (alg : Algorithm Unit 𝓐 𝓡) (ν : Kernel 𝓐 rw [h_eq, h_ker] at h exact (hasCondDistrib_prod_right_iff _ _ hf).1 h +omit [StandardBorelSpace 𝓡] [Nonempty 𝓡] in lemma hasCondDistrib_action (alg : Algorithm Unit 𝓐 𝓡) (ν : Kernel 𝓐 𝓡) [IsMarkovKernel ν] (n : ℕ) : HasCondDistrib (action alg n) @@ -779,7 +790,7 @@ lemma isAlgEnvSeq_arrayMeasure (alg : Algorithm Unit 𝓐 𝓡) (ν : Kernel lemma hasLaw_action_zero (alg : Algorithm Unit 𝓐 𝓡) (ν : Kernel 𝓐 𝓡) [IsMarkovKernel ν] : HasLaw (action alg 0) (alg.policyZero ()) (arrayMeasure ν) := by - have h : HasCondDistrib (action alg 0) (fun _ : probSpace 𝓐 𝓡 ↦ ()) alg.policyZero + have h : HasCondDistrib (action alg 0) (fun _ : ProbSpace 𝓐 𝓡 ↦ ()) alg.policyZero (arrayMeasure ν) := (isAlgEnvSeq_arrayMeasure alg ν).hasCondDistrib_action_zero exact h.hasLaw_of_const' diff --git a/LeanMachineLearning/Online/Bandit/BayesRegret.lean b/LeanMachineLearning/Online/Bandit/BayesRegret.lean index c1a95147..d44d0bbf 100644 --- a/LeanMachineLearning/Online/Bandit/BayesRegret.lean +++ b/LeanMachineLearning/Online/Bandit/BayesRegret.lean @@ -11,13 +11,13 @@ public import LeanMachineLearning.Online.Bandit.Regret /-! # Bayesian regret -This file defines `actionMean`, `bestAction`, `gap`, and `regret` as random variables in a +This file defines `actionMean`, `bestAction`, `gap`, and `regret` as random variables on a measurable space `Ω`. These definitions are useful when `IsBayesAlgEnvSeq Q κ alg E A Y P`. -Recall that `IsBayesAlgEnvSeq Q κ alg E A Y P` states that there is a measure `P : Measure Ω` such -that the parameter `E : Ω → 𝓔` has law `Q` and that the sequences of actions `A : ℕ → Ω → 𝓐` and -feedbacks `Y : ℕ → Ω → 𝓨` are generated by the algorithm `alg : Algorithm 𝓐 𝓨` interacting with an -underlying environment that depends on `E` and `κ` (`Environment.bandit (κ.sectR (E ω))`) +Recall that `IsBayesAlgEnvSeq Q κ alg E A Y P` states that, under the measure `P : Measure Ω`, +the parameter `E : Ω → 𝓔` has law `Q` and the sequences of actions `A : ℕ → Ω → 𝓐` and +feedbacks `Y : ℕ → Ω → 𝓨` are generated by the algorithm `alg : Algorithm Unit 𝓐 𝓨` interacting +with an underlying environment that depends on `E` and `κ` (`Environment.bandit (κ.sectR (E ω))`). ## Main definitions @@ -30,6 +30,11 @@ underlying environment that depends on `E` and `κ` (`Environment.bandit (κ.sec `IsBayesAlgEnvSeq Q κ alg E A Y P`, then `P[regret κ E A n]` is the so-called Bayesian regret of algorithm `alg` under the prior `Q`. +## References + +* T. Lattimore and C. Szepesvári, *Bandit Algorithms*, Cambridge University Press, 2020, + Chapters 34 and 36. + -/ @[expose] public section @@ -38,8 +43,8 @@ open MeasureTheory ProbabilityTheory Finset namespace Learning.IsBayesAlgEnvSeq -variable {𝓔 𝓐 𝓨 Ω : Type*} -variable [MeasurableSpace 𝓔] [MeasurableSpace 𝓐] [MeasurableSpace 𝓨] [MeasurableSpace Ω] +variable {𝓔 𝓐 Ω : Type*} +variable [MeasurableSpace 𝓔] [MeasurableSpace 𝓐] [MeasurableSpace Ω] /-- A random variable that gives the mean feedback of action `a`. -/ noncomputable @@ -54,6 +59,7 @@ lemma measurable_actionMean {κ : Kernel (𝓔 × 𝓐) ℝ} {E : Ω → 𝓔} { lemma measurable_uncurry_actionMean_comp [Countable 𝓐] [MeasurableSingletonClass 𝓐] {κ : Kernel (𝓔 × 𝓐) ℝ} {E : Ω → 𝓔} (hE : Measurable E) {f : Ω → 𝓐} (hf : Measurable f) : Measurable (fun ω ↦ actionMean κ E (f ω) ω) := by + -- write the function as a composition with `fun ω ↦ (f ω, ω)` change Measurable ((fun aω ↦ actionMean κ E aω.1 aω.2) ∘ fun ω ↦ (f ω, ω)) apply Measurable.comp _ (by fun_prop) exact measurable_from_prod_countable_right (fun _ ↦ measurable_actionMean hE) @@ -89,7 +95,7 @@ lemma gap_nonneg_of_le {κ : Kernel (𝓔 × 𝓐) ℝ} {E : Ω → 𝓔} {A : Bandits.gap_nonneg_of_le (h (E ω)) omit [MeasurableSpace Ω] in -lemma gap_le_of_mem_Icc [Nonempty 𝓐] {κ : Kernel (𝓔 × 𝓐) ℝ} {E : Ω → 𝓔} {A : ℕ → Ω → 𝓐} {n : ℕ} +lemma gap_le_of_mem_Icc {κ : Kernel (𝓔 × 𝓐) ℝ} {E : Ω → 𝓔} {A : ℕ → Ω → 𝓐} {n : ℕ} {ω : Ω} {l u : ℝ} (h : ∀ e a, (κ (e, a))[id] ∈ Set.Icc l u) : gap κ E A n ω ≤ u - l := Bandits.gap_le_of_mem_Icc (h (E ω)) @@ -100,7 +106,7 @@ lemma gap_eq_sub [Nonempty 𝓐] [Fintype 𝓐] {κ : Kernel (𝓔 × 𝓐) ℝ} rw [gap, Bandits.gap] congr apply le_antisymm - · exact ciSup_le <| isMaxOn_argmax (fun a ↦ actionMean κ E a ω) + · exact ciSup_le <| isMaxOn_univ_iff.1 <| isMaxOn_argmax (fun a ↦ actionMean κ E a ω) · exact Finite.le_ciSup (fun a ↦ actionMean κ E a ω) _ @[fun_prop] @@ -109,7 +115,7 @@ lemma measurable_gap [Countable 𝓐] {κ : Kernel (𝓔 × 𝓐) ℝ} {E : Ω (Measurable.iSup fun _ ↦ stronglyMeasurable_id.integral_kernel.measurable.comp (by fun_prop)).sub (stronglyMeasurable_id.integral_kernel.measurable.comp (by fun_prop)) -lemma integrable_gap [Countable 𝓐] [Nonempty 𝓐] {κ : Kernel (𝓔 × 𝓐) ℝ} {E : Ω → 𝓔} +lemma integrable_gap [Countable 𝓐] {κ : Kernel (𝓔 × 𝓐) ℝ} {E : Ω → 𝓔} {A : ℕ → Ω → 𝓐} {n : ℕ} {P : Measure Ω} [IsFiniteMeasure P] (hE : Measurable E) (hA : ∀ t, Measurable (A t)) {l u : ℝ} (h : ∀ e a, (κ (e, a))[id] ∈ Set.Icc l u) : Integrable (gap κ E A n) P := by @@ -138,7 +144,7 @@ lemma measurable_regret [Countable 𝓐] {κ : Kernel (𝓔 × 𝓐) ℝ} {E : rw [regret_eq_sum_gap'] fun_prop -lemma integrable_regret [Countable 𝓐] [Nonempty 𝓐] {κ : Kernel (𝓔 × 𝓐) ℝ} {E : Ω → 𝓔} +lemma integrable_regret [Countable 𝓐] {κ : Kernel (𝓔 × 𝓐) ℝ} {E : Ω → 𝓔} {A : ℕ → Ω → 𝓐} {n : ℕ} {P : Measure Ω} [IsFiniteMeasure P] (hE : Measurable E) (hA : ∀ t, Measurable (A t)) {l u : ℝ} (h : ∀ e a, (κ (e, a))[id] ∈ Set.Icc l u) : Integrable (regret κ E A n) P := by diff --git a/LeanMachineLearning/Online/Bandit/SumRewards.lean b/LeanMachineLearning/Online/Bandit/Concentration.lean similarity index 53% rename from LeanMachineLearning/Online/Bandit/SumRewards.lean rename to LeanMachineLearning/Online/Bandit/Concentration.lean index 1e9221dd..ef108d57 100644 --- a/LeanMachineLearning/Online/Bandit/SumRewards.lean +++ b/LeanMachineLearning/Online/Bandit/Concentration.lean @@ -7,10 +7,32 @@ module public import LeanMachineLearning.ForMathlib.Probability.Moments.SubGaussian public import LeanMachineLearning.Online.Bandit.ArrayProbSpace -public import LeanMachineLearning.Online.Bandit.BayesRegret -public import LeanMachineLearning.SequentialLearning.BayesStationaryEnv +public import LeanMachineLearning.Online.Bandit.Regret -/-! # Law of the sum of rewards +/-! # Concentration of the sums of rewards + +For a stochastic bandit, we bound the probability of events involving the number of pulls +`pullCount A a n` and the sum of rewards `sumRewards A R a n` of an action by probabilities of +events about sums of i.i.d. rewards under `streamMeasure ν`. The bounds are first proved in the +array model `ArrayModel.arrayMeasure ν`, in which the sum of rewards of action `a` after `k` pulls +is the sum of the first `k` entries of row `a` of the reward array, then transferred to any +algorithm-environment sequence since the joint law of the numbers of pulls and of the sums of +rewards does not depend on the probability space (`IsAlgEnvSeq.identDistrib_pullCount_sumRewards`). + +We then specialize those bounds to sub-Gaussian rewards, for the analysis of the ETC, UCB and +Thompson sampling algorithms. + +## Main statements + +* `prob_pullCount_prod_sumRewards_mem_le`, `prob_exists_pullCount_eq_and_sumRewards_mem_le`: bounds + on the probability of events about the number of pulls and the sum of rewards of an action. +* `prob_sumRewards_sub_pullCount_mul_ge_le`, `prob_sumRewards_sub_pullCount_mul_le_le`: uniform in + time sub-Gaussian concentration of the sum of rewards of an action. + +## References + +* T. Lattimore and C. Szepesvári, *Bandit Algorithms*, Cambridge University Press, 2020, + Chapters 5 to 8. -/ @[expose] public section @@ -97,189 +119,56 @@ lemma prob_exists_pullCount_eq_and_sumRewards_mem_le (a : 𝓐) (m : ℕ) {B : S _ = streamMeasure ν {ω | ∑ i ∈ range m, ω i a ∈ B} := (identDistrib_sum_range_snd a m).measure_mem_eq hB -lemma prob_sumRewards_le_sumRewards_le [Fintype 𝓐] (a : 𝓐) (n m₁ m₂ : ℕ) : - (𝔓) {ω | pullCount A (bestArm ν) n ω = m₁ ∧ pullCount A a n ω = m₂ ∧ - sumRewards A R (bestArm ν) n ω ≤ sumRewards A R a n ω} ≤ - streamMeasure ν - {ω | ∑ i ∈ range m₁, ω i (bestArm ν) ≤ ∑ i ∈ range m₂, ω i a} := by +lemma prob_sumRewards_le_sumRewards_le (a b : 𝓐) (n m₁ m₂ : ℕ) : + (𝔓) {ω | pullCount A a n ω = m₁ ∧ pullCount A b n ω = m₂ ∧ + sumRewards A R a n ω ≤ sumRewards A R b n ω} ≤ + streamMeasure ν {ω | ∑ i ∈ range m₁, ω i a ≤ ∑ i ∈ range m₂, ω i b} := by simp_rw [sumRewards_eq] - calc 𝔓 {ω | pullCount A (bestArm ν) n ω = m₁ ∧ pullCount A a n ω = m₂ ∧ - ∑ i ∈ range (pullCount A (bestArm ν) n ω), ω.2 i (bestArm ν) ≤ - ∑ i ∈ range (pullCount A a n ω), ω.2 i a} - _ ≤ 𝔓 ((fun ω ↦ (∑ i ∈ range m₁, ω.2 i (bestArm ν), ∑ i ∈ range m₂, ω.2 i a)) ⁻¹' - {p | p.1 ≤ p.2}) := by + calc 𝔓 {ω | pullCount A a n ω = m₁ ∧ pullCount A b n ω = m₂ ∧ + ∑ i ∈ range (pullCount A a n ω), ω.2 i a ≤ ∑ i ∈ range (pullCount A b n ω), ω.2 i b} + _ ≤ 𝔓 ((fun ω ↦ (∑ i ∈ range m₁, ω.2 i a, ∑ i ∈ range m₂, ω.2 i b)) ⁻¹' {p | p.1 ≤ p.2}) := by refine measure_mono fun ω hω ↦ ?_ simp only [Set.preimage_ofPred_eq, Set.mem_ofPred_eq] at hω ⊢ grind - _ = streamMeasure ν - {ω | ∑ i ∈ range m₁, ω i (bestArm ν) ≤ ∑ i ∈ range m₂, ω i a} := by + _ = streamMeasure ν {ω | ∑ i ∈ range m₁, ω i a ≤ ∑ i ∈ range m₂, ω i b} := by rw [← Measure.snd_prod (μ := (Measure.infinitePi fun (_ : ℕ) ↦ (volume : Measure unitInterval))) (ν := streamMeasure ν), Measure.snd, Measure.map_apply (by fun_prop)] · rfl simp only [measurableSet_setOfPred] fun_prop -lemma probReal_sumRewards_le_sumRewards_le [Fintype 𝓐] (a : 𝓐) (n m₁ m₂ : ℕ) : - (𝔓).real {ω | pullCount A (bestArm ν) n ω = m₁ ∧ pullCount A a n ω = m₂ ∧ - sumRewards A R (bestArm ν) n ω ≤ sumRewards A R a n ω} ≤ - (streamMeasure ν).real - {ω | ∑ i ∈ range m₁, ω i (bestArm ν) ≤ ∑ i ∈ range m₂, ω i a} := by +lemma probReal_sumRewards_le_sumRewards_le (a b : 𝓐) (n m₁ m₂ : ℕ) : + (𝔓).real {ω | pullCount A a n ω = m₁ ∧ pullCount A b n ω = m₂ ∧ + sumRewards A R a n ω ≤ sumRewards A R b n ω} ≤ + (streamMeasure ν).real {ω | ∑ i ∈ range m₁, ω i a ≤ ∑ i ∈ range m₂, ω i b} := by simp_rw [measureReal_def] gcongr · finiteness - · exact prob_sumRewards_le_sumRewards_le a n m₁ m₂ + · exact prob_sumRewards_le_sumRewards_le a b n m₁ m₂ end ArrayModel -variable {𝓐 Ω Ω' : Type*} [DecidableEq 𝓐] {m𝓐 : MeasurableSpace 𝓐} {mΩ : MeasurableSpace Ω} - {mΩ' : MeasurableSpace Ω'} - {P : Measure Ω} [IsProbabilityMeasure P] {P' : Measure Ω'} [IsProbabilityMeasure P'] +variable {𝓐 Ω : Type*} [DecidableEq 𝓐] {m𝓐 : MeasurableSpace 𝓐} {mΩ : MeasurableSpace Ω} + {P : Measure Ω} [IsProbabilityMeasure P] {alg : Algorithm Unit 𝓐 ℝ} {ν : Kernel 𝓐 ℝ} [IsMarkovKernel ν] - {O : ℕ → Ω → Unit} {A : ℕ → Ω → 𝓐} {R : ℕ → Ω → ℝ} - {O₂ : ℕ → Ω' → Unit} {A₂ : ℕ → Ω' → 𝓐} {R₂ : ℕ → Ω' → ℝ} - {ω : Ω} {m n t : ℕ} {a : 𝓐} - -lemma sumRewards_eq_comp : - sumRewards A R a n = - (fun p : ℕ → Round Unit 𝓐 ℝ ↦ - ∑ i ∈ range n, if (p i).action = a then (p i).feedback else 0) ∘ (trajectory O A R) := by - ext - simp [sumRewards, trajectory] - grind - -lemma pullCount_eq_comp : - pullCount A a n = - (fun p : ℕ → Round Unit 𝓐 ℝ ↦ ∑ i ∈ range n, if (p i).action = a then 1 else 0) ∘ - (trajectory O A R) := by - ext - simp [pullCount, trajectory] - rfl - --- todo: write those lemmas with IdentDistrib instead of equality of maps -lemma _root_.Learning.IsAlgEnvSeq.law_sumRewards_unique [MeasurableSingletonClass 𝓐] - (h1 : IsAlgEnvSeq O A R alg (Environment.bandit ν) P) - (h2 : IsAlgEnvSeq O₂ A₂ R₂ alg (Environment.bandit ν) P') : - P.map (sumRewards A R a n) = P'.map (sumRewards A₂ R₂ a n) := by - have hA := h1.measurable_action - have hR := h1.measurable_feedback - have hA2 := h2.measurable_action - have hR2 := h2.measurable_feedback - have h_unique := isAlgEnvSeq_unique h1 h2 - rw [sumRewards_eq_comp (O := O), sumRewards_eq_comp (O := O₂), ← Measure.map_map, h_unique, - Measure.map_map, ← sumRewards_eq_comp (O := O₂)] - · refine measurable_sum _ fun i hi ↦ Measurable.ite ?_ (by fun_prop) (by fun_prop) - exact (measurableSet_singleton _).preimage (by fun_prop) - · fun_prop - · refine measurable_sum _ fun i hi ↦ Measurable.ite ?_ (by fun_prop) (by fun_prop) - exact (measurableSet_singleton _).preimage (by fun_prop) - · fun_prop - -lemma _root_.Learning.IsAlgEnvSeq.law_pullCount_sumRewards_unique' [MeasurableSingletonClass 𝓐] - (h1 : IsAlgEnvSeq O A R alg (Environment.bandit ν) P) - (h2 : IsAlgEnvSeq O₂ A₂ R₂ alg (Environment.bandit ν) P') : - IdentDistrib (fun ω a ↦ (pullCount A a n ω, sumRewards A R a n ω)) - (fun ω a ↦ (pullCount A₂ a n ω, sumRewards A₂ R₂ a n ω)) P P' := by - have hO := h1.measurable_obs - have hA := h1.measurable_action - have hR := h1.measurable_feedback - have hO2 := h2.measurable_obs - have hA2 := h2.measurable_action - have hR2 := h2.measurable_feedback - constructor - · refine Measurable.aemeasurable ?_ - rw [measurable_pi_iff] - exact fun a ↦ Measurable.prod (by fun_prop) (measurable_sumRewards hA hR _ _) - · refine Measurable.aemeasurable ?_ - rw [measurable_pi_iff] - exact fun a ↦ Measurable.prod (by fun_prop) (measurable_sumRewards hA2 hR2 _ _) - have h_unique := isAlgEnvSeq_unique h1 h2 - let f := fun (p : ℕ → Round Unit 𝓐 ℝ) (a : 𝓐) ↦ - (∑ i ∈ range n, if (p i).action = a then 1 else 0, - ∑ i ∈ range n, if (p i).action = a then (p i).feedback else 0) - have hf : Measurable f := by - rw [measurable_pi_iff] - intro a - refine Measurable.prod ?_ ?_ - · simp only [f] - refine measurable_sum _ fun i hi ↦ Measurable.ite ?_ (by fun_prop) (by fun_prop) - exact (measurableSet_singleton _).preimage (by fun_prop) - · simp only [f] - refine measurable_sum _ fun i hi ↦ Measurable.ite ?_ (by fun_prop) (by fun_prop) - exact (measurableSet_singleton _).preimage (by fun_prop) - have h_eq_comp : (fun ω a ↦ (pullCount A a n ω, sumRewards A R a n ω)) - = f ∘ (trajectory O A R) := by - ext ω a : 2 - rw [pullCount_eq_comp (O := O) (R := R), sumRewards_eq_comp (O := O)] - grind - have h_eq_comp2 : (fun ω a ↦ (pullCount A₂ a n ω, sumRewards A₂ R₂ a n ω)) - = f ∘ (trajectory O₂ A₂ R₂) := by - ext ω a : 2 - rw [pullCount_eq_comp (O := O₂) (R := R₂), sumRewards_eq_comp (O := O₂)] - grind - rw [h_eq_comp, h_eq_comp2, ← Measure.map_map hf, h_unique, Measure.map_map hf, - ← h_eq_comp2] - · fun_prop - · fun_prop - -lemma _root_.Learning.IsAlgEnvSeq.law_pullCount_sumRewards_unique [MeasurableSingletonClass 𝓐] - (h1 : IsAlgEnvSeq O A R alg (Environment.bandit ν) P) - (h2 : IsAlgEnvSeq O₂ A₂ R₂ alg (Environment.bandit ν) P') : - P.map (fun ω ↦ (pullCount A a n ω, sumRewards A R a n ω)) = - P'.map (fun ω ↦ (pullCount A₂ a n ω, sumRewards A₂ R₂ a n ω)) := - ((h1.law_pullCount_sumRewards_unique' h2 (n := n)).comp (u := fun f ↦ f a) (by fun_prop)).map_eq - -lemma _root_.Learning.IsAlgEnvSeq.identDistrib_pullCount_sumRewards [MeasurableSingletonClass 𝓐] - (h1 : IsAlgEnvSeq O A R alg (Environment.bandit ν) P) - (h2 : IsAlgEnvSeq O₂ A₂ R₂ alg (Environment.bandit ν) P') : - IdentDistrib (fun ω n a ↦ (pullCount A a n ω, sumRewards A R a n ω)) - (fun ω' n a ↦ (pullCount A₂ a n ω', sumRewards A₂ R₂ a n ω')) P P' := by - let f (τ : ℕ → Round Unit 𝓐 ℝ) (n : ℕ) (a : 𝓐) : ℕ × ℝ := - (∑ i ∈ range n, if (τ i).action = a then 1 else 0, - ∑ i ∈ range n, if (τ i).action = a then (τ i).feedback else 0) - have hc1 : (fun ω n a ↦ (pullCount A a n ω, sumRewards A R a n ω)) = - f ∘ (trajectory O A R) := by - ext ω n a : 3 - simp_rw [Function.comp, f, pullCount, card_filter, sumRewards, trajectory] - rfl - have hc2 : (fun ω' n a ↦ (pullCount A₂ a n ω', sumRewards A₂ R₂ a n ω')) = - f ∘ (trajectory O₂ A₂ R₂) := by - ext ω' n a : 3 - simp_rw [Function.comp, f, pullCount, card_filter, sumRewards, trajectory] - rfl - have hf : Measurable f := by - simp_rw [f, measurable_pi_iff] - intro n a - apply Measurable.prod - · dsimp only - exact measurable_sum _ - (fun _ _ ↦ Measurable.ite (by measurability) (by fun_prop) (by fun_prop)) - · dsimp only - exact measurable_sum _ - (fun _ _ ↦ Measurable.ite (by measurability) (by fun_prop) (by fun_prop)) - rw [hc1, hc2] - exact (h1.identDistrib_trajectory h2).comp hf + {O : ℕ → Ω → Unit} {A : ℕ → Ω → 𝓐} {R : ℕ → Ω → ℝ} {n : ℕ} {a : 𝓐} variable [Nonempty 𝓐] --- this is what we will use for UCB +/-- Union bound over the possible values of the number of pulls: the probability that the number of +pulls and the sum of rewards of `a` at time `n` lie in `s` is at most a sum over `k ≤ n` of the +probabilities that `k` and the sum of `k` i.i.d. rewards of `a` lie in `s`. -/ lemma prob_pullCount_prod_sumRewards_mem_le [Countable 𝓐] [MeasurableSingletonClass 𝓐] (h : IsAlgEnvSeq O A R alg (Environment.bandit ν) P) {s : Set (ℕ × ℝ)} [DecidablePred (· ∈ Prod.fst '' s)] (hs : MeasurableSet s) : P {ω | (pullCount A a n ω, sumRewards A R a n ω) ∈ s} ≤ ∑ k ∈ (range (n + 1)).filter (· ∈ Prod.fst '' s), streamMeasure ν {ω | ∑ i ∈ range k, ω i a ∈ Prod.mk k ⁻¹' s} := by - have hA := h.measurable_action - have hR := h.measurable_feedback calc P {ω | (pullCount A a n ω, sumRewards A R a n ω) ∈ s} - _ = (P.map (fun ω ↦ (pullCount A a n ω, sumRewards A R a n ω))) s := by - rw [Measure.map_apply (by fun_prop) hs]; rfl - _ = ((ArrayModel.arrayMeasure ν).map - (fun ω ↦ (pullCount (ArrayModel.action alg) a n ω, - sumRewards (ArrayModel.action alg) (ArrayModel.reward alg) a n ω))) s := by - rw [h.law_pullCount_sumRewards_unique (ArrayModel.isAlgEnvSeq_arrayMeasure alg ν)] _ = (ArrayModel.arrayMeasure ν) {ω | (pullCount (ArrayModel.action alg) a n ω, - sumRewards (ArrayModel.action alg) (ArrayModel.reward alg) a n ω) ∈ s} := by - rw [Measure.map_apply (by fun_prop) hs]; rfl + sumRewards (ArrayModel.action alg) (ArrayModel.reward alg) a n ω) ∈ s} := + (h.identDistrib_prodMk_pullCount_sumRewards (ArrayModel.isAlgEnvSeq_arrayMeasure alg ν) a + n).measure_mem_eq hs _ ≤ ∑ k ∈ (range (n + 1)).filter (· ∈ Prod.fst '' s), streamMeasure ν {ω | ∑ i ∈ range k, ω i a ∈ Prod.mk k ⁻¹' s} := ArrayModel.prob_pullCount_prod_sumRewards_mem_le a n hs @@ -368,38 +257,19 @@ lemma prob_exists_pullCount_eq_and_sumRewards_mem_le [Countable 𝓐] [Measurabl (ArrayModel.isAlgEnvSeq_arrayMeasure alg ν)).measure_mem_eq hs _ ≤ _ := ArrayModel.prob_exists_pullCount_eq_and_sumRewards_mem_le a m hB -lemma probReal_sumRewards_le_sumRewards_le [Fintype 𝓐] [MeasurableSingletonClass 𝓐] - (h : IsAlgEnvSeq O A R alg (Environment.bandit ν) P) - (a : 𝓐) (n m₁ m₂ : ℕ) : - P.real {ω | pullCount A (bestArm ν) n ω = m₁ ∧ pullCount A a n ω = m₂ ∧ - sumRewards A R (bestArm ν) n ω ≤ sumRewards A R a n ω} ≤ - (streamMeasure ν).real - {ω | ∑ i ∈ range m₁, ω i (bestArm ν) ≤ ∑ i ∈ range m₂, ω i a} := by - have hA := h.measurable_action - have hR := h.measurable_feedback +lemma probReal_sumRewards_le_sumRewards_le [Countable 𝓐] [MeasurableSingletonClass 𝓐] + (h : IsAlgEnvSeq O A R alg (Environment.bandit ν) P) (a b : 𝓐) (n m₁ m₂ : ℕ) : + P.real {ω | pullCount A a n ω = m₁ ∧ pullCount A b n ω = m₂ ∧ + sumRewards A R a n ω ≤ sumRewards A R b n ω} ≤ + (streamMeasure ν).real {ω | ∑ i ∈ range m₁, ω i a ≤ ∑ i ∈ range m₂, ω i b} := by refine le_trans (le_of_eq ?_) - (ArrayModel.probReal_sumRewards_le_sumRewards_le (alg := alg) a n m₁ m₂) + (ArrayModel.probReal_sumRewards_le_sumRewards_le (alg := alg) a b n m₁ m₂) let s := {p : ℕ × ℕ × ℝ × ℝ | p.1 = m₁ ∧ p.2.1 = m₂ ∧ p.2.2.1 ≤ p.2.2.2} have hs : MeasurableSet s := by simp only [measurableSet_setOfPred, s]; fun_prop - change P.real ((fun ω ↦ (pullCount A (bestArm ν) n ω, - pullCount A a n ω, sumRewards A R (bestArm ν) n ω, sumRewards A R a n ω)) ⁻¹' s) = - (ArrayModel.arrayMeasure ν).real - ((fun ω ↦ (pullCount (ArrayModel.action alg) (bestArm ν) n ω, - pullCount (ArrayModel.action alg) a n ω, - sumRewards (ArrayModel.action alg) (ArrayModel.reward alg) (bestArm ν) n ω, - sumRewards (ArrayModel.action alg) (ArrayModel.reward alg) a n ω)) ⁻¹' s) simp_rw [measureReal_def] congr 1 - rw [← Measure.map_apply ?_ hs, ← Measure.map_apply (by fun_prop) hs] - swap - · refine Measurable.prod (by fun_prop) (Measurable.prod (by fun_prop) ?_) - exact (measurable_sumRewards hA hR _ _).prod (measurable_sumRewards hA hR _ _) - congr 1 - refine IdentDistrib.map_eq ?_ - have h_eq := h.law_pullCount_sumRewards_unique' (ArrayModel.isAlgEnvSeq_arrayMeasure alg ν) - (n := n) - exact h_eq.comp (u := fun p ↦ ((p (bestArm ν)).1, (p a).1, (p (bestArm ν)).2, (p a).2)) - (by fun_prop) + exact ((h.identDistrib_pi_pullCount_sumRewards (ArrayModel.isAlgEnvSeq_arrayMeasure alg ν) n).comp + (u := fun p ↦ ((p a).1, (p b).1, (p a).2, (p b).2)) (by fun_prop)).measure_mem_eq hs section Subgaussian @@ -407,7 +277,7 @@ namespace StreamMeasure omit [DecidableEq 𝓐] [Nonempty 𝓐] -lemma prob_sum_range_sub_ge_le_of_HasSubgaussianMGF {σ2 : ℝ≥0} +lemma prob_sum_range_sub_ge_le_of_hasSubgaussianMGF {σ2 : ℝ≥0} (h : HasSubgaussianMGF (fun x ↦ x - (ν a)[id]) σ2 (ν a)) {ε : ℝ} (hε : 0 ≤ ε) (n : ℕ) : streamMeasure ν {ω | ε ≤ ∑ k ∈ range n, (ω k a - (ν a)[id])} ≤ ENNReal.ofReal (Real.exp (-ε ^ 2 / (2 * n * σ2))) := by @@ -418,7 +288,7 @@ lemma prob_sum_range_sub_ge_le_of_HasSubgaussianMGF {σ2 : ℝ≥0} · intro _ _ exact h.congr_identDistrib ((identDistrib_eval_eval_id_streamMeasure _ _ _).symm.sub_const _) -lemma prob_sum_range_sub_le_le_of_HasSubgaussianMGF {σ2 : ℝ≥0} +lemma prob_sum_range_sub_le_le_of_hasSubgaussianMGF {σ2 : ℝ≥0} (h : HasSubgaussianMGF (fun x ↦ x - (ν a)[id]) σ2 (ν a)) {ε : ℝ} (hε : 0 ≤ ε) (n : ℕ) : streamMeasure ν {ω | ∑ k ∈ range n, (ω k a - (ν a)[id]) ≤ -ε} ≤ ENNReal.ofReal (Real.exp (-ε ^ 2 / (2 * n * σ2))) := by @@ -429,8 +299,8 @@ lemma prob_sum_range_sub_le_le_of_HasSubgaussianMGF {σ2 : ℝ≥0} · intro _ _ exact h.congr_identDistrib ((identDistrib_eval_eval_id_streamMeasure _ _ _).symm.sub_const _) -/-- Auxiliary lemma for `prob_sum_range_sub_*_le_of_HasSubgaussianMGF'`. -/ -private lemma exp_neg_sqrt_sq_div_le {σ2 : ℝ≥0} (hσ2 : 0 < σ2) {δ : ℝ} (hδ : 0 < δ) (hn : 0 < n) : +/-- Auxiliary lemma for `prob_sum_range_sub_*_le_of_hasSubgaussianMGF'`. -/ +private lemma exp_neg_sqrt_sq_div_le {σ2 : ℝ≥0} (hσ2 : σ2 ≠ 0) {δ : ℝ} (hδ : 0 < δ) (hn : 0 < n) : Real.exp (-√(2 * n * σ2 * Real.log (1 / δ)) ^ 2 / (2 * n * σ2)) ≤ δ := by by_cases hd : δ < 1 · have hl : 0 < Real.log (1 / δ) := Real.log_pos ((one_lt_div hδ).2 hd) @@ -442,36 +312,42 @@ private lemma exp_neg_sqrt_sq_div_le {σ2 : ℝ≥0} (hσ2 : 0 < σ2) {δ : ℝ} rw [Real.sqrt_eq_zero_of_nonpos (mul_nonpos_of_nonneg_of_nonpos (by positivity) hl)] simp [hd] -lemma prob_sum_range_sub_ge_le_of_HasSubgaussianMGF' {σ2 : ℝ≥0} (hσ2 : 0 < σ2) - (h : HasSubgaussianMGF (fun x ↦ x - (ν a)[id]) σ2 (ν a)) {δ : ℝ} (hδ : 0 < δ) (hn : 0 < n) : +lemma prob_sum_range_sub_ge_le_of_hasSubgaussianMGF' {σ2 : ℝ≥0} + (h : HasSubgaussianMGF (fun x ↦ x - (ν a)[id]) σ2 (ν a)) (hσ2 : σ2 ≠ 0) {δ : ℝ} (hδ : 0 < δ) + (hn : 0 < n) : streamMeasure ν {ω | √(2 * n * σ2 * Real.log (1 / δ)) ≤ ∑ k ∈ range n, (ω k a - (ν a)[id])} ≤ ENNReal.ofReal δ := calc _ ≤ ENNReal.ofReal (Real.exp (-√(2 * n * σ2 * Real.log (1 / δ)) ^ 2 / (2 * n * σ2))) := - prob_sum_range_sub_ge_le_of_HasSubgaussianMGF h (by positivity) n + prob_sum_range_sub_ge_le_of_hasSubgaussianMGF h (by positivity) n _ ≤ ENNReal.ofReal δ := by gcongr exact exp_neg_sqrt_sq_div_le hσ2 hδ hn -lemma prob_sum_range_sub_le_le_of_HasSubgaussianMGF' {σ2 : ℝ≥0} (hσ2 : 0 < σ2) - (h : HasSubgaussianMGF (fun x ↦ x - (ν a)[id]) σ2 (ν a)) {δ : ℝ} (hδ : 0 < δ) (hn : 0 < n) : +lemma prob_sum_range_sub_le_le_of_hasSubgaussianMGF' {σ2 : ℝ≥0} + (h : HasSubgaussianMGF (fun x ↦ x - (ν a)[id]) σ2 (ν a)) (hσ2 : σ2 ≠ 0) {δ : ℝ} (hδ : 0 < δ) + (hn : 0 < n) : streamMeasure ν {ω | ∑ k ∈ range n, (ω k a - (ν a)[id]) ≤ -√(2 * n * σ2 * Real.log (1 / δ))} ≤ ENNReal.ofReal δ := calc _ ≤ ENNReal.ofReal (Real.exp (-√(2 * n * σ2 * Real.log (1 / δ)) ^ 2 / (2 * n * σ2))) := - prob_sum_range_sub_le_le_of_HasSubgaussianMGF h (by positivity) n + prob_sum_range_sub_le_le_of_hasSubgaussianMGF h (by positivity) n _ ≤ ENNReal.ofReal δ := by gcongr exact exp_neg_sqrt_sq_div_le hσ2 hδ hn end StreamMeasure -lemma prob_sumRewards_sub_pullCount_mul_ge_le [Countable 𝓐] [MeasurableSingletonClass 𝓐] - {σ2 : ℝ≥0} (hσ2 : 0 < σ2) (ha : HasSubgaussianMGF (fun x ↦ x - (ν a)[id]) σ2 (ν a)) - (h : IsAlgEnvSeq O A R alg (Environment.bandit ν) P) {δ : ℝ} (hδ : 0 < δ) : - P {ω | ∃ t < n, pullCount A a t ω ≠ 0 ∧ √(2 * pullCount A a t ω * σ2 * Real.log (1 / δ)) ≤ - sumRewards A R a t ω - pullCount A a t ω * (ν a)[id]} ≤ ENNReal.ofReal ((n - 1) * δ) := - let B (m : ℕ) := {x : ℝ | √(2 * m * σ2 * Real.log (1 / δ)) ≤ x - m * (ν a)[id]} +/-- Union bound over the number of pulls: if, for all `m ≠ 0`, the sum of `m` i.i.d. rewards of +action `a` (under `streamMeasure ν`) lies in `B m` with probability at most `δ`, then the +probability that there is a time `t < n` at which `a` has been pulled and the sum of its rewards +lies in `B (pullCount A a t ω)` is at most `(n - 1) * δ`. -/ +lemma prob_exists_sumRewards_mem_le [Countable 𝓐] [MeasurableSingletonClass 𝓐] + (h : IsAlgEnvSeq O A R alg (Environment.bandit ν) P) {B : ℕ → Set ℝ} + (hB : ∀ m, MeasurableSet (B m)) {δ : ℝ} (hδ : 0 ≤ δ) + (h_le : ∀ m, m ≠ 0 → streamMeasure ν {ω | ∑ i ∈ range m, ω i a ∈ B m} ≤ ENNReal.ofReal δ) : + P {ω | ∃ t < n, pullCount A a t ω ≠ 0 ∧ sumRewards A R a t ω ∈ B (pullCount A a t ω)} ≤ + ENNReal.ofReal ((n - 1) * δ) := calc _ ≤ P (⋃ m ∈ Icc 1 (n - 1), {ω | ∃ t, t < n ∧ pullCount A a t ω = m ∧ sumRewards A R a t ω ∈ B m}) := by @@ -485,59 +361,45 @@ lemma prob_sumRewards_sub_pullCount_mul_ge_le [Countable 𝓐] [MeasurableSingle measure_biUnion_finset_le _ _ _ ≤ ∑ m ∈ Icc 1 (n - 1), P {ω | ∃ t, pullCount A a t ω = m ∧ sumRewards A R a t ω ∈ B m} := sum_le_sum (fun _ _ ↦ measure_mono (fun _ ⟨t, _, hps⟩ ↦ ⟨t, hps⟩)) - _ ≤ ∑ m ∈ Icc 1 (n - 1), streamMeasure ν {ω | ∑ i ∈ range m, ω i a ∈ B m} := by - apply sum_le_sum - exact (fun m _ ↦ prob_exists_pullCount_eq_and_sumRewards_mem_le h a m (by measurability)) - _ ≤ ∑ m ∈ Icc 1 (n - 1), ENNReal.ofReal δ := by - apply sum_le_sum - intro m hm - exact le_of_eq_of_le (by simp [B]) - (StreamMeasure.prob_sum_range_sub_ge_le_of_HasSubgaussianMGF' hσ2 ha hδ (mem_Icc.mp hm).1) + _ ≤ ∑ m ∈ Icc 1 (n - 1), streamMeasure ν {ω | ∑ i ∈ range m, ω i a ∈ B m} := + sum_le_sum fun m _ ↦ prob_exists_pullCount_eq_and_sumRewards_mem_le h a m (hB m) + _ ≤ ∑ m ∈ Icc 1 (n - 1), ENNReal.ofReal δ := + sum_le_sum fun m hm ↦ h_le m (Nat.one_le_iff_ne_zero.mp (mem_Icc.mp hm).1) _ = ENNReal.ofReal ((n - 1) * δ) := by by_cases hn : n = 0 - · simp [hn, hδ.le] + · simp [hn, hδ] · rw [sum_const, Nat.card_Icc, add_tsub_cancel_right, ← ENNReal.ofReal_nsmul, nsmul_eq_mul, Nat.cast_sub (Nat.one_le_iff_ne_zero.mpr hn)] ring_nf +lemma prob_sumRewards_sub_pullCount_mul_ge_le [Countable 𝓐] [MeasurableSingletonClass 𝓐] + (h : IsAlgEnvSeq O A R alg (Environment.bandit ν) P) {σ2 : ℝ≥0} + (ha : HasSubgaussianMGF (fun x ↦ x - (ν a)[id]) σ2 (ν a)) (hσ2 : σ2 ≠ 0) {δ : ℝ} (hδ : 0 < δ) : + P {ω | ∃ t < n, pullCount A a t ω ≠ 0 ∧ √(2 * pullCount A a t ω * σ2 * Real.log (1 / δ)) ≤ + sumRewards A R a t ω - pullCount A a t ω * (ν a)[id]} ≤ ENNReal.ofReal ((n - 1) * δ) := + prob_exists_sumRewards_mem_le h + (B := fun m ↦ {x | √(2 * m * σ2 * Real.log (1 / δ)) ≤ x - m * (ν a)[id]}) + (fun _ ↦ measurableSet_le (by fun_prop) (by fun_prop)) hδ.le fun m hm ↦ + le_of_eq_of_le (by simp) (StreamMeasure.prob_sum_range_sub_ge_le_of_hasSubgaussianMGF' ha hσ2 hδ + (Nat.pos_of_ne_zero hm)) + lemma prob_sumRewards_sub_pullCount_mul_le_le [Countable 𝓐] [MeasurableSingletonClass 𝓐] - {σ2 : ℝ≥0} (hσ2 : 0 < σ2) (ha : HasSubgaussianMGF (fun x ↦ x - (ν a)[id]) σ2 (ν a)) - (h : IsAlgEnvSeq O A R alg (Environment.bandit ν) P) {δ : ℝ} (hδ : 0 < δ) : + (h : IsAlgEnvSeq O A R alg (Environment.bandit ν) P) {σ2 : ℝ≥0} + (ha : HasSubgaussianMGF (fun x ↦ x - (ν a)[id]) σ2 (ν a)) (hσ2 : σ2 ≠ 0) {δ : ℝ} (hδ : 0 < δ) : P {ω | ∃ t < n, pullCount A a t ω ≠ 0 ∧ sumRewards A R a t ω - pullCount A a t ω * (ν a)[id] ≤ -√(2 * pullCount A a t ω * σ2 * Real.log (1 / δ))} ≤ ENNReal.ofReal ((n - 1) * δ) := - let B (m : ℕ) := {x : ℝ | x - m * (ν a)[id] ≤ -√(2 * m * σ2 * Real.log (1 / δ))} - calc - _ ≤ P (⋃ m ∈ Icc 1 (n - 1), {ω | ∃ t, t < n ∧ pullCount A a t ω = m ∧ - sumRewards A R a t ω ∈ B m}) := by - apply measure_mono - intro ω ⟨t, ht, hp, hb⟩ - have hm : pullCount A a t ω ∈ Icc 1 (n - 1) := mem_Icc.mpr ⟨Nat.one_le_iff_ne_zero.mpr hp, - (pullCount_le a t ω).trans (Nat.le_sub_one_of_lt ht)⟩ - exact Set.mem_biUnion hm ⟨t, ht, rfl, hb⟩ - _ ≤ ∑ m ∈ Icc 1 (n - 1), P {ω | ∃ t, t < n ∧ pullCount A a t ω = m ∧ - sumRewards A R a t ω ∈ B m} := - measure_biUnion_finset_le _ _ - _ ≤ ∑ m ∈ Icc 1 (n - 1), P {ω | ∃ t, pullCount A a t ω = m ∧ sumRewards A R a t ω ∈ B m} := - sum_le_sum (fun _ _ ↦ measure_mono (fun _ ⟨t, _, hps⟩ ↦ ⟨t, hps⟩)) - _ ≤ ∑ m ∈ Icc 1 (n - 1), streamMeasure ν {ω | ∑ i ∈ range m, ω i a ∈ B m} := by - apply sum_le_sum - exact (fun m _ ↦ prob_exists_pullCount_eq_and_sumRewards_mem_le h a m (by measurability)) - _ ≤ ∑ m ∈ Icc 1 (n - 1), ENNReal.ofReal δ := by - apply sum_le_sum - intro m hm - exact le_of_eq_of_le (by simp [B]) - (StreamMeasure.prob_sum_range_sub_le_le_of_HasSubgaussianMGF' hσ2 ha hδ (mem_Icc.mp hm).1) - _ = ENNReal.ofReal ((n - 1) * δ) := by - by_cases hn : n = 0 - · simp [hn, hδ.le] - · rw [sum_const, Nat.card_Icc, add_tsub_cancel_right, ← ENNReal.ofReal_nsmul, nsmul_eq_mul, - Nat.cast_sub (Nat.one_le_iff_ne_zero.mpr hn)] - ring_nf - -lemma prob_sumRewards_sub_pullCount_mul_ge_le_of_Fintype [Fintype 𝓐] [MeasurableSingletonClass 𝓐] - {σ2 : ℝ≥0} (hσ2 : 0 < σ2) (hν : ∀ a, HasSubgaussianMGF (fun x ↦ x - (ν a)[id]) σ2 (ν a)) - (h : IsAlgEnvSeq O A R alg (Environment.bandit ν) P) {δ : ℝ} (hδ : 0 < δ) : + prob_exists_sumRewards_mem_le h + (B := fun m ↦ {x | x - m * (ν a)[id] ≤ -√(2 * m * σ2 * Real.log (1 / δ))}) + (fun _ ↦ measurableSet_le (by fun_prop) (by fun_prop)) hδ.le fun m hm ↦ + le_of_eq_of_le (by simp) (StreamMeasure.prob_sum_range_sub_le_le_of_hasSubgaussianMGF' ha hσ2 hδ + (Nat.pos_of_ne_zero hm)) + +/-- Union bound over the actions in `prob_sumRewards_sub_pullCount_mul_ge_le`. -/ +lemma prob_exists_sumRewards_sub_pullCount_mul_ge_le [Fintype 𝓐] [MeasurableSingletonClass 𝓐] + (h : IsAlgEnvSeq O A R alg (Environment.bandit ν) P) {σ2 : ℝ≥0} + (hν : ∀ a, HasSubgaussianMGF (fun x ↦ x - (ν a)[id]) σ2 (ν a)) (hσ2 : σ2 ≠ 0) {δ : ℝ} + (hδ : 0 < δ) : P {ω | ∃ a, ∃ t < n, pullCount A a t ω ≠ 0 ∧ √(2 * pullCount A a t ω * σ2 * Real.log (1 / δ)) ≤ sumRewards A R a t ω - pullCount A a t ω * (ν a)[id]} ≤ @@ -549,7 +411,7 @@ lemma prob_sumRewards_sub_pullCount_mul_ge_le_of_Fintype [Fintype 𝓐] [Measura rw [Set.ofPred_exists] exact measure_iUnion_fintype_le _ _ _ ≤ ∑ a, ENNReal.ofReal ((n - 1) * δ) := - sum_le_sum fun a _ ↦ prob_sumRewards_sub_pullCount_mul_ge_le hσ2 (hν a) h hδ + sum_le_sum fun a _ ↦ prob_sumRewards_sub_pullCount_mul_ge_le h (hν a) hσ2 hδ _ = ENNReal.ofReal (Fintype.card 𝓐 * (n - 1) * δ) := by rw [sum_const, Finset.card_univ, ← ENNReal.ofReal_nsmul, nsmul_eq_mul] ring_nf @@ -595,15 +457,8 @@ lemma prob_sum_le_sqrt_log {σ2 : ℝ≥0} calc streamMeasure ν {ω | (∑ s ∈ range k, (ω s a - (ν a)[id])) ≤ - √(2 * c * k * σ2 * Real.log (n + 1))} - _ ≤ ENNReal.ofReal (Real.exp (-(√(2 * c * k * σ2 * Real.log (n + 1))) ^ 2 / (2 * k * σ2))) := by - rw [← ofReal_measureReal] - gcongr - refine (HasSubgaussianMGF.measure_sum_range_le_le_of_iIndepFun (c := σ2) ?_ ?_ (by positivity)) - · exact (iIndepFun_eval_streamMeasure'' ν a).comp (fun i ω ↦ ω - (ν a)[id]) - (fun _ ↦ by fun_prop) - · intro i him - refine (hν a).congr_identDistrib ?_ - exact (identDistrib_eval_eval_id_streamMeasure _ _ _).symm.sub_const _ + _ ≤ ENNReal.ofReal (Real.exp (-(√(2 * c * k * σ2 * Real.log (n + 1))) ^ 2 / (2 * k * σ2))) := + StreamMeasure.prob_sum_range_sub_le_le_of_hasSubgaussianMGF (hν a) (by positivity) k _ = 1 / (n + 1) ^ c := by rw [Real.sq_sqrt] swap; · exact mul_nonneg (by positivity) (Real.log_nonneg (by simp)) @@ -623,15 +478,8 @@ lemma prob_sum_ge_sqrt_log {σ2 : ℝ≥0} calc streamMeasure ν {ω | √(2 * c * k * σ2 * Real.log (n + 1)) ≤ (∑ s ∈ range k, (ω s a - (ν a)[id]))} - _ ≤ ENNReal.ofReal (Real.exp (-(√(2 * c * k * σ2 * Real.log (n + 1))) ^ 2 / (2 * k * σ2))) := by - rw [← ofReal_measureReal] - gcongr - refine (HasSubgaussianMGF.measure_sum_range_ge_le_of_iIndepFun (c := σ2) ?_ ?_ (by positivity)) - · exact (iIndepFun_eval_streamMeasure'' ν a).comp (fun i ω ↦ ω - (ν a)[id]) - (fun _ ↦ by fun_prop) - · intro i him - refine (hν a).congr_identDistrib ?_ - exact (identDistrib_eval_eval_id_streamMeasure _ _ _).symm.sub_const _ + _ ≤ ENNReal.ofReal (Real.exp (-(√(2 * c * k * σ2 * Real.log (n + 1))) ^ 2 / (2 * k * σ2))) := + StreamMeasure.prob_sum_range_sub_ge_le_of_hasSubgaussianMGF (hν a) (by positivity) k _ = 1 / (n + 1) ^ c := by rw [Real.sq_sqrt] swap; · exact mul_nonneg (by positivity) (Real.log_nonneg (by simp)) @@ -698,102 +546,3 @@ lemma prob_avg_sub_sqrt_log_ge {σ2 : ℝ≥0} {c : ℝ} end Subgaussian end Bandits - -namespace Learning.IsBayesAlgEnvSeq - -variable {𝓔 Ω : Type*} [MeasurableSpace 𝓔] [MeasurableSpace Ω] -variable {K : ℕ} [Nonempty (Fin K)] -variable {Q : Measure 𝓔} [IsProbabilityMeasure Q] {κ : Kernel (𝓔 × Fin K) ℝ} [IsMarkovKernel κ] -variable {alg : Algorithm Unit (Fin K) ℝ} -variable {E : Ω → 𝓔} {A : ℕ → Ω → (Fin K)} {R : ℕ → Ω → ℝ} -variable {P : Measure Ω} [IsProbabilityMeasure P] - -/-- Auxiliary lemma for `prob_empMean_sub_actionMean_ge_le`. -/ -private lemma sqrt_two_mul_le_sub {k : ℕ} (hk : k ≠ 0) {s μ σ l : ℝ} - (h : √(2 * σ * l / k) ≤ s / k - μ) : √(2 * k * σ * l) ≤ s - k * μ := by - have hkp : (0 : ℝ) < k := by positivity - calc √(2 * k * σ * l) - _ = √(2 * σ * l / k * k ^ 2) := by - field_simp - _ = √(2 * σ * l / k) * k := by - rw [Real.sqrt_mul' _ (sq_nonneg _), Real.sqrt_sq hkp.le] - _ ≤ (s / k - μ) * k := by - nlinarith - _ = s - k * μ := by - field_simp - -lemma prob_empMean_sub_actionMean_ge_le (h : IsBayesAlgEnvSeq Q κ alg E A R P) {σ2 : ℝ≥0} - (hσ2 : 0 < σ2) (hs : ∀ e a, HasSubgaussianMGF (fun x ↦ x - (κ (e, a))[id]) σ2 (κ (e, a))) - {δ : ℝ} (hδ : 0 < δ) (n : ℕ) : - P {ω | ∃ t < n, ∃ a, pullCount A a t ω ≠ 0 ∧ - √(2 * σ2 * Real.log (1 / δ) / pullCount A a t ω) ≤ empMean A R a t ω - actionMean κ E a ω} - ≤ ENNReal.ofReal (K * (n - 1) * δ) := by - have := h.measurable_param - have := h.measurable_action - have := h.measurable_feedback - let S : Set (𝓔 × (ℕ → Round Unit (Fin K) ℝ)) := - {(e, τ) | ∃ a, ∃ t < n, pullCount IT.action a t τ ≠ 0 ∧ - √(2 * pullCount IT.action a t τ * σ2 * Real.log (1 / δ)) ≤ - sumRewards IT.action IT.feedback a t τ - pullCount IT.action a t τ * actionMean κ id a e} - calc - _ ≤ (P.map (fun ω ↦ (E ω, trajectory (noObs Ω) A R ω))) S := by - rw [Measure.map_apply (by fun_prop) (by measurability)] - apply measure_mono - intro ω ⟨t, ht, a, hpc, hle⟩ - rw [empMean] at hle - exact ⟨a, t, ht, hpc, sqrt_two_mul_le_sub hpc hle⟩ - _ = (P.map E ⊗ₘ condDistrib (trajectory (noObs Ω) A R) E P) S := by - rw [← compProd_map_condDistrib (by fun_prop) (by fun_prop)] - _ = ∫⁻ e, condDistrib (trajectory (noObs Ω) A R) E P e (Prod.mk e ⁻¹' S) ∂(P.map E) := - Measure.compProd_apply (by measurability) - _ ≤ ∫⁻ e, ENNReal.ofReal (Fintype.card (Fin K) * (n - 1) * δ) ∂(P.map E) := by - apply lintegral_mono_ae - rw [h.hasLaw_env.map_eq] - filter_upwards [h.ae_IsAlgEnvSeq] with e he - exact Bandits.prob_sumRewards_sub_pullCount_mul_ge_le_of_Fintype hσ2 (hs e) he hδ - _ = ENNReal.ofReal (K * (n - 1) * δ) := by - simp [Measure.map_apply h.measurable_param] - -/-- Auxiliary lemma for `prob_empMean_bestAction_sub_actionMean_le_le`. -/ -private lemma sub_le_neg_sqrt_two_mul {k : ℕ} (hk : k ≠ 0) {s μ σ l : ℝ} - (h : s / k - μ ≤ -√(2 * σ * l / k)) : s - k * μ ≤ -√(2 * k * σ * l) := by - have : √(2 * k * σ * l) ≤ -s - k * -μ := sqrt_two_mul_le_sub hk (by grind) - linarith - -lemma prob_empMean_bestAction_sub_actionMean_le_le (h : IsBayesAlgEnvSeq Q κ alg E A R P) - {σ2 : ℝ≥0} (hσ2 : 0 < σ2) - (hs : ∀ e a, HasSubgaussianMGF (fun x ↦ x - (κ (e, a))[id]) σ2 (κ (e, a))) - {δ : ℝ} (hδ : 0 < δ) (n : ℕ) : - P {ω | ∃ t < n, pullCount A (bestAction κ E ω) t ω ≠ 0 ∧ - empMean A R (bestAction κ E ω) t ω - actionMean κ E (bestAction κ E ω) ω ≤ - -√(2 * σ2 * Real.log (1 / δ) / (pullCount A (bestAction κ E ω) t ω))} - ≤ ENNReal.ofReal ((n - 1) * δ) := by - have := h.measurable_param - have := h.measurable_action - have := h.measurable_feedback - let S : Set (𝓔 × (ℕ → Round Unit (Fin K) ℝ)) := - {(e, τ) | ∃ t < n, pullCount IT.action (bestAction κ id e) t τ ≠ 0 ∧ - sumRewards IT.action IT.feedback (bestAction κ id e) t τ - - pullCount IT.action (bestAction κ id e) t τ * actionMean κ id (bestAction κ id e) e ≤ - -√(2 * pullCount IT.action (bestAction κ id e) t τ * σ2 * Real.log (1 / δ))} - calc - _ ≤ (P.map (fun ω ↦ (E ω, trajectory (noObs Ω) A R ω))) S := by - rw [Measure.map_apply (by fun_prop) (by measurability)] - apply measure_mono - intro ω ⟨t, ht, hpc, hle⟩ - rw [empMean] at hle - exact ⟨t, ht, hpc, sub_le_neg_sqrt_two_mul hpc hle⟩ - _ = (P.map E ⊗ₘ condDistrib (trajectory (noObs Ω) A R) E P) S := by - rw [← compProd_map_condDistrib (by fun_prop) (by fun_prop)] - _ = ∫⁻ e, condDistrib (trajectory (noObs Ω) A R) E P e (Prod.mk e ⁻¹' S) ∂(P.map E) := - Measure.compProd_apply (by measurability) - _ ≤ ∫⁻ e, ENNReal.ofReal ((n - 1) * δ) ∂(P.map E) := by - apply lintegral_mono_ae - rw [h.hasLaw_env.map_eq] - filter_upwards [h.ae_IsAlgEnvSeq] with e he - exact Bandits.prob_sumRewards_sub_pullCount_mul_le_le (ν := κ.sectR e) hσ2 (hs e _) he - hδ - _ = ENNReal.ofReal ((n - 1) * δ) := by - simp [Measure.map_apply h.measurable_param] - -end Learning.IsBayesAlgEnvSeq diff --git a/LeanMachineLearning/Online/Bandit/Regret.lean b/LeanMachineLearning/Online/Bandit/Regret.lean index 58c5683a..c84952be 100644 --- a/LeanMachineLearning/Online/Bandit/Regret.lean +++ b/LeanMachineLearning/Online/Bandit/Regret.lean @@ -18,6 +18,25 @@ public import LeanMachineLearning.SequentialLearning.FiniteActions kernel `ν : Kernel 𝓐 ℝ` and the outcome `ω : Ω`. * `bestArm ν` is an action with the highest mean. +## Main statements + +* `regret_eq_sum_pullCount_mul_gap`: the regret is `∑ a, pullCount A a t ω * gap ν a` + (regret decomposition). +* `integral_regret_le_of_forall_integral_pullCount_le`: to bound the expected regret, it suffices + to bound the expected number of pulls of each action with positive gap. +* `pullCount_rate_tendsto_of_sublinear_regret`: if the regret is sublinear, the fraction of pulls + of an action with positive gap tends to zero. + +## Implementation notes + +The highest mean is `⨆ a, (ν a)[id]`. If the means are not bounded above (which is only possible if +`𝓐` is infinite), this supremum takes the junk value `0`. + +## References + +* T. Lattimore and C. Szepesvári, *Bandit Algorithms*, Cambridge University Press, 2020, + Chapter 4. + -/ @[expose] public section @@ -28,11 +47,8 @@ open scoped ENNReal NNReal namespace Bandits -variable {𝓞 𝓐 Ω : Type*} [DecidableEq 𝓐] {m𝓞 : MeasurableSpace 𝓞} {m𝓐 : MeasurableSpace 𝓐} - {mΩ : MeasurableSpace Ω} - {ν : Kernel 𝓐 ℝ} - {O : ℕ → Ω → 𝓞} {A : ℕ → Ω → 𝓐} {R : ℕ → Ω → ℝ} - {ω : Ω} {m n t : ℕ} {a : 𝓐} +variable {𝓐 Ω : Type*} [DecidableEq 𝓐] {m𝓐 : MeasurableSpace 𝓐} {mΩ : MeasurableSpace Ω} + {ν : Kernel 𝓐 ℝ} {A : ℕ → Ω → 𝓐} {ω : Ω} {n t : ℕ} {a : 𝓐} /-- Gap of an action `a`: difference between the highest mean of the actions and the mean of `a`. -/ noncomputable @@ -50,11 +66,14 @@ lemma gap_nonneg_of_le {u : ℝ} (h : ∀ a, (ν a)[id] ≤ u) : 0 ≤ gap ν a exact le_ciSup ⟨u, Set.forall_mem_range.2 h⟩ a omit [DecidableEq 𝓐] in -lemma gap_le_of_mem_Icc [Nonempty 𝓐] {l u : ℝ} (h : ∀ a, (ν a)[id] ∈ Set.Icc l u) : +lemma gap_le_of_mem_Icc {l u : ℝ} (h : ∀ a, (ν a)[id] ∈ Set.Icc l u) : gap ν a ≤ u - l := by + have : Nonempty 𝓐 := ⟨a⟩ grind [gap, ciSup_le (fun i ↦ (h i).2)] -/-- Regret of a sequence of pulls `k : ℕ → 𝓐` at time `t` for the reward kernel `ν ; Kernel 𝓐 ℝ`. -/ +/-- Regret of a sequence of pulls `A : ℕ → Ω → 𝓐` at time `t` for the reward kernel +`ν : Kernel 𝓐 ℝ`: difference between `t` times the highest mean and the sum of the means of the +actions pulled before time `t`. -/ noncomputable def regret (ν : Kernel 𝓐 ℝ) (A : ℕ → Ω → 𝓐) (t : ℕ) (ω : Ω) : ℝ := t * (⨆ a, (ν a)[id]) - ∑ s ∈ range t, (ν (A s ω))[id] @@ -79,7 +98,7 @@ lemma regret_eq_sum_pullCount_mul_gap [Fintype 𝓐] : simp_rw [regret_eq_sum_gap, sum_pullCount_mul] lemma integral_regret_eq_sum_gap_mul_integral_pullCount - [StandardBorelSpace 𝓐] [Fintype 𝓐] {P : Measure Ω} [IsProbabilityMeasure P] + [MeasurableSingletonClass 𝓐] [Fintype 𝓐] {P : Measure Ω} [IsFiniteMeasure P] (hA : ∀ n, Measurable (A n)) : P[regret ν A n] = ∑ a, gap ν a * P[fun ω ↦ (pullCount A a n ω : ℝ)] := by simp_rw [regret_eq_sum_pullCount_mul_gap] @@ -91,12 +110,10 @@ lemma integral_regret_eq_sum_gap_mul_integral_pullCount /-- To bound the expected regret, it suffices to bound the expected number of pulls for each action with positive gap. -/ lemma integral_regret_le_of_forall_integral_pullCount_le - [StandardBorelSpace 𝓐] [Fintype 𝓐] {P : Measure Ω} [IsProbabilityMeasure P] - {alg : Algorithm 𝓞 𝓐 ℝ} {env : Environment 𝓞 𝓐 ℝ} {B : 𝓐 → ℝ} - (h : IsAlgEnvSeq O A R alg env P) + [MeasurableSingletonClass 𝓐] [Fintype 𝓐] {P : Measure Ω} [IsFiniteMeasure P] {B : 𝓐 → ℝ} + (hA : ∀ n, Measurable (A n)) (h_le : ∀ a, gap ν a ≠ 0 → ∫ ω, (pullCount A a n ω : ℝ) ∂P ≤ B a) : P[regret ν A n] ≤ ∑ a, gap ν a * B a := by - have hA := h.measurable_action rw [integral_regret_eq_sum_gap_mul_integral_pullCount hA] gcongr 1 with a by_cases h_gap : gap ν a = 0 @@ -109,7 +126,7 @@ section bestArm variable [Fintype 𝓐] [Nonempty 𝓐] -/-- action with the highest mean. -/ +/-- An action with the highest mean. -/ noncomputable def bestArm (ν : Kernel 𝓐 ℝ) : 𝓐 := (exists_max_image univ (fun a ↦ (ν a)[id]) (univ_nonempty_iff.mpr inferInstance)).choose diff --git a/LeanMachineLearning/Online/Bandit/RewardByCountMeasure.lean b/LeanMachineLearning/Online/Bandit/RewardByCountMeasure.lean index c1a02683..7584f1cc 100644 --- a/LeanMachineLearning/Online/Bandit/RewardByCountMeasure.lean +++ b/LeanMachineLearning/Online/Bandit/RewardByCountMeasure.lean @@ -7,9 +7,30 @@ module public import LeanMachineLearning.ForMathlib.Probability.ConditionalProbability public import LeanMachineLearning.ForMathlib.Probability.HasLaw +public import LeanMachineLearning.ForMathlib.Probability.IdentDistrib public import LeanMachineLearning.Online.Bandit.ArrayProbSpace -/-! # Laws of `stepsUntil` and `rewardByCount` +/-! # Law of the rewards by count + +For a stochastic bandit with reward kernel `ν` and an algorithm-environment sequence `(A, R)` on a +probability space `(Ω, P)`, `rewardByCount A R a m` is the reward obtained at the `m`-th pull of +action `a`, defined on the product space `Ω × (ℕ → 𝓐 → ℝ)`, where the second factor is an auxiliary +array of rewards with law `streamMeasure ν`, used when action `a` is pulled fewer than `m` times. + +## Main statements + +* `hasLaw_rewardByCount_infinitePi`: the array `(a, m) ↦ rewardByCount A R a (m + 1)` has law + `⨂ (a, m), ν a` under `P.prod (streamMeasure ν)`. That is, the rewards by count are independent + (`iIndepFun_rewardByCount`) and the reward at the `m`-th pull of `a` has law `ν a` + (`hasLaw_rewardByCount`). +* `condDistrib_rewardByCount_stepsUntil`: the conditional distribution of the reward at the `m`-th + pull of `a` given the time of that pull is the constant kernel with value `ν a`. + +## References + +* T. Lattimore and C. Szepesvári, *Bandit Algorithms*, Cambridge University Press, 2020, + Section 4.6. + -/ @[expose] public section @@ -22,25 +43,23 @@ namespace Bandits variable {𝓐 Ω : Type*} {m𝓐 : MeasurableSpace 𝓐} {mΩ : MeasurableSpace Ω} [DecidableEq 𝓐] {O : ℕ → Ω → Unit} {A : ℕ → Ω → 𝓐} {R : ℕ → Ω → ℝ} {P : Measure Ω} [IsProbabilityMeasure P] {alg : Algorithm Unit 𝓐 ℝ} {ν : Kernel 𝓐 ℝ} [IsMarkovKernel ν] - {h_inter : IsAlgEnvSeq O A R alg (Environment.bandit ν) P} local notation "𝔓" => P.prod (streamMeasure ν) -/-- Law of `Y` conditioned on the event `s`.-/ -notation "𝓛[" Y " | " s "; " μ "]" => Measure.map Y (μ[|s]) -/-- Law of `Y` conditioned on the event that `X` is in `s`. -/ -notation "𝓛[" Y " | " X " in " s "; " μ "]" => Measure.map Y (μ[|X ⁻¹' s]) /-- Law of `Y` conditioned on the event that `X` equals `x`. -/ -notation "𝓛[" Y " | " X " ← " x "; " μ "]" => Measure.map Y (μ[|X ⁻¹' {x}]) +local notation "𝓛[" Y " | " X " ← " x "; " μ "]" => Measure.map Y (μ[|X ⁻¹' {x}]) omit [DecidableEq 𝓐] in -lemma condDistrib_reward'' +/-- Under `P.prod (streamMeasure ν)`, the conditional distribution of the reward at time `n` given +the action at time `n` is `ν`. -/ +lemma condDistrib_reward_fst_prod (h : IsAlgEnvSeq O A R alg (Environment.bandit ν) P) (n : ℕ) : 𝓛[fun ω ↦ R n ω.1 | fun ω ↦ A n ω.1; 𝔓] =ᵐ[(𝔓).map (fun ω ↦ A n ω.1)] ν := by have hA := h.measurable_action have hR := h.measurable_feedback have h_ra' : 𝓛[R n | A n; P] =ᵐ[P.map (A n)] ν := h.condDistrib_feedback_bandit n have h_law : (𝔓).map (fun ω ↦ A n ω.1) = P.map (A n) := by + -- write the function as a composition with `Prod.fst` change ((𝔓).map (A n ∘ Prod.fst)) = _ rw [← Measure.map_map (by fun_prop) (by fun_prop), ← Measure.fst, Measure.fst_prod] rw [h_law] @@ -55,6 +74,8 @@ section CondIndep variable [StandardBorelSpace 𝓐] omit [DecidableEq 𝓐] in +/-- Under `P.prod (streamMeasure ν)`, the law of the reward at time `n` conditioned on the action +at time `n` being `a` is `ν a`. -/ lemma reward_cond_action [Countable 𝓐] (h : IsAlgEnvSeq O A R alg (Environment.bandit ν) P) (a : 𝓐) (n : ℕ) (hμa : (𝔓).map (fun ω ↦ A n ω.1) {a} ≠ 0) : @@ -62,7 +83,7 @@ lemma reward_cond_action [Countable 𝓐] have hA := h.measurable_action have hR := h.measurable_feedback have h_ra : 𝓛[fun ω ↦ R n ω.1 | fun ω ↦ A n ω.1; 𝔓] =ᵐ[(𝔓).map (fun ω ↦ A n ω.1)] ν := - condDistrib_reward'' h n + condDistrib_reward_fst_prod h n have h_eq := condDistrib_ae_eq_cond (μ := 𝔓) (X := fun ω ↦ A n ω.1) (Y := fun ω ↦ R n ω.1) (by fun_prop) (by fun_prop) rw [Filter.EventuallyEq, ae_iff_of_countable] at h_ra h_eq @@ -95,7 +116,7 @@ lemma condIndepFun_reward_stepsUntil_action [StandardBorelSpace Ω] [Countable have hA := h.measurable_action have hR := h.measurable_feedback exact condIndepFun_fst_prod (ν := streamMeasure ν) - (measurable_indicator_stepsUntil_eq h a m n) (by fun_prop) (by fun_prop) + (measurable_indicator_stepsUntil_eq hA a m n) (by fun_prop) (by fun_prop) (condIndepFun_reward_stepsUntil_action' h a m n) lemma reward_cond_stepsUntil [StandardBorelSpace Ω] [Countable 𝓐] @@ -176,51 +197,6 @@ lemma condDistrib_rewardByCount_stepsUntil [StandardBorelSpace Ω] [Countable refine reward_cond_stepsUntil h a m n hm ?_ rwa [Measure.map_apply (by fun_prop) (measurableSet_singleton _)] at hn -/-- The reward received at the `m`-th pull of action `a` has law `ν a`. -/ -lemma hasLaw_rewardByCount [StandardBorelSpace Ω] [Countable 𝓐] - (h : IsAlgEnvSeq O A R alg (Environment.bandit ν) P) (a : 𝓐) (m : ℕ) (hm : m ≠ 0) : - HasLaw (rewardByCount A R a m) (ν a) 𝔓 where - aemeasurable := - (measurable_rewardByCount h.measurable_action h.measurable_feedback a m).aemeasurable - map_eq := by - have hA := h.measurable_action - have hR := h.measurable_feedback - have h_condDistrib : - condDistrib (rewardByCount A R a m) (fun ω ↦ stepsUntil A a m ω.1) 𝔓 - =ᵐ[(𝔓).map (fun ω ↦ stepsUntil A a m ω.1)] - Kernel.const _ (ν a) := condDistrib_rewardByCount_stepsUntil h a m hm - calc (𝔓).map (rewardByCount A R a m) - _ = (condDistrib (rewardByCount A R a m) (fun ω ↦ stepsUntil A a m ω.1) 𝔓) - ∘ₘ ((𝔓).map (fun ω ↦ stepsUntil A a m ω.1)) := by - rw [condDistrib_comp_map (by fun_prop) (by fun_prop)] - _ = (Kernel.const _ (ν a)) ∘ₘ ((𝔓).map (fun ω ↦ stepsUntil A a m ω.1)) := - Measure.comp_congr h_condDistrib - _ = ν a := by simp - -lemma identDistrib_rewardByCount [StandardBorelSpace Ω] [Countable 𝓐] - (h : IsAlgEnvSeq O A R alg (Environment.bandit ν) P) (a : 𝓐) (n m : ℕ) - (hn : n ≠ 0) (hm : m ≠ 0) : - IdentDistrib (rewardByCount A R a n) (rewardByCount A R a m) 𝔓 𝔓 where - aemeasurable_fst := - (measurable_rewardByCount h.measurable_action h.measurable_feedback a n).aemeasurable - aemeasurable_snd := - (measurable_rewardByCount h.measurable_action h.measurable_feedback a m).aemeasurable - map_eq := by rw [(hasLaw_rewardByCount h a n hn).map_eq, (hasLaw_rewardByCount h a m hm).map_eq] - -lemma identDistrib_rewardByCount_id [StandardBorelSpace Ω] [Countable 𝓐] - (h : IsAlgEnvSeq O A R alg (Environment.bandit ν) P) (a : 𝓐) (n : ℕ) (hn : n ≠ 0) : - IdentDistrib (rewardByCount A R a n) id 𝔓 (ν a) where - aemeasurable_fst := - (measurable_rewardByCount h.measurable_action h.measurable_feedback a n).aemeasurable - aemeasurable_snd := Measurable.aemeasurable <| by fun_prop - map_eq := by rw [(hasLaw_rewardByCount h a n hn).map_eq, Measure.map_id] - -lemma identDistrib_rewardByCount_eval [StandardBorelSpace Ω] [Countable 𝓐] - (h : IsAlgEnvSeq O A R alg (Environment.bandit ν) P) (a : 𝓐) (n m : ℕ) (hn : n ≠ 0) : - IdentDistrib (rewardByCount A R a n) (fun ω ↦ ω m a) 𝔓 (streamMeasure ν) := - (identDistrib_rewardByCount_id h a n hn).trans - (identDistrib_eval_eval_id_streamMeasure ν m a).symm - end CondIndep section Independence @@ -383,17 +359,17 @@ lemma identDistrib_rewardByCountUntil_add_one_cond simp only [hW, Function.update_idem] rw [← rewardByCountUntil_apply_of_pullCount_le hk.le, Function.update_eq_self] -- both `(W, R t)` and `(W, ω.2 (k + 1) b)` have law `(μ'.map W).prod (ν b)` - have hW : HasLaw W (μ'.map W) μ' := hWm.hasLaw_map μ' + have hW : HasLaw W (μ'.map W) μ' := hasLaw_map hWm.aemeasurable have h1' : HasLaw (fun ω ↦ Function.update (W ω) (b, k) (R t ω.1)) (((μ'.map W).prod (ν b)).map fun q : (𝓐 × ℕ → ℝ) × ℝ ↦ Function.update q.1 (b, k) q.2) μ' := - ((measurable_update' (a := (b, k))).hasLaw_map _).comp + (hasLaw_map (measurable_update' (a := (b, k))).aemeasurable).comp ((indepFun_update_rewardByCountUntil_reward h t b k).hasLaw_prod hW (hasLaw_reward_cond_prod h t b k hP)) have h2' : HasLaw (fun ω : Ω × (ℕ → 𝓐 → ℝ) ↦ Function.update (W ω) (b, k) (ω.2 (k + 1) b)) (((μ'.map W).prod (ν b)).map fun q : (𝓐 × ℕ → ℝ) × ℝ ↦ Function.update q.1 (b, k) q.2) μ' := - ((measurable_update' (a := (b, k))).hasLaw_map _).comp + (hasLaw_map (measurable_update' (a := (b, k))).aemeasurable).comp ((indepFun_update_rewardByCountUntil_eval hA hR _ t b k).hasLaw_prod hW (hasLaw_snd_apply_prod_streamMeasure _ _ _ _)) exact ((IdentDistrib.of_ae_eq (measurable_rewardByCountUntil hA hR _).aemeasurable h1).trans @@ -411,7 +387,8 @@ lemma identDistrib_rewardByCountUntil_add_one (h : IsAlgEnvSeq O A R alg (Enviro (g := fun ω : Ω × (ℕ → 𝓐 → ℝ) ↦ (A t ω.1, pullCount A (A t ω.1) t ω.1)) (((hA t).comp measurable_fst).prodMk ((measurable_uncurry_pullCount_comp hA (hA t) measurable_const).comp measurable_fst)) - (measurable_rewardByCountUntil hA hR _) (measurable_rewardByCountUntil hA hR _) fun p ↦ ?_ + (measurable_rewardByCountUntil hA hR _).aemeasurable + (measurable_rewardByCountUntil hA hR _).aemeasurable fun p ↦ ?_ have h_eq : (fun ω : Ω × (ℕ → 𝓐 → ℝ) ↦ (A t ω.1, pullCount A (A t ω.1) t ω.1)) ⁻¹' {p} = {x | A t x = p.1 ∧ pullCount A p.1 t x = p.2} ×ˢ Set.univ := by ext ω @@ -443,7 +420,7 @@ lemma hasLaw_rewardByCount_infinitePi (h : IsAlgEnvSeq O A R alg (Environment.ba -- `rewardByCountUntil A R t` has that law for all `t` and converges entrywise to the array exact hasLaw_of_forall_eventually_eq (L := Filter.atTop) (measurable_rewardByCountUntil h.measurable_action h.measurable_feedback) hY.aemeasurable - (hasLaw_rewardByCountUntil h) eventually_rewardByCountUntil_eq + (hasLaw_rewardByCountUntil h) fun p ↦ ae_of_all _ (eventually_rewardByCountUntil_eq · p) /-- The reward received at the `(m + 1)`-th pull of action `a` has law `ν a`. -/ lemma hasLaw_rewardByCount_add_one (h : IsAlgEnvSeq O A R alg (Environment.bandit ν) P) @@ -482,6 +459,28 @@ lemma iIndepFun_rewardByCount_add_one_action (h : IsAlgEnvSeq O A R alg (Environ (iIndepFun_rewardByCount_add_one h).precomp (g := fun m ↦ (a, m)) fun _ _ hmn ↦ (Prod.mk.inj hmn).2 +/-- The reward received at the `m`-th pull of action `a` has law `ν a`, for `m ≠ 0`. -/ +lemma hasLaw_rewardByCount (h : IsAlgEnvSeq O A R alg (Environment.bandit ν) P) (a : 𝓐) (m : ℕ) + (hm : m ≠ 0) : + HasLaw (rewardByCount A R a m) (ν a) 𝔓 := by + obtain ⟨m, rfl⟩ := Nat.exists_eq_add_one_of_ne_zero hm + exact hasLaw_rewardByCount_add_one h a m + +lemma identDistrib_rewardByCount (h : IsAlgEnvSeq O A R alg (Environment.bandit ν) P) (a : 𝓐) + (n m : ℕ) (hn : n ≠ 0) (hm : m ≠ 0) : + IdentDistrib (rewardByCount A R a n) (rewardByCount A R a m) 𝔓 𝔓 := + (hasLaw_rewardByCount h a n hn).identDistrib (hasLaw_rewardByCount h a m hm) + +lemma identDistrib_rewardByCount_id (h : IsAlgEnvSeq O A R alg (Environment.bandit ν) P) (a : 𝓐) + (n : ℕ) (hn : n ≠ 0) : + IdentDistrib (rewardByCount A R a n) id 𝔓 (ν a) := + (hasLaw_rewardByCount h a n hn).identDistrib HasLaw.id + +lemma identDistrib_rewardByCount_eval (h : IsAlgEnvSeq O A R alg (Environment.bandit ν) P) + (a : 𝓐) (n m : ℕ) (hn : n ≠ 0) : + IdentDistrib (rewardByCount A R a n) (fun ω ↦ ω m a) 𝔓 (streamMeasure ν) := + (hasLaw_rewardByCount h a n hn).identDistrib (hasLaw_eval_eval_streamMeasure ν m a) + /-- Two distinct rewards by count are independent. -/ lemma indepFun_rewardByCount (h : IsAlgEnvSeq O A R alg (Environment.bandit ν) P) {a b : 𝓐} {m n : ℕ} (hm : m ≠ 0) (hn : n ≠ 0) (hne : (a, m) ≠ (b, n)) : diff --git a/LeanMachineLearning/SequentialLearning/ActionIndicator.lean b/LeanMachineLearning/SequentialLearning/ActionIndicator.lean index 5b5debc8..0f96a7a6 100644 --- a/LeanMachineLearning/SequentialLearning/ActionIndicator.lean +++ b/LeanMachineLearning/SequentialLearning/ActionIndicator.lean @@ -12,19 +12,18 @@ public import LeanMachineLearning.SequentialLearning.SumRewards `actionIndicator A k n ω = 𝟙{A n ω = k}` is the `{0,1}`-valued indicator that action `k` was chosen at round `n`. It is the increment weight of every per-action sum attached to an action process: -`pullCount A k n` is its partial sum (`sum_range_actionIndicator_eq_pullCount`) and -`sumRewards A Y k n` is its reward-weighted partial sum (`sum_actionIndicator_mul`). - +`pullCount A k n` is its partial sum (`sum_actionIndicator_eq_pullCount`) and +`sumRewards A Y k n` is its reward-weighted partial sum (`sum_actionIndicator_smul`). ## Main definitions * `Learning.actionIndicator` -## Main results +## Main statements -* `Learning.sum_range_actionIndicator_eq_pullCount`, `Learning.sum_actionIndicator_mul` — the two +* `Learning.sum_actionIndicator_eq_pullCount`, `Learning.sum_actionIndicator_smul` — the two partial-sum identities. -* `Learning.adapted_actionIndicator`, `Learning.integrable_actionIndicator`. +* `Learning.IsAlgEnvSeq.adapted_actionIndicator`, `Learning.integrable_actionIndicator`. -/ @[expose] public section @@ -64,7 +63,6 @@ lemma sum_actionIndicator [Fintype 𝓐] (A : ℕ → Ω → 𝓐) (j : ℕ) (ω lemma sum_actionIndicator_eq_pullCount [DecidableEq 𝓐] (A : ℕ → Ω → 𝓐) (k : 𝓐) (n : ℕ) (ω : Ω) : ∑ j ∈ range n, actionIndicator A k j ω = (pullCount A k n ω : ℝ) := by - classical rw [pullCount_eq_sum] push_cast refine Finset.sum_congr rfl fun j _ ↦ ?_ @@ -95,7 +93,7 @@ lemma integrable_actionIndicator (P : Measure Ω) [IsFiniteMeasure P] /-- The action indicator is adapted to the history filtration: whether action `k` was chosen at `n` is known at time `n`. -/ lemma IsAlgEnvSeq.adapted_actionIndicator {alg : Algorithm 𝓞 𝓐 𝓨} {env : Environment 𝓞 𝓐 𝓨} - [IsFiniteMeasure P] (h : IsAlgEnvSeq O A Y alg env P) (k : 𝓐) : + (h : IsAlgEnvSeq O A Y alg env P) (k : 𝓐) : Adapted h.filtration (actionIndicator A k) := fun _ ↦ Measurable.indicator measurable_const (h.adapted_action _ (measurableSet_singleton k)) @@ -103,7 +101,7 @@ lemma IsAlgEnvSeq.adapted_actionIndicator {alg : Algorithm 𝓞 𝓐 𝓨} {env at `n` is known once we know the action at `n`. -/ lemma IsAlgEnvSeq.adapted_actionIndicator_filtrationAction {alg : Algorithm 𝓞 𝓐 𝓨} {env : Environment 𝓞 𝓐 𝓨} - [IsFiniteMeasure P] (h : IsAlgEnvSeq O A Y alg env P) (k : 𝓐) : + (h : IsAlgEnvSeq O A Y alg env P) (k : 𝓐) : Adapted h.filtrationAction (actionIndicator A k) := fun _ ↦ Measurable.indicator measurable_const (h.adapted_action_filtrationAction _ (measurableSet_singleton k)) diff --git a/LeanMachineLearning/SequentialLearning/Algorithm.lean b/LeanMachineLearning/SequentialLearning/Algorithm.lean index 20159435..956fe1cf 100644 --- a/LeanMachineLearning/SequentialLearning/Algorithm.lean +++ b/LeanMachineLearning/SequentialLearning/Algorithm.lean @@ -5,7 +5,9 @@ Authors: Rémy Degenne, Paulo Rauber -/ module -public import LeanMachineLearning.ForMathlib.MeasureTheory.Measurable +public import LeanMachineLearning.ForMathlib.Basic.Unique +public import LeanMachineLearning.ForMathlib.MeasureTheory.MeasurableSpace.Basic +public import LeanMachineLearning.ForMathlib.MeasureTheory.MeasurableSpace.Instances public import LeanMachineLearning.ForMathlib.Probability.Kernel.IonescuTulcea.Traj public import LeanMachineLearning.ForMathlib.Probability.Kernel.MeasurableSpace @@ -32,13 +34,21 @@ applied to the empty history (the unique element of `Hist 𝓞 𝓐 𝓨 0`). * `Hist 𝓞 𝓐 𝓨 n`: a history of `n` complete rounds. * `Algorithm 𝓞 𝓐 𝓨`: a stochastic, sequential algorithm. * `Environment 𝓞 𝓐 𝓨`: a stochastic environment. -* `history O A Y n`: the history before time `n`, a random variable with values in `Hist 𝓞 𝓐 𝓨 n`. +* `Environment.obsZero`, `Algorithm.policyZero`, `Environment.feedbackZero`: the laws of the first + round, in which the history is empty. +* `stepKernel alg env n`: the law of the round at time `n` given the history before `n`. +* `step O A Y n`, `history O A Y n`, `trajectory O A Y`: the round at time `n`, the history before + time `n` (a random variable with values in `Hist 𝓞 𝓐 𝓨 n`) and the sequence of all rounds. * `IsAlgEnvSeq O A Y alg env P`: an algorithm-environment sequence. That is, a sequence of observations `O`, actions `A` and feedbacks `Y` that have the correct conditional distributions to be generated by an algorithm `alg` interacting with an environment `env`, defined on a - probability space `(Ω, P)`. + measure space `(Ω, P)` (in applications, a probability space). * `IsAlgEnvSeqUntil O A Y alg env P N`: `O`, `A` and `Y` form an algorithm-environment sequence for the times `n < N`. +* `IsAlgEnvSeq.filtration`, `IsAlgEnvSeq.filtrationObs`, `IsAlgEnvSeq.filtrationAction`: the + filtrations generated by the rounds up to time `n`, and by the history before time `n` together + with the observation (and the action) at time `n`. +* `noObs Ω`: the observation process of an algorithm-environment sequence with `𝓞 = Unit`. -/ @@ -48,11 +58,6 @@ open MeasureTheory ProbabilityTheory Filter Real Finset open scoped ENNReal NNReal --- TODO: this belongs to Mathlib. -instance Prod.instUnique {α β : Type*} [Unique α] [Unique β] : Unique (α × β) where - default := (default, default) - uniq p := by simp [Prod.ext_iff, Unique.eq_default] - namespace Learning variable {𝓞 𝓐 𝓨 Ω : Type*} {m𝓞 : MeasurableSpace 𝓞} {m𝓐 : MeasurableSpace 𝓐} @@ -223,7 +228,7 @@ section IsAlgEnvSeq variable {O : ℕ → Ω → 𝓞} {A : ℕ → Ω → 𝓐} {Y : ℕ → Ω → 𝓨} {alg : Algorithm 𝓞 𝓐 𝓨} {env : Environment 𝓞 𝓐 𝓨} - {P : Measure Ω} [IsFiniteMeasure P] {N : ℕ} + {P : Measure Ω} {N : ℕ} /-- Step of the algorithm-environment sequence: the round at time `n`. -/ def step (O : ℕ → Ω → 𝓞) (A : ℕ → Ω → 𝓐) (Y : ℕ → Ω → 𝓨) (n : ℕ) (ω : Ω) : Round 𝓞 𝓐 𝓨 := @@ -245,9 +250,8 @@ def trajectory (O : ℕ → Ω → 𝓞) (A : ℕ → Ω → 𝓐) (Y : ℕ → fun n ↦ (O n ω, A n ω, Y n ω) @[fun_prop] -lemma measurable_trajectory {O : ℕ → Ω → 𝓞} {A : ℕ → Ω → 𝓐} {Y : ℕ → Ω → 𝓨} - (hO : ∀ n, Measurable (O n)) (hA : ∀ n, Measurable (A n)) - (hR : ∀ n, Measurable (Y n)) : Measurable (trajectory O A Y) := by +lemma measurable_trajectory (hO : ∀ n, Measurable (O n)) (hA : ∀ n, Measurable (A n)) + (hY : ∀ n, Measurable (Y n)) : Measurable (trajectory O A Y) := by unfold trajectory fun_prop @@ -311,7 +315,7 @@ by an algorithm interacting with an environment. -/ structure IsAlgEnvSeq (O : ℕ → Ω → 𝓞) (A : ℕ → Ω → 𝓐) (Y : ℕ → Ω → 𝓨) (alg : Algorithm 𝓞 𝓐 𝓨) (env : Environment 𝓞 𝓐 𝓨) - (P : Measure Ω) [IsFiniteMeasure P] : Prop where + (P : Measure Ω) : Prop where /-- The observation sequence is measurable. -/ measurable_obs n : Measurable (O n) := by fun_prop /-- The action sequence is measurable. -/ @@ -336,7 +340,7 @@ an environment. In particular, the law of `history O A Y N` is determined. -/ structure IsAlgEnvSeqUntil (O : ℕ → Ω → 𝓞) (A : ℕ → Ω → 𝓐) (Y : ℕ → Ω → 𝓨) (alg : Algorithm 𝓞 𝓐 𝓨) (env : Environment 𝓞 𝓐 𝓨) - (P : Measure Ω) [IsFiniteMeasure P] (N : ℕ) : Prop where + (P : Measure Ω) (N : ℕ) : Prop where /-- The observation sequence is measurable. -/ measurable_obs n : Measurable (O n) := by fun_prop /-- The action sequence is measurable. -/ @@ -450,25 +454,25 @@ lemma IsAlgEnvSeqUntil.measurable_history (h : IsAlgEnvSeqUntil O A Y alg env P lemma IsAlgEnvSeq.hasCondDistrib_step (h : IsAlgEnvSeq O A Y alg env P) (n : ℕ) : HasCondDistrib (step O A Y n) (history O A Y n) (stepKernel alg env n) P := - (h.hasCondDistrib_obs n).prod - ((h.hasCondDistrib_action n).prod (h.hasCondDistrib_feedback n)) + (h.hasCondDistrib_obs n).compProd + ((h.hasCondDistrib_action n).compProd (h.hasCondDistrib_feedback n)) lemma IsAlgEnvSeqUntil.hasCondDistrib_step (h : IsAlgEnvSeqUntil O A Y alg env P N) (n : ℕ) (hn : n < N) : HasCondDistrib (step O A Y n) (history O A Y n) (stepKernel alg env n) P := - (h.hasCondDistrib_obs n hn).prod - ((h.hasCondDistrib_action n hn).prod (h.hasCondDistrib_feedback n hn)) + (h.hasCondDistrib_obs n hn).compProd + ((h.hasCondDistrib_action n hn).compProd (h.hasCondDistrib_feedback n hn)) section Zero /-! ### Laws at time `0` At time `0` the history is the unique element of `Hist 𝓞 𝓐 𝓨 0`: conditioning on it is the same -as not conditioning. Note that those results need `P` to be a probability measure. -/ +as not conditioning. The statements about laws (`HasLaw`) need `P` to be a probability measure, +while the statements about conditional distributions hold for s-finite measures. -/ variable [IsProbabilityMeasure P] -omit [IsFiniteMeasure P] in /-- The history before time `0` is a constant. -/ lemma hasLaw_history_zero (O : ℕ → Ω → 𝓞) (A : ℕ → Ω → 𝓐) (Y : ℕ → Ω → 𝓨) : HasLaw (history O A Y 0) (Measure.dirac default) P where @@ -486,19 +490,19 @@ lemma IsAlgEnvSeq.hasLaw_obs_zero (h : IsAlgEnvSeq O A Y alg env P) : (h.isAlgEnvSeqUntil 1).hasLaw_obs_zero zero_lt_one omit [IsProbabilityMeasure P] in -lemma IsAlgEnvSeqUntil.hasCondDistrib_action_zero (h : IsAlgEnvSeqUntil O A Y alg env P N) - (hN : 0 < N) : +lemma IsAlgEnvSeqUntil.hasCondDistrib_action_zero [SFinite P] + (h : IsAlgEnvSeqUntil O A Y alg env P N) (hN : 0 < N) : HasCondDistrib (A 0) (O 0) alg.policyZero P := hasCondDistrib_prodMk_left_unique_iff.mp (h.hasCondDistrib_action 0 hN) omit [IsProbabilityMeasure P] in -lemma IsAlgEnvSeq.hasCondDistrib_action_zero (h : IsAlgEnvSeq O A Y alg env P) : +lemma IsAlgEnvSeq.hasCondDistrib_action_zero [SFinite P] (h : IsAlgEnvSeq O A Y alg env P) : HasCondDistrib (A 0) (O 0) alg.policyZero P := (h.isAlgEnvSeqUntil 1).hasCondDistrib_action_zero zero_lt_one omit [IsProbabilityMeasure P] in -lemma IsAlgEnvSeqUntil.hasCondDistrib_feedback_zero (h : IsAlgEnvSeqUntil O A Y alg env P N) - (hN : 0 < N) : +lemma IsAlgEnvSeqUntil.hasCondDistrib_feedback_zero [SFinite P] + (h : IsAlgEnvSeqUntil O A Y alg env P N) (hN : 0 < N) : HasCondDistrib (Y 0) (fun ω ↦ (O 0 ω, A 0 ω)) env.feedbackZero P := by have h0 := h.hasCondDistrib_feedback 0 hN rw [history_zero] at h0 @@ -506,7 +510,7 @@ lemma IsAlgEnvSeqUntil.hasCondDistrib_feedback_zero (h : IsAlgEnvSeqUntil O A Y ((measurableEmbedding_prodMk_left (default : Hist 𝓞 𝓐 𝓨 0)).prodMap .id) omit [IsProbabilityMeasure P] in -lemma IsAlgEnvSeq.hasCondDistrib_feedback_zero (h : IsAlgEnvSeq O A Y alg env P) : +lemma IsAlgEnvSeq.hasCondDistrib_feedback_zero [SFinite P] (h : IsAlgEnvSeq O A Y alg env P) : HasCondDistrib (Y 0) (fun ω ↦ (O 0 ω, A 0 ω)) env.feedbackZero P := (h.isAlgEnvSeqUntil 1).hasCondDistrib_feedback_zero zero_lt_one @@ -523,30 +527,30 @@ lemma IsAlgEnvSeq.hasLaw_step_zero (h : IsAlgEnvSeq O A Y alg env P) : end Zero -lemma IsAlgEnvSeq.hasLaw_obs_comp (h : IsAlgEnvSeq O A Y alg env P) (n : ℕ) : +lemma IsAlgEnvSeq.hasLaw_obs_comp [SFinite P] (h : IsAlgEnvSeq O A Y alg env P) (n : ℕ) : HasLaw (O n) (env.obs n ∘ₘ (P.map (history O A Y n))) P := HasCondDistrib.hasLaw_comp (h.hasCondDistrib_obs n) -lemma IsAlgEnvSeq.hasLaw_action_comp (h : IsAlgEnvSeq O A Y alg env P) (n : ℕ) : +lemma IsAlgEnvSeq.hasLaw_action_comp [SFinite P] (h : IsAlgEnvSeq O A Y alg env P) (n : ℕ) : HasLaw (A n) (alg.policy n ∘ₘ (P.map fun ω ↦ (history O A Y n ω, O n ω))) P := HasCondDistrib.hasLaw_comp (h.hasCondDistrib_action n) -lemma IsAlgEnvSeq.hasLaw_feedback_comp (h : IsAlgEnvSeq O A Y alg env P) (n : ℕ) : +lemma IsAlgEnvSeq.hasLaw_feedback_comp [SFinite P] (h : IsAlgEnvSeq O A Y alg env P) (n : ℕ) : HasLaw (Y n) ((env.feedback n) ∘ₘ (P.map fun ω ↦ ((history O A Y n ω, O n ω), A n ω))) P := HasCondDistrib.hasLaw_comp (h.hasCondDistrib_feedback n) -lemma IsAlgEnvSeq.hasLaw_step_comp (h : IsAlgEnvSeq O A Y alg env P) (n : ℕ) : +lemma IsAlgEnvSeq.hasLaw_step_comp [SFinite P] (h : IsAlgEnvSeq O A Y alg env P) (n : ℕ) : HasLaw (step O A Y n) (stepKernel alg env n ∘ₘ (P.map (history O A Y n))) P := HasCondDistrib.hasLaw_comp (h.hasCondDistrib_step n) /-- Conditionally on the event `(O 0, A 0) = p`, the first feedback has law `env.feedbackZero p`. -/ -lemma IsAlgEnvSeq.hasLaw_feedback_zero_cond [MeasurableSingletonClass 𝓞] +lemma IsAlgEnvSeq.hasLaw_feedback_zero_cond [IsFiniteMeasure P] [MeasurableSingletonClass 𝓞] [MeasurableSingletonClass 𝓐] (h : IsAlgEnvSeq O A Y alg env P) {p : 𝓞 × 𝓐} (hP : P ((fun ω ↦ (O 0 ω, A 0 ω)) ⁻¹' {p}) ≠ 0) : HasLaw (Y 0) (env.feedbackZero p) P[|(fun ω ↦ (O 0 ω, A 0 ω)) ⁻¹' {p}] := - h.hasCondDistrib_feedback_zero.hasLaw_cond (h.measurable_feedback 0) - (measurableSet_singleton p) (fun a ha ↦ by rw [Set.mem_singleton_iff.1 ha]) hP + h.hasCondDistrib_feedback_zero.hasLaw_cond (measurableSet_singleton p) + (fun a ha ↦ by rw [Set.mem_singleton_iff.1 ha]) hP section Filtration @@ -748,36 +752,6 @@ the algorithm only sees the past rounds. Since `Unit` carries a unique probabili observation kernels of such an environment are all equal to `Kernel.const _ (Measure.dirac ())`, and the observation process of an algorithm-environment sequence is `noObs`. -/ -/-- Every probability measure on `Unit` is `Measure.dirac ()`. -/ -lemma Measure.eq_dirac_unit (μ : Measure Unit) [IsProbabilityMeasure μ] : - μ = Measure.dirac () := by - ext s hs - rcases Set.eq_empty_or_nonempty s with rfl | ⟨u, hu⟩ - · simp - · have hs_univ : s = Set.univ := Set.eq_univ_of_forall fun x ↦ by rwa [Subsingleton.elim x u] - simp [hs_univ] - -/-- Every Markov kernel with codomain `Unit` is the constant kernel at `Measure.dirac ()`. -/ -lemma Kernel.eq_const_dirac_unit {α : Type*} {mα : MeasurableSpace α} (κ : Kernel α Unit) - [IsMarkovKernel κ] : - κ = Kernel.const α (Measure.dirac ()) := by - ext a : 1 - rw [Kernel.const_apply] - exact Measure.eq_dirac_unit (κ a) - -/-- A random variable with values in `Unit` admits any Markov kernel as conditional -distribution. -/ -lemma hasCondDistrib_unit {α : Type*} {mα : MeasurableSpace α} {P : Measure Ω} - [IsProbabilityMeasure P] {X : Ω → α} (hX : AEMeasurable X P) (U : Ω → Unit) - (κ : Kernel α Unit) [IsMarkovKernel κ] : - HasCondDistrib U X κ P := by - have hU : U = fun _ ↦ () := funext fun _ ↦ rfl - subst hU - refine HasLaw.mk (hX.prodMk aemeasurable_const) ?_ - rw [Kernel.eq_const_dirac_unit κ, Measure.compProd_const, Measure.prod_dirac, - AEMeasurable.map_map_of_aemeasurable (by fun_prop) hX] - rfl - /-- The observation process of an algorithm-environment sequence without observations. -/ def noObs (Ω : Type*) : ℕ → Ω → Unit := fun _ _ ↦ () diff --git a/LeanMachineLearning/SequentialLearning/AlgorithmDensity.lean b/LeanMachineLearning/SequentialLearning/AlgorithmDensity.lean index 0175947c..6a72ab12 100644 --- a/LeanMachineLearning/SequentialLearning/AlgorithmDensity.lean +++ b/LeanMachineLearning/SequentialLearning/AlgorithmDensity.lean @@ -5,8 +5,10 @@ Authors: Paulo Rauber -/ module +public import LeanMachineLearning.ForMathlib.MeasureTheory.Measure.WithDensity public import LeanMachineLearning.ForMathlib.Probability.Kernel.Composition.MeasureCompProd -public import LeanMachineLearning.ForMathlib.Probability.WithDensity +public import LeanMachineLearning.ForMathlib.Probability.Kernel.Composition.WithDensity +public import LeanMachineLearning.ForMathlib.Probability.Kernel.RadonNikodym public import LeanMachineLearning.SequentialLearning.Algorithm /-! @@ -19,22 +21,22 @@ concept that we also introduce here. ## Main definitions -* `AbsolutelyContinuous alg alg₀`: `alg` is absolutely continuous with respect to `alg₀` (also - denoted `alg ≪ₐ alg₀`) when, in every situation, a set of actions with probability zero under - `alg₀` also has probability zero under `alg`. Intuitively, `alg` never acts in a way that `alg₀` - would never act. -* `density alg alg₀ n`: a density function that allows obtaining the law of the history at time `n` - under `alg` from the law of the history at time `n` under `alg₀` when they are interacting with - the same environment and `alg ≪ₐ alg₀`. +* `Algorithm.AbsolutelyContinuous alg alg₀`: `alg` is absolutely continuous with respect to `alg₀` + (also denoted `alg ≪ₐ alg₀`) when, in every situation, a set of actions with probability zero + under `alg₀` also has probability zero under `alg`. Intuitively, `alg` never acts in a way that + `alg₀` would never act. +* `Algorithm.density alg alg₀ n`: a density function that allows obtaining the law of the history + at time `n` under `alg` from the law of the history at time `n` under `alg₀` when they are + interacting with the same environment and `alg ≪ₐ alg₀`. -## Main results +## Main statements -* `absolutelyContinuous_map_hist`: the law of the history at time `n` under `alg` is absolutely - continuous with respect to the law of the history at time `n` under `alg₀` when they - are interacting with the same environment and `alg ≪ₐ alg₀`. -* `hasLaw_history_withDensity`: the law of the history at time `n` under `alg` is the law of the - history at time `n` under `alg₀` with density `alg.density alg₀ n` when they are interacting - with the same environment and `alg ≪ₐ alg₀`. +* `IsAlgEnvSeq.absolutelyContinuous_map_history`: the law of the history at time `n` under `alg` + is absolutely continuous with respect to the law of the history at time `n` under `alg₀` when + they are interacting with the same environment and `alg ≪ₐ alg₀`. +* `IsAlgEnvSeq.hasLaw_history_withDensity`: the law of the history at time `n` under `alg` is the + law of the history at time `n` under `alg₀` with density `alg.density alg₀ n` when they are + interacting with the same environment and `alg ≪ₐ alg₀`. -/ @@ -62,9 +64,21 @@ lemma AbsolutelyContinuous.policyZero {alg alg₀ : Algorithm 𝓞 𝓐 𝓨} (h alg.policyZero o ≪ alg₀.policyZero o := h.policy 0 (default, o) -/-- If the algorithm `alg` is absolutely continuous with respect to the algorithm `alg₀` and they -are both interacting with the same environment, then the law of the history before time `n` under -`alg` is the law of the history before time `n` under `alg₀` with density `alg.density alg₀ n`. -/ +@[refl] +lemma AbsolutelyContinuous.refl (alg : Algorithm 𝓞 𝓐 𝓨) : alg ≪ₐ alg where + policy _ _ := Measure.AbsolutelyContinuous.rfl + +lemma AbsolutelyContinuous.trans {alg₁ alg₂ alg₃ : Algorithm 𝓞 𝓐 𝓨} (h₁₂ : alg₁ ≪ₐ alg₂) + (h₂₃ : alg₂ ≪ₐ alg₃) : + alg₁ ≪ₐ alg₃ where + policy n h := (h₁₂.policy n h).trans (h₂₃.policy n h) + +/-- The density of the law of the history before time `n` under the algorithm `alg` with respect +to its law under the algorithm `alg₀`, in a common environment: the product over the rounds of the +Radon-Nikodym derivatives of the policies at the actions taken. +If `alg ≪ₐ alg₀`, the law of the history before time `n` under `alg` is the law of the history +before time `n` under `alg₀` with density `alg.density alg₀ n` +(`IsAlgEnvSeq.hasLaw_history_withDensity`). -/ noncomputable def density [MeasurableSpace.CountablyGenerated 𝓐] (alg alg₀ : Algorithm 𝓞 𝓐 𝓨) : (n : ℕ) → Hist 𝓞 𝓐 𝓨 n → ℝ≥0∞ @@ -135,7 +149,7 @@ lemma hasLaw_history_withDensity (h : IsAlgEnvSeq O A Y alg env P) induction n with | zero => rw [(hasLaw_history_zero O A Y).map_eq, (hasLaw_history_zero O₀ A₀ Y₀).map_eq, - show alg.density alg₀ 0 = 1 from rfl, withDensity_one] + show alg.density alg₀ 0 = 1 from funext (Algorithm.density_zero alg alg₀), withDensity_one] | succ n ih => let ρ h' (r : Round 𝓞 𝓐 𝓨) := Kernel.rnDeriv (alg.policy n) (alg₀.policy n) (h', r.obs) r.action diff --git a/LeanMachineLearning/SequentialLearning/AlgorithmDensityBayes.lean b/LeanMachineLearning/SequentialLearning/AlgorithmDensityBayes.lean index be324371..7c05f891 100644 --- a/LeanMachineLearning/SequentialLearning/AlgorithmDensityBayes.lean +++ b/LeanMachineLearning/SequentialLearning/AlgorithmDensityBayes.lean @@ -14,19 +14,20 @@ public import LeanMachineLearning.SequentialLearning.BayesStationaryEnv This file provides results about `Algorithm.density` for the Bayesian stationary environment setting. -## Main results +## Main statements Let `h : IsBayesAlgEnvSeq Q κ alg E A Y P`, `h₀ : IsBayesAlgEnvSeq Q κ alg₀ E₀ A₀ Y₀ P₀`, and `hc : alg ≪ₐ alg₀`. -* `hasLaw_hist_withDensity h h₀ hc n`: the law of the history at time `n` under `P` is the law of - the history at time `n` under `P₀` with density `alg.density alg₀ n`. Intuitively, the law of the - history under `alg` can be obtained from the law of the history under `alg₀` when they are - interacting with underlying stationary environments drawn from the same distribution. -* `hasCondDistrib_env_history h h₀ hc n`: the conditional distribution of `E` given the history - at time `n` under `P` is almost everywhere equal to the conditional distribution of `E₀` given - the history at time `n` under `P₀`. Intuitively, the posterior is independent of the algorithm - used to observe the history. +* `IsBayesAlgEnvSeq.hasLaw_history_withDensity h h₀ hc n`: the law of the history at time `n` + under `P` is the law of the history at time `n` under `P₀` with density `alg.density alg₀ n`. + Intuitively, the law of the history under `alg` can be obtained from the law of the history + under `alg₀` when they are interacting with underlying stationary environments drawn from the + same distribution. +* `IsBayesAlgEnvSeq.hasCondDistrib_env_history h h₀ hc n`: the conditional distribution of `E` + given the history at time `n` under `P` is almost everywhere equal to the conditional + distribution of `E₀` given the history at time `n` under `P₀`. Intuitively, the posterior is + independent of the algorithm used to observe the history. -/ @@ -56,16 +57,22 @@ variable {E₀ : Ω₀ → 𝓔} {A₀ : ℕ → Ω₀ → 𝓐} {Y₀ : ℕ → variable {alg₀ : Algorithm Unit 𝓐 𝓨} variable {P₀ : Measure Ω₀} [IsProbabilityMeasure P₀] -lemma condDistrib_history_eq_condDistrib_hist_withDensity (h : IsBayesAlgEnvSeq Q κ alg E A Y P) +/-- The conditional law of the history given the parameter under `alg` is, for almost all +parameters, the conditional law of the history given the parameter under `alg₀` with density +`alg.density alg₀ n`. -/ +lemma condDistrib_history_ae_eq_withDensity (h : IsBayesAlgEnvSeq Q κ alg E A Y P) (h₀ : IsBayesAlgEnvSeq Q κ alg₀ E₀ A₀ Y₀ P₀) (hc : alg ≪ₐ alg₀) (n : ℕ) : condDistrib (history (noObs Ω) A Y n) E P =ᵐ[Q] ((condDistrib (history (noObs Ω₀) A₀ Y₀ n) E₀ P₀).withDensity (fun _ ↦ alg.density alg₀ n)) := by - filter_upwards [h.ae_IsAlgEnvSeq, h₀.ae_IsAlgEnvSeq, h.hasLaw_IT_hist n, h₀.hasLaw_IT_hist n] - with _ hae hae₀ he he₀ - rw [Kernel.withDensity_apply _ (by fun_prop), ← he.map_eq, ← he₀.map_eq] - exact (hae.hasLaw_history_withDensity hae₀ hc n).map_eq - + filter_upwards [h.ae_isAlgEnvSeq, h₀.ae_isAlgEnvSeq, h.hasLaw_IT_hist n, h₀.hasLaw_IT_hist n] + with _ hae hae₀ he he₀ + rw [Kernel.withDensity_apply _ (by fun_prop), ← he.map_eq, ← he₀.map_eq] + exact (hae.hasLaw_history_withDensity hae₀ hc n).map_eq + +/-- The law of the history under `alg` is the law of the history under `alg₀` with density +`alg.density alg₀ n`, when the two algorithms interact with Bayesian stationary environments with +the same prior. -/ lemma hasLaw_history_withDensity (h : IsBayesAlgEnvSeq Q κ alg E A Y P) (h₀ : IsBayesAlgEnvSeq Q κ alg₀ E₀ A₀ Y₀ P₀) (hc : alg ≪ₐ alg₀) (n : ℕ) : HasLaw (history (noObs Ω) A Y n) @@ -82,12 +89,15 @@ lemma hasLaw_history_withDensity (h : IsBayesAlgEnvSeq Q κ alg E A Y P) have hE := h.measurable_param have hE₀ := h₀.measurable_param rw [← condDistrib_comp_map hE.aemeasurable (by fun_prop), h.hasLaw_env.map_eq, - Measure.bind_congr_right (h.condDistrib_history_eq_condDistrib_hist_withDensity h₀ hc n), - ← Measure.withDensity_comp (by fun_prop), - ← h₀.hasLaw_env.map_eq, condDistrib_comp_map hE₀.aemeasurable (by fun_prop)] + Measure.bind_congr_right (h.condDistrib_history_ae_eq_withDensity h₀ hc n), + ← Measure.withDensity_comp (by fun_prop), + ← h₀.hasLaw_env.map_eq, condDistrib_comp_map hE₀.aemeasurable (by fun_prop)] variable [StandardBorelSpace 𝓔] [Nonempty 𝓔] +/-- The posterior distribution of the parameter given the history does not depend on the +algorithm: the conditional law of `E` given the history under `alg` is the conditional law of `E₀` +given the history under `alg₀`. -/ lemma hasCondDistrib_env_history (h : IsBayesAlgEnvSeq Q κ alg E A Y P) (h₀ : IsBayesAlgEnvSeq Q κ alg₀ E₀ A₀ Y₀ P₀) (hc : alg ≪ₐ alg₀) (n : ℕ) : HasCondDistrib E (history (noObs Ω) A Y n) @@ -105,7 +115,7 @@ lemma hasCondDistrib_env_history (h : IsBayesAlgEnvSeq Q κ alg E A Y P) have hE₀ := h₀.measurable_param rw [← map_swap_compProd_map_condDistrib (by fun_prop) (by fun_prop), h.hasLaw_env.map_eq, Measure.compProd_eq_compProd_withDensity_comp_snd (by fun_prop) - (h.condDistrib_history_eq_condDistrib_hist_withDensity h₀ hc n), + (h.condDistrib_history_ae_eq_withDensity h₀ hc n), map_swap_withDensity_comp_snd (by fun_prop), ← h₀.hasLaw_env.map_eq, map_swap_compProd_map_condDistrib (by fun_prop) (by fun_prop), ← compProd_map_condDistrib (by fun_prop) (by fun_prop), diff --git a/LeanMachineLearning/SequentialLearning/Algorithms/Markov.lean b/LeanMachineLearning/SequentialLearning/Algorithms/Markov.lean index 3a612140..12c25e01 100644 --- a/LeanMachineLearning/SequentialLearning/Algorithms/Markov.lean +++ b/LeanMachineLearning/SequentialLearning/Algorithms/Markov.lean @@ -5,6 +5,7 @@ Authors: Rémy Degenne, Paulo Rauber -/ module +public import LeanMachineLearning.ForMathlib.Probability.Independence.Conditional public import LeanMachineLearning.ForMathlib.Probability.Kernel.Composition.MapComap public import LeanMachineLearning.SequentialLearning.Algorithm @@ -28,10 +29,10 @@ observation. We say that `alg` is a *Markov algorithm* if there exists a sequenc ## Main statements -* `Algorithm.IsMarkov.hasCondDistrib_action`: in a run of a Markov algorithm, the conditional +* `IsAlgEnvSeq.hasCondDistrib_action_policyCondObs`: in a run of a Markov algorithm, the conditional distribution of the action at time `n` given the observation at time `n` is `alg.policyCondObs n`. -* `Algorithm.IsMarkov.condIndepFun_action_history`: in a run of a Markov algorithm, the action at +* `IsAlgEnvSeq.condIndepFun_action_history`: in a run of a Markov algorithm, the action at time `n` is conditionally independent of the history before time `n` given the observation at time `n`. @@ -91,19 +92,52 @@ lemma policyCondObs_eq_of_policy_eq [Nonempty 𝓨] (alg : Algorithm 𝓞 𝓐 rw [policy_eq_prodMkLeft_policyCondObs, Kernel.prodMkLeft_inj] at h exact h -namespace IsMarkov +section Markov + +variable {κ : ℕ → Kernel 𝓞 𝓐} [∀ n, IsMarkovKernel (κ n)] + +/-- The algorithm whose action at time `n` is drawn from `κ n` applied to the observation at +time `n`, whatever the history. -/ +def markov (κ : ℕ → Kernel 𝓞 𝓐) [∀ n, IsMarkovKernel (κ n)] : Algorithm 𝓞 𝓐 𝓨 where + policy n := (κ n).prodMkLeft (Hist 𝓞 𝓐 𝓨 n) + +@[simp] +lemma policy_markov (n : ℕ) : + (markov κ : Algorithm 𝓞 𝓐 𝓨).policy n = (κ n).prodMkLeft (Hist 𝓞 𝓐 𝓨 n) := rfl + +@[simp] +lemma policyZero_markov : (markov κ : Algorithm 𝓞 𝓐 𝓨).policyZero = κ 0 := by + ext o : 1 + rw [policyZero_apply, policy_markov, Kernel.prodMkLeft_apply] + +instance : (markov κ : Algorithm 𝓞 𝓐 𝓨).IsMarkov where + exists_policy_eq_prodMkLeft := ⟨κ, inferInstance, fun _ ↦ rfl⟩ + +@[simp] +lemma policyCondObs_markov [Nonempty 𝓨] (n : ℕ) : + (markov κ : Algorithm 𝓞 𝓐 𝓨).policyCondObs n = κ n := + policyCondObs_eq_of_policy_eq _ rfl + +end Markov + +end Algorithm + +section IsMarkov + +/-! ### Runs of a Markov algorithm -/ variable {Ω : Type*} {mΩ : MeasurableSpace Ω} - {alg : Algorithm 𝓞 𝓐 𝓨} {env : Environment 𝓞 𝓐 𝓨} {P : Measure Ω} [IsFiniteMeasure P] + {alg : Algorithm 𝓞 𝓐 𝓨} {env : Environment 𝓞 𝓐 𝓨} {P : Measure Ω} {O : ℕ → Ω → 𝓞} {A : ℕ → Ω → 𝓐} {Y : ℕ → Ω → 𝓨} {n N : ℕ} -lemma hasCondDistrib_action_history_obs [alg.IsMarkov] (h : IsAlgEnvSeq O A Y alg env P) (n : ℕ) : +lemma IsAlgEnvSeq.hasCondDistrib_action_history_obs_policyCondObs [alg.IsMarkov] + (h : IsAlgEnvSeq O A Y alg env P) (n : ℕ) : HasCondDistrib (A n) (fun ω ↦ (history O A Y n ω, O n ω)) ((alg.policyCondObs n).prodMkLeft (Hist 𝓞 𝓐 𝓨 n)) P := by rw [← alg.policy_eq_prodMkLeft_policyCondObs] exact h.hasCondDistrib_action n -lemma hasCondDistrib_action_history_obs_of_isAlgEnvSeqUntil [alg.IsMarkov] +lemma IsAlgEnvSeqUntil.hasCondDistrib_action_history_obs_policyCondObs [alg.IsMarkov] (h : IsAlgEnvSeqUntil O A Y alg env P N) (hn : n < N) : HasCondDistrib (A n) (fun ω ↦ (history O A Y n ω, O n ω)) ((alg.policyCondObs n).prodMkLeft (Hist 𝓞 𝓐 𝓨 n)) P := by @@ -112,45 +146,49 @@ lemma hasCondDistrib_action_history_obs_of_isAlgEnvSeqUntil [alg.IsMarkov] /-- The conditional distribution of the action at time `n` given the observation at time `n` is `alg.policyCondObs n`. -/ -lemma hasCondDistrib_action [alg.IsMarkov] (h : IsAlgEnvSeq O A Y alg env P) (n : ℕ) : +lemma IsAlgEnvSeq.hasCondDistrib_action_policyCondObs [SFinite P] [alg.IsMarkov] + (h : IsAlgEnvSeq O A Y alg env P) (n : ℕ) : HasCondDistrib (A n) (O n) (alg.policyCondObs n) P := - (hasCondDistrib_action_history_obs h n).comp_right + (h.hasCondDistrib_action_history_obs_policyCondObs n).comp_right /-- The conditional distribution of the action at time `n < N` given the observation at time `n` is `alg.policyCondObs n`. -/ -lemma hasCondDistrib_action_of_isAlgEnvSeqUntil [alg.IsMarkov] +lemma IsAlgEnvSeqUntil.hasCondDistrib_action_policyCondObs [SFinite P] [alg.IsMarkov] (h : IsAlgEnvSeqUntil O A Y alg env P N) (hn : n < N) : HasCondDistrib (A n) (O n) (alg.policyCondObs n) P := - (hasCondDistrib_action_history_obs_of_isAlgEnvSeqUntil h hn).comp_right + (h.hasCondDistrib_action_history_obs_policyCondObs hn).comp_right /-- The law of the action at time `n` is the law of the observation at time `n` composed with `alg.policyCondObs n`. -/ -lemma hasLaw_action_comp [alg.IsMarkov] (h : IsAlgEnvSeq O A Y alg env P) (n : ℕ) : +lemma IsAlgEnvSeq.hasLaw_action_comp_policyCondObs [SFinite P] [alg.IsMarkov] + (h : IsAlgEnvSeq O A Y alg env P) (n : ℕ) : HasLaw (A n) (alg.policyCondObs n ∘ₘ (P.map (O n))) P := - (hasCondDistrib_action h n).hasLaw_comp + (h.hasCondDistrib_action_policyCondObs n).hasLaw_comp /-- Conditionally on an event determined by the history before time `n` and the observation at time `n`, on which that observation is equal to `b`, the action at time `n` has law `alg.policyCondObs n b`. -/ -lemma hasLaw_action_cond [alg.IsMarkov] (h : IsAlgEnvSeq O A Y alg env P) (n : ℕ) +lemma IsAlgEnvSeq.hasLaw_action_cond_policyCondObs [IsFiniteMeasure P] [alg.IsMarkov] + (h : IsAlgEnvSeq O A Y alg env P) (n : ℕ) {s : Set (Hist 𝓞 𝓐 𝓨 n × 𝓞)} (hs : MeasurableSet s) {b : 𝓞} (hsb : ∀ u ∈ s, u.2 = b) (hP : P ((fun ω ↦ (history O A Y n ω, O n ω)) ⁻¹' s) ≠ 0) : HasLaw (A n) (alg.policyCondObs n b) P[|(fun ω ↦ (history O A Y n ω, O n ω)) ⁻¹' s] := by - refine (hasCondDistrib_action_history_obs h n).hasLaw_cond (h.measurable_action _) hs + refine (h.hasCondDistrib_action_history_obs_policyCondObs n).hasLaw_cond hs (fun u hu ↦ ?_) hP rw [Kernel.prodMkLeft_apply, hsb u hu] /-- Conditionally on an event determined by the history before time `n` and the observation at time `n`, on which that observation is constant, the action at time `n` is independent of the history before time `n` and of the observation at time `n`. -/ -lemma indepFun_history_obs_action_cond [alg.IsMarkov] (h : IsAlgEnvSeq O A Y alg env P) (n : ℕ) +lemma IsAlgEnvSeq.indepFun_history_obs_action_cond [IsFiniteMeasure P] [alg.IsMarkov] + (h : IsAlgEnvSeq O A Y alg env P) (n : ℕ) {s : Set (Hist 𝓞 𝓐 𝓨 n × 𝓞)} (hs : MeasurableSet s) {b : 𝓞} (hsb : ∀ u ∈ s, u.2 = b) : (fun ω ↦ (history O A Y n ω, O n ω)) ⟂ᵢ[P[|(fun ω ↦ (history O A Y n ω, O n ω)) ⁻¹' s]] A n := by have hO := h.measurable_obs have hA := h.measurable_action have hY := h.measurable_feedback - refine (hasCondDistrib_action_history_obs h n).indepFun_cond (by fun_prop) hs + refine (h.hasCondDistrib_action_history_obs_policyCondObs n).indepFun_cond (by fun_prop) hs (η := alg.policyCondObs n b) fun u hu ↦ ?_ rw [Kernel.prodMkLeft_apply, hsb u hu] @@ -159,63 +197,33 @@ variable [StandardBorelSpace 𝓞] [Nonempty 𝓞] [StandardBorelSpace 𝓐] [No /-- The action at time `n` is conditionally independent of the history before time `n`, given the observation at time `n`. -/ -lemma condIndepFun_action_history [StandardBorelSpace Ω] [alg.IsMarkov] - (h : IsAlgEnvSeq O A Y alg env P) (n : ℕ) : +lemma IsAlgEnvSeq.condIndepFun_action_history [IsFiniteMeasure P] [StandardBorelSpace Ω] + [alg.IsMarkov] (h : IsAlgEnvSeq O A Y alg env P) (n : ℕ) : A n ⟂ᵢ[O n, h.measurable_obs n; P] history O A Y n := by have hO := h.measurable_obs have hA := h.measurable_action have hY := h.measurable_feedback refine condIndepFun_of_exists_condDistrib_prod_ae_eq_prodMkLeft (η := alg.policyCondObs n) (by fun_prop) (by fun_prop) (by fun_prop) ?_ - exact HasCondDistrib.condDistrib_eq (hasCondDistrib_action_history_obs h n) + exact HasCondDistrib.condDistrib_ae_eq (h.hasCondDistrib_action_history_obs_policyCondObs n) /-- The action at time `n` is conditionally independent of the history before time `n` and the observation at time `n`, given the observation at time `n`. -/ -lemma condIndepFun_action_history_obs [StandardBorelSpace Ω] [alg.IsMarkov] - (h : IsAlgEnvSeq O A Y alg env P) (n : ℕ) : +lemma IsAlgEnvSeq.condIndepFun_action_history_obs [IsFiniteMeasure P] [StandardBorelSpace Ω] + [alg.IsMarkov] (h : IsAlgEnvSeq O A Y alg env P) (n : ℕ) : A n ⟂ᵢ[O n, h.measurable_obs n; P] (fun ω ↦ (history O A Y n ω, O n ω)) := by have hO := h.measurable_obs have hA := h.measurable_action have hY := h.measurable_feedback - exact (condIndepFun_action_history h n).prod_right (by fun_prop) (by fun_prop) (by fun_prop) + exact (h.condIndepFun_action_history n).prod_right (by fun_prop) (by fun_prop) (by fun_prop) end IsMarkov -section Markov - -variable {κ : ℕ → Kernel 𝓞 𝓐} [∀ n, IsMarkovKernel (κ n)] - -/-- The algorithm whose action at time `n` is drawn from `κ n` applied to the observation at -time `n`, whatever the history. -/ -def markov (κ : ℕ → Kernel 𝓞 𝓐) [∀ n, IsMarkovKernel (κ n)] : Algorithm 𝓞 𝓐 𝓨 where - policy n := (κ n).prodMkLeft (Hist 𝓞 𝓐 𝓨 n) - -@[simp] -lemma policy_markov (n : ℕ) : - (markov κ : Algorithm 𝓞 𝓐 𝓨).policy n = (κ n).prodMkLeft (Hist 𝓞 𝓐 𝓨 n) := rfl - -@[simp] -lemma policyZero_markov : (markov κ : Algorithm 𝓞 𝓐 𝓨).policyZero = κ 0 := by - ext o : 1 - rw [policyZero_apply, policy_markov, Kernel.prodMkLeft_apply] - -instance : (markov κ : Algorithm 𝓞 𝓐 𝓨).IsMarkov where - exists_policy_eq_prodMkLeft := ⟨κ, inferInstance, fun _ ↦ rfl⟩ - -@[simp] -lemma policyCondObs_markov [Nonempty 𝓨] (n : ℕ) : - (markov κ : Algorithm 𝓞 𝓐 𝓨).policyCondObs n = κ n := - policyCondObs_eq_of_policy_eq _ rfl - -end Markov - -end Algorithm - namespace IsAlgEnvSeq variable {Ω : Type*} {mΩ : MeasurableSpace Ω} {κ : ℕ → Kernel 𝓞 𝓐} [∀ n, IsMarkovKernel (κ n)] {env : Environment 𝓞 𝓐 𝓨} - {P : Measure Ω} [IsFiniteMeasure P] + {P : Measure Ω} {O : ℕ → Ω → 𝓞} {A : ℕ → Ω → 𝓐} {Y : ℕ → Ω → 𝓨} lemma hasCondDistrib_action_history_obs_markov @@ -225,45 +233,47 @@ lemma hasCondDistrib_action_history_obs_markov /-- The conditional distribution of the action at time `n` given the observation at time `n` is `κ n`. -/ -lemma hasCondDistrib_action_markov (h : IsAlgEnvSeq O A Y (Algorithm.markov κ) env P) (n : ℕ) : +lemma hasCondDistrib_action_markov [SFinite P] (h : IsAlgEnvSeq O A Y (Algorithm.markov κ) env P) + (n : ℕ) : HasCondDistrib (A n) (O n) (κ n) P := (hasCondDistrib_action_history_obs_markov h n).comp_right /-- The conditional distribution of the action at time `n` given the observation at time `n` is `κ n`. -/ -lemma condDistrib_action_markov [StandardBorelSpace 𝓐] [Nonempty 𝓐] +lemma condDistrib_action_markov [IsFiniteMeasure P] [StandardBorelSpace 𝓐] [Nonempty 𝓐] (h : IsAlgEnvSeq O A Y (Algorithm.markov κ) env P) (n : ℕ) : condDistrib (A n) (O n) P =ᵐ[P.map (O n)] κ n := - (hasCondDistrib_action_markov h n).condDistrib_eq + (hasCondDistrib_action_markov h n).condDistrib_ae_eq /-- Conditionally on an event determined by the history before time `n` and the observation at time `n`, on which that observation is equal to `b`, the action at time `n` has law `κ n b`. -/ -lemma hasLaw_action_cond_markov (h : IsAlgEnvSeq O A Y (Algorithm.markov κ) env P) (n : ℕ) +lemma hasLaw_action_cond_markov [IsFiniteMeasure P] + (h : IsAlgEnvSeq O A Y (Algorithm.markov κ) env P) (n : ℕ) {s : Set (Hist 𝓞 𝓐 𝓨 n × 𝓞)} (hs : MeasurableSet s) {b : 𝓞} (hsb : ∀ u ∈ s, u.2 = b) (hP : P ((fun ω ↦ (history O A Y n ω, O n ω)) ⁻¹' s) ≠ 0) : HasLaw (A n) (κ n b) P[|(fun ω ↦ (history O A Y n ω, O n ω)) ⁻¹' s] := by - refine (hasCondDistrib_action_history_obs_markov h n).hasLaw_cond (h.measurable_action _) hs + refine (hasCondDistrib_action_history_obs_markov h n).hasLaw_cond hs (fun u hu ↦ ?_) hP rw [Kernel.prodMkLeft_apply, hsb u hu] /-- Conditionally on an event determined by the history before time `n` and the observation at time `n`, on which that observation is constant, the action at time `n` is independent of the history before time `n` and of the observation at time `n`. -/ -lemma indepFun_history_obs_action_cond_markov +lemma indepFun_history_obs_action_cond_markov [IsFiniteMeasure P] (h : IsAlgEnvSeq O A Y (Algorithm.markov κ) env P) (n : ℕ) {s : Set (Hist 𝓞 𝓐 𝓨 n × 𝓞)} (hs : MeasurableSet s) {b : 𝓞} (hsb : ∀ u ∈ s, u.2 = b) : (fun ω ↦ (history O A Y n ω, O n ω)) ⟂ᵢ[P[|(fun ω ↦ (history O A Y n ω, O n ω)) ⁻¹' s]] A n := - Algorithm.IsMarkov.indepFun_history_obs_action_cond h n hs hsb + h.indepFun_history_obs_action_cond n hs hsb /-- The action at time `n` is conditionally independent of the history before time `n`, given the observation at time `n`. -/ -lemma condIndepFun_action_history_markov [StandardBorelSpace Ω] +lemma condIndepFun_action_history_markov [IsFiniteMeasure P] [StandardBorelSpace Ω] [StandardBorelSpace 𝓞] [Nonempty 𝓞] [StandardBorelSpace 𝓐] [Nonempty 𝓐] [StandardBorelSpace 𝓨] [Nonempty 𝓨] (h : IsAlgEnvSeq O A Y (Algorithm.markov κ) env P) (n : ℕ) : A n ⟂ᵢ[O n, h.measurable_obs n; P] history O A Y n := - Algorithm.IsMarkov.condIndepFun_action_history h n + h.condIndepFun_action_history n end IsAlgEnvSeq diff --git a/LeanMachineLearning/SequentialLearning/Algorithms/RandomSampling/Basic.lean b/LeanMachineLearning/SequentialLearning/Algorithms/RandomSampling/Basic.lean index 26b287bf..8fc8c177 100644 --- a/LeanMachineLearning/SequentialLearning/Algorithms/RandomSampling/Basic.lean +++ b/LeanMachineLearning/SequentialLearning/Algorithms/RandomSampling/Basic.lean @@ -7,7 +7,7 @@ module public import LeanMachineLearning.SequentialLearning.Algorithms.Markov -import LeanMachineLearning.ForMathlib.Probability.Independence.IndepFun +import LeanMachineLearning.ForMathlib.Probability.Independence.Basic /-! # Random Sampling @@ -17,13 +17,13 @@ measure at each iteration. ## Main definitions -* `Algorithm.const`: The random sampling algorithm that samples from a fixed distribution at -each iteration. +* `Algorithm.const μ`: the random sampling algorithm, that samples from the fixed distribution `μ` + at each iteration. ## Main statements -* `hasLaw_action`: Each action follows the distribution μ. -* `iIndep_action`: Actions are mutually independent across time steps. +* `IsAlgEnvSeq.hasLaw_action_const`: each action has law `μ`. +* `IsAlgEnvSeq.iIndepFun_action_const`: the actions are mutually independent. -/ @[expose] public section @@ -39,7 +39,6 @@ variable {𝓞 𝓐 𝓨 Ω : Type*} {m𝓞 : MeasurableSpace 𝓞} {m𝓐 : Mea {mΩ : MeasurableSpace Ω} {μ : Measure 𝓐} [IsProbabilityMeasure μ] {P : Measure Ω} [IsProbabilityMeasure P] -open Set in /-- The _Random Sampling_ algorithm, which samples from a fixed probability measure at each iteration. -/ @[simps] @@ -56,21 +55,21 @@ instance : (Algorithm.const μ : Algorithm 𝓞 𝓐 𝓨).IsMarkov := inferInstanceAs (Algorithm.markov (fun _ ↦ Kernel.const 𝓞 μ) : Algorithm 𝓞 𝓐 𝓨).IsMarkov @[simp] -lemma policyCondObs_const [Nonempty 𝓨] (n : ℕ) : +lemma Algorithm.policyCondObs_const [Nonempty 𝓨] (n : ℕ) : (Algorithm.const μ : Algorithm 𝓞 𝓐 𝓨).policyCondObs n = Kernel.const 𝓞 μ := Algorithm.policyCondObs_eq_of_policy_eq _ rfl -namespace Algorithm.const +namespace IsAlgEnvSeq variable {O : ℕ → Ω → 𝓞} {A : ℕ → Ω → 𝓐} {Y : ℕ → Ω → 𝓨} {env : Environment 𝓞 𝓐 𝓨} /-- Each action of the random sampling algorithm follows the distribution μ. -/ -lemma hasLaw_action (h : IsAlgEnvSeq O A Y (Algorithm.const μ) env P) (n : ℕ) : +lemma hasLaw_action_const (h : IsAlgEnvSeq O A Y (Algorithm.const μ) env P) (n : ℕ) : HasLaw (A n) μ P := (h.hasCondDistrib_action n).hasLaw_of_const /-- Actions of the random sampling algorithm are mutually independent. -/ -lemma iIndep_action (h : IsAlgEnvSeq O A Y (Algorithm.const μ) env P) : +lemma iIndepFun_action_const (h : IsAlgEnvSeq O A Y (Algorithm.const μ) env P) : iIndepFun A P := by have hO := h.measurable_obs have hA := h.measurable_action @@ -78,15 +77,16 @@ lemma iIndep_action (h : IsAlgEnvSeq O A Y (Algorithm.const μ) env P) : intro n have map_eq := (h.hasCondDistrib_action (n + 1)).map_eq simp only [Algorithm.const_policy, Measure.compProd_const] at map_eq - have law_eq : P.map (A (n + 1)) = μ := (hasLaw_action h (n + 1)).map_eq + have law_eq : P.map (A (n + 1)) = μ := (h.hasLaw_action_const (n + 1)).map_eq rw [← law_eq, ← indepFun_iff_map_prod_eq_prod_map_map] at map_eq - · change A (n + 1) ⟂ᵢ[P] (fun (p : Hist 𝓞 𝓐 𝓨 (n + 1) × 𝓞) (i : Iic n) ↦ + · -- the actions before time `n + 1` are a function of the history at time `n + 1` + change A (n + 1) ⟂ᵢ[P] (fun (p : Hist 𝓞 𝓐 𝓨 (n + 1) × 𝓞) (i : Iic n) ↦ (p.1 ⟨i.1, Nat.lt_succ_of_le (mem_Iic.mp i.2)⟩).action) ∘ (fun ω ↦ (history O A Y (n + 1) ω, O (n + 1) ω)) refine map_eq.symm.comp measurable_id (by fun_prop) · exact ((h.measurable_history (n + 1)).prodMk (h.measurable_obs (n + 1))).aemeasurable · exact (h.measurable_action (n + 1)).aemeasurable -end Algorithm.const +end IsAlgEnvSeq end Learning diff --git a/LeanMachineLearning/SequentialLearning/Algorithms/RandomSampling/Tendsto.lean b/LeanMachineLearning/SequentialLearning/Algorithms/RandomSampling/Tendsto.lean index b82d306c..c0408d5c 100644 --- a/LeanMachineLearning/SequentialLearning/Algorithms/RandomSampling/Tendsto.lean +++ b/LeanMachineLearning/SequentialLearning/Algorithms/RandomSampling/Tendsto.lean @@ -6,30 +6,34 @@ Authors: Gaëtan Serré module public import LeanMachineLearning.ForMathlib.MeasureTheory.Order.MeasurableArg -public import LeanMachineLearning.ForMathlib.Order.Interval.Finset +public import LeanMachineLearning.ForMathlib.Order.Interval.Finset.Basic public import LeanMachineLearning.SequentialLearning.Algorithms.RandomSampling.Basic public import LeanMachineLearning.SequentialLearning.EvaluationEnv import Mathlib.Topology.Separation.CompletelyRegular -import LeanMachineLearning.ForMathlib.Topology.Instances.ENNReal.Lemmas - /-! # Random Sampling convergence lemmas -This file contains several convergence lemmas for the `Algorithm.const` algorithm along with an +This file contains several convergence lemmas for the `Algorithm.const` algorithm. The lemmas about +the actions hold in any environment. The lemmas about the feedbacks are stated for an `Environment.eval` environment, that evaluates the actions using a measurable function. +All the statements are in the namespace `Learning.IsAlgEnvSeq`, so that they can be used with +dot notation on the run. + ## Main statements -* `hasLaw_feeback`: Each feedback follows the distribution μ.map f. -* `iIndep_feedback`: Feedbacks are mutually independent across time steps. -* `action_tendsto_any`: The minimum distance from sampled actions to any point in α tends to zero - in measure. -* `feedback_tendsto_any`: The minimum distance from rewards to any value of `f` tends to zero in - measure. -* `tendsto_min`: The minimum reward converges in measure to the global minimum value. -* `tendsto_max`: The maximum reward converges in measure to the global maximum value. +* `IsAlgEnvSeq.hasLaw_feedback_const_eval`: each feedback has law `μ.map f`. +* `IsAlgEnvSeq.iIndepFun_feedback_const_eval`: the feedbacks are mutually independent. +* `IsAlgEnvSeq.action_tendsto_any_const`: the minimum distance from the sampled actions to any + point tends to zero in measure. +* `IsAlgEnvSeq.feedback_tendsto_any_const_eval`: the minimum distance from the feedbacks to any + value of `f` tends to zero in measure. +* `IsAlgEnvSeq.tendsto_min_feedback_const_eval`: the minimum feedback converges in measure to the + global minimum value of `f`. +* `IsAlgEnvSeq.tendsto_max_feedback_const_eval`: the maximum feedback converges in measure to the + global maximum value of `f`. -/ @[expose] public section @@ -38,50 +42,53 @@ open Learning MeasureTheory ProbabilityTheory Filter Finset ENNReal open scoped Topology -namespace Learning.Algorithm.const +namespace Learning.IsAlgEnvSeq -variable {𝓐 𝓨 Ω : Type*} {m𝓐 : MeasurableSpace 𝓐} {m𝓨 : MeasurableSpace 𝓨} - {mΩ : MeasurableSpace Ω} {μ : Measure 𝓐} [IsProbabilityMeasure μ] {P : Measure Ω} - [IsProbabilityMeasure P] {O : ℕ → Ω → Unit} {A : ℕ → Ω → 𝓐} {Y : ℕ → Ω → 𝓨} - {env : Environment Unit 𝓐 𝓨} - {f : 𝓐 → 𝓨} {hf : Measurable f} +variable {𝓞 𝓐 𝓨 Ω : Type*} {m𝓞 : MeasurableSpace 𝓞} {m𝓐 : MeasurableSpace 𝓐} + {m𝓨 : MeasurableSpace 𝓨} {mΩ : MeasurableSpace Ω} {μ : Measure 𝓐} [IsProbabilityMeasure μ] + {P : Measure Ω} [IsProbabilityMeasure P] {A : ℕ → Ω → 𝓐} {Y : ℕ → Ω → 𝓨} section rewards -variable [StandardBorelSpace 𝓨] [Nonempty 𝓨] +variable {O : ℕ → Ω → Unit} {f : 𝓐 → 𝓨} {hf : Measurable f} [MeasurableEq 𝓨] /-- Each reward follows the distribution μ.map f. -/ -lemma hasLaw_feeback (h : IsAlgEnvSeq O A Y (Algorithm.const μ) (Environment.eval f hf) P) (n : ℕ) : +lemma hasLaw_feedback_const_eval + (h : IsAlgEnvSeq O A Y (Algorithm.const μ) (Environment.eval f hf) P) (n : ℕ) : HasLaw (Y n) (μ.map f) P := by - refine HasLaw.congr ?_ (feedback_eval_ae_eq_eval_action h n) + refine HasLaw.congr ?_ (feedback_ae_eq_eval h n) have hA := h.measurable_action n refine ⟨by fun_prop, ?_⟩ - rw [← Measure.map_map hf hA, (hasLaw_action h n).map_eq] + rw [← Measure.map_map hf hA, (hasLaw_action_const h n).map_eq] /-- Rewards are mutually independent. -/ -lemma iIndep_feedback (h : IsAlgEnvSeq O A Y (Algorithm.const μ) (Environment.eval f hf) P) : +lemma iIndepFun_feedback_const_eval + (h : IsAlgEnvSeq O A Y (Algorithm.const μ) (Environment.eval f hf) P) : iIndepFun Y P := have (n : ℕ) : f ∘ A n =ᵐ[P] Y n := - (feedback_eval_ae_eq_eval_action h n).symm - iIndepFun.congr this <| (iIndep_action h).comp _ (fun _ ↦ hf) + (feedback_ae_eq_eval h n).symm + iIndepFun.congr this <| (iIndepFun_action_const h).comp _ (fun _ ↦ hf) end rewards -variable [PseudoMetricSpace 𝓐] [SecondCountableTopology 𝓐] [OpensMeasurableSpace 𝓐] - [μ.IsOpenPosMeasure] +section actions + +/-! ### Convergence of the actions, in any environment -/ + +variable {O : ℕ → Ω → 𝓞} {env : Environment 𝓞 𝓐 𝓨} + [PseudoMetricSpace 𝓐] [OpensMeasurableSpace 𝓐] [μ.IsOpenPosMeasure] /-- The minimum distance from sampled actions to any point tends to zero. -/ -theorem action_tendsto_any (h : IsAlgEnvSeq O A Y (Algorithm.const μ) (Environment.eval f hf) P) +lemma action_tendsto_any_const (h : IsAlgEnvSeq O A Y (Algorithm.const μ) env P) (a : 𝓐) {ε : ℝ} (hε : 0 < ε) : Tendsto (fun i => P {x | ε ≤ (fun (j : Iic i) ↦ dist (A j.1 x) a).min}) atTop (𝓝 0) := by - set const_alg := Algorithm.const (𝓞 := Unit) (𝓨 := 𝓨) μ - refine tendsto_zero_of_le (g := fun n ↦ P (⋂ i ∈ Iic n, {x | ε ≤ dist (A i x) a})) ?_ ?_ + refine tendsto_nhds_bot_mono' (f := fun n ↦ P (⋂ i ∈ Iic n, {x | ε ≤ dist (A i x) a})) ?_ ?_ · have inter_prod (n : ℕ) : P (⋂ j ∈ Iic n, {x | ε ≤ dist (A j x) a}) = ∏ j ∈ Iic n, P {x | ε ≤ dist (A j x) a} := by refine iIndepSet.meas_biInter ?_ _ rw [iIndepSet_iff_meas_biInter fun i ↦ ?_] · intro s - have iIndep_actions := Algorithm.const.iIndep_action h + have iIndep_actions := iIndepFun_action_const h rw [iIndepFun_iff_measure_inter_preimage_eq_mul] at iIndep_actions have meas_dist : ∀ i ∈ s, MeasurableSet {x | ε ≤ dist x a} := by intro i hs @@ -94,7 +101,7 @@ theorem action_tendsto_any (h : IsAlgEnvSeq O A Y (Algorithm.const μ) (Environm have prod_law (n : ℕ) : ∏ j ∈ Iic n, P {x | ε ≤ dist (A j x) a} = ∏ j ∈ Iic n, μ {x | ε ≤ dist x a} := by refine prod_congr rfl fun j hj ↦ ?_ - have hlaw (n : ℕ) : HasLaw (A n) μ P := Algorithm.const.hasLaw_action h n + have hlaw (n : ℕ) : HasLaw (A n) μ P := hasLaw_action_const h n rw [← (hlaw j).map_eq, P.map_apply] · simp · exact h.measurable_action j @@ -114,18 +121,16 @@ theorem action_tendsto_any (h : IsAlgEnvSeq O A Y (Algorithm.const μ) (Environm intro i hi ω (hω : ε ≤ (fun (j : Iic n) ↦ dist (A j.1 ω) a).min) simp_all only [univ_eq_attach, le_inf'_iff, mem_attach, forall_const, Subtype.forall, mem_Iic] -variable [PseudoMetricSpace 𝓨] [BorelSpace 𝓨] (hfc : Continuous f) - /-- The minimum distance from image of actions to any function value tends to zero. -/ -lemma image_action_tendsto_any - (h : IsAlgEnvSeq O A Y (Algorithm.const μ) (Environment.eval f hfc.measurable) P) +lemma image_action_tendsto_any_const {𝓩 : Type*} [PseudoMetricSpace 𝓩] {f : 𝓐 → 𝓩} + (hfc : Continuous f) + (h : IsAlgEnvSeq O A Y (Algorithm.const μ) env P) (a : 𝓐) {ε : ℝ} (hε : 0 < ε) : Tendsto (fun i => P {x | ε ≤ (fun (j : Iic i) ↦ dist (f (A j.1 x)) (f a)).min}) atTop (𝓝 0) := by - have hf := hfc.measurable rw [Metric.continuous_iff] at hfc obtain ⟨δ, hδ, hfc⟩ := hfc a ε hε - refine action_tendsto_any h a hδ |> tendsto_zero_of_le <| ?_ + refine action_tendsto_any_const h a hδ |> tendsto_nhds_bot_mono' <| ?_ intro n refine measure_mono ?_ simp only [Set.ofPred_subset_ofPred] @@ -137,29 +142,16 @@ lemma image_action_tendsto_any have := (fun (j : Iic n) ↦ dist (f (A (j) ω)) (f a)).min_le j linarith -variable [StandardBorelSpace 𝓨] [Nonempty 𝓨] - -/-- The minimum distance from rewards to any function value tends to zero. -/ -lemma feedback_tendsto_any - (h : IsAlgEnvSeq O A Y (Algorithm.const μ) (Environment.eval f hfc.measurable) P) - (a : 𝓐) {ε : ℝ} (hε : 0 < ε) : - Tendsto (fun i => P {x | ε ≤ (fun (j : Iic i) ↦ dist (Y j.1 x) (f a)).min}) atTop (𝓝 0) := by - convert image_action_tendsto_any hfc h a hε using 2 with n - refine measure_congr ?_ - let g : ((Iic n) → 𝓨) → ℝ := fun r ↦ (fun i ↦ dist (r i) (f a)).min - filter_upwards [feedback_eval_ae_eq_eval_action_comp h g] with ω hω - simp only [eq_iff_iff] - simp [g, hω] - -variable {R : ℕ → Ω → ℝ} {f : 𝓐 → ℝ} (hfc : Continuous f) {a : 𝓐} +variable {f : 𝓐 → ℝ} {a : 𝓐} /-- The minimum image action converges to the function's global minimum. -/ -lemma tendsto_min₀ (h : IsAlgEnvSeq O A R (Algorithm.const μ) (Environment.eval f hfc.measurable) P) +lemma tendsto_min_action_const (hfc : Continuous f) + (h : IsAlgEnvSeq O A Y (Algorithm.const μ) env P) (hf_min : ∀ x, f a ≤ f x) : TendstoInMeasure P (fun n ω ↦ (fun (i : Iic n) ↦ f (A i.1 ω)).min) atTop (fun _ ↦ f a) := by rw [tendstoInMeasure_iff_dist] intro ε hε - refine image_action_tendsto_any hfc h a hε |> tendsto_zero_of_le <| ?_ + refine image_action_tendsto_any_const hfc h a hε |> tendsto_nhds_bot_mono' <| ?_ intro n refine measure_mono ?_ simp only [Set.ofPred_subset_ofPred] @@ -170,25 +162,19 @@ lemma tendsto_min₀ (h : IsAlgEnvSeq O A R (Algorithm.const μ) (Environment.ev rw [← argmin_spec] set k := argmin (fun (i : Iic n) ↦ f (A i ω)) have := hf_min (A k ω) - have : f (A k ω) ≤ f (A j ω) := isMinOn_argmin (fun (i : Iic n) ↦ f (A i ω)) j + have : f (A k ω) ≤ f (A j ω) := + isMinOn_univ_iff.1 (isMinOn_argmin (fun (i : Iic n) ↦ f (A i ω))) j simp [Real.dist_eq] grind -/-- The minimum reward converges to the function's global minimum. -/ -lemma tendsto_min (h : IsAlgEnvSeq O A R (Algorithm.const μ) (Environment.eval f hfc.measurable) P) - (hf_min : ∀ x, f a ≤ f x) : - TendstoInMeasure P (fun n ω ↦ (fun (i : Iic n) ↦ R i.1 ω).min) atTop (fun _ ↦ f a) := by - refine TendstoInMeasure.congr_left (fun n ↦ ?_) <| tendsto_min₀ hfc h hf_min - filter_upwards [feedback_eval_ae_eq_eval_action_comp h Function.min] with ω hω - rw [← hω] - /-- The maximum image action converges to the function's global maximum. -/ -lemma tendsto_max₀ (h : IsAlgEnvSeq O A R (Algorithm.const μ) (Environment.eval f hfc.measurable) P) +lemma tendsto_max_action_const (hfc : Continuous f) + (h : IsAlgEnvSeq O A Y (Algorithm.const μ) env P) (hf_max : ∀ x, f x ≤ f a) : TendstoInMeasure P (fun n ω ↦ (fun (i : Iic n) ↦ f (A i.1 ω)).max) atTop (fun _ ↦ f a) := by rw [tendstoInMeasure_iff_dist] intro ε hε - refine image_action_tendsto_any hfc h a hε |> tendsto_zero_of_le <| ?_ + refine image_action_tendsto_any_const hfc h a hε |> tendsto_nhds_bot_mono' <| ?_ intro n refine measure_mono ?_ simp only [Set.ofPred_subset_ofPred] @@ -200,16 +186,52 @@ lemma tendsto_max₀ (h : IsAlgEnvSeq O A R (Algorithm.const μ) (Environment.ev set k := argmax (fun (i : Iic n) ↦ f (A i ω)) have := hf_max (A k ω) have : f (A j ω) ≤ f (A k ω) := - isMaxOn_argmax (fun (i : Iic n) ↦ f (A i ω)) j + isMaxOn_univ_iff.1 (isMaxOn_argmax (fun (i : Iic n) ↦ f (A i ω))) j simp [Real.dist_eq] grind +end actions + +section feedbacks + +/-! ### Convergence of the feedbacks, in an evaluation environment -/ + +variable {O : ℕ → Ω → Unit} + [PseudoMetricSpace 𝓐] [OpensMeasurableSpace 𝓐] [μ.IsOpenPosMeasure] + +/-- The minimum distance from rewards to any function value tends to zero. -/ +lemma feedback_tendsto_any_const_eval [PseudoMetricSpace 𝓨] [BorelSpace 𝓨] [MeasurableEq 𝓨] + {f : 𝓐 → 𝓨} (hfc : Continuous f) + (h : IsAlgEnvSeq O A Y (Algorithm.const μ) (Environment.eval f hfc.measurable) P) + (a : 𝓐) {ε : ℝ} (hε : 0 < ε) : + Tendsto (fun i => P {x | ε ≤ (fun (j : Iic i) ↦ dist (Y j.1 x) (f a)).min}) atTop (𝓝 0) := by + convert image_action_tendsto_any_const hfc h a hε using 2 with n + refine measure_congr ?_ + let g : ((Iic n) → 𝓨) → ℝ := fun r ↦ (fun i ↦ dist (r i) (f a)).min + filter_upwards [comp_feedback_ae_eq_eval h g] with ω hω + simp only [eq_iff_iff] + simp [g, hω] + +variable {R : ℕ → Ω → ℝ} {f : 𝓐 → ℝ} (hfc : Continuous f) {a : 𝓐} + +/-- The minimum reward converges to the function's global minimum. -/ +lemma tendsto_min_feedback_const_eval + (h : IsAlgEnvSeq O A R (Algorithm.const μ) (Environment.eval f hfc.measurable) P) + (hf_min : ∀ x, f a ≤ f x) : + TendstoInMeasure P (fun n ω ↦ (fun (i : Iic n) ↦ R i.1 ω).min) atTop (fun _ ↦ f a) := by + refine TendstoInMeasure.congr_left (fun n ↦ ?_) <| tendsto_min_action_const hfc h hf_min + filter_upwards [comp_feedback_ae_eq_eval h Function.min] with ω hω + rw [← hω] + /-- The maximum reward converges to the function's global maximum. -/ -lemma tendsto_max (h : IsAlgEnvSeq O A R (Algorithm.const μ) (Environment.eval f hfc.measurable) P) +lemma tendsto_max_feedback_const_eval + (h : IsAlgEnvSeq O A R (Algorithm.const μ) (Environment.eval f hfc.measurable) P) (hf_max : ∀ x, f x ≤ f a) : TendstoInMeasure P (fun n ω ↦ (fun (i : Iic n) ↦ R i.1 ω).max) atTop (fun _ ↦ f a) := by - refine TendstoInMeasure.congr_left (fun n ↦ ?_) <| tendsto_max₀ hfc h hf_max - filter_upwards [feedback_eval_ae_eq_eval_action_comp h Function.max] with ω hω + refine TendstoInMeasure.congr_left (fun n ↦ ?_) <| tendsto_max_action_const hfc h hf_max + filter_upwards [comp_feedback_ae_eq_eval h Function.max] with ω hω rw [← hω] -end Learning.Algorithm.const +end feedbacks + +end Learning.IsAlgEnvSeq diff --git a/LeanMachineLearning/SequentialLearning/Algorithms/RoundRobin.lean b/LeanMachineLearning/SequentialLearning/Algorithms/RoundRobin.lean index f73d6dde..4b9ccb6b 100644 --- a/LeanMachineLearning/SequentialLearning/Algorithms/RoundRobin.lean +++ b/LeanMachineLearning/SequentialLearning/Algorithms/RoundRobin.lean @@ -13,11 +13,16 @@ public import LeanMachineLearning.SequentialLearning.StationaryEnv That algorithm chooses each of finitely many actions in a round-robin fashion. That is, if there are `K` actions numbered from 0 to `K - 1`, then at time `n` it chooses -he action `n % K`. +the action `n % K`. ## Main definitions -* `roundRobinAlgorithm K`: the Round-Robin algorithm on `K` actions. +* `Algorithm.roundRobin K`: the Round-Robin algorithm on `K` actions. + +## Main statements + +* `RoundRobin.pullCount_mul`: in any environment, at time `K * m`, each action has been chosen + `m` times. -/ @@ -28,7 +33,7 @@ open scoped ENNReal NNReal section Aux -lemma sum_mod_range {K : ℕ} (hK : 0 < K) (a : Fin K) : +private lemma sum_mod_range {K : ℕ} (hK : 0 < K) (a : Fin K) : (∑ s ∈ range K, if ⟨s % K, Nat.mod_lt _ hK⟩ = a then 1 else 0) = 1 := by have h_iff (s : ℕ) (hs : s < K) : ⟨s % K, Nat.mod_lt _ hK⟩ = a ↔ s = a := by simp only [Nat.mod_eq_of_lt hs, Fin.ext_iff] @@ -38,7 +43,7 @@ lemma sum_mod_range {K : ℕ} (hK : 0 < K) (a : Fin K) : rw [sum_ite_eq'] simp -lemma sum_mod_range_mul {K : ℕ} (hK : 0 < K) (m : ℕ) (a : Fin K) : +private lemma sum_mod_range_mul {K : ℕ} (hK : 0 < K) (m : ℕ) (a : Fin K) : (∑ s ∈ range (K * m), if ⟨s % K, Nat.mod_lt _ hK⟩ = a then 1 else 0) = m := by induction m with | zero => simp @@ -83,26 +88,26 @@ def RoundRobin.nextAction [NeZero K] (n : ℕ) : Fin K := variable (K) in /-- The Round-Robin algorithm: deterministic algorithm that chooses action `n % K` at time `n`. -/ noncomputable -def roundRobinAlgorithm [NeZero K] : Algorithm 𝓞 (Fin K) 𝓨 := +def Algorithm.roundRobin [NeZero K] : Algorithm 𝓞 (Fin K) 𝓨 := Algorithm.deterministic (fun n _ ↦ RoundRobin.nextAction K n) (by fun_prop) end AlgorithmDefinition namespace RoundRobin -variable [NeZero K] {ν : Kernel (Fin K) 𝓨} [IsMarkovKernel ν] +variable [NeZero K] {env : Environment 𝓞 (Fin K) 𝓨} {Ω : Type*} {mΩ : MeasurableSpace Ω} - {P : Measure Ω} [IsProbabilityMeasure P] - {O : ℕ → Ω → Unit} {A : ℕ → Ω → Fin K} {Y : ℕ → Ω → 𝓨} + {P : Measure Ω} [SFinite P] + {O : ℕ → Ω → 𝓞} {A : ℕ → Ω → Fin K} {Y : ℕ → Ω → 𝓨} /-- The action chosen at time `n` is the action `n % K`. -/ lemma action_ae_eq (n : ℕ) - (h : IsAlgEnvSeqUntil O A Y (roundRobinAlgorithm K) (Environment.bandit ν) P (n + 1)) : + (h : IsAlgEnvSeqUntil O A Y (Algorithm.roundRobin K) env P (n + 1)) : A n =ᵐ[P] fun _ ↦ nextAction K n := - h.action_deterministic_ae_eq n.lt_succ_self + h.action_ae_eq_deterministic n.lt_succ_self lemma action_zero - (h : IsAlgEnvSeqUntil O A Y (roundRobinAlgorithm K) (Environment.bandit ν) P 1) : + (h : IsAlgEnvSeqUntil O A Y (Algorithm.roundRobin K) env P 1) : A 0 =ᵐ[P] fun _ ↦ 0 := by filter_upwards [action_ae_eq 0 h] with ω hω rw [hω] @@ -110,7 +115,7 @@ lemma action_zero /-- At time `K * m`, the number of times each action is chosen is equal to `m`. -/ lemma pullCount_mul (m : ℕ) - (h : IsAlgEnvSeqUntil O A Y (roundRobinAlgorithm K) (Environment.bandit ν) P (K * m)) + (h : IsAlgEnvSeqUntil O A Y (Algorithm.roundRobin K) env P (K * m)) (a : Fin K) : pullCount A a (K * m) =ᵐ[P] fun _ ↦ m := by rw [Filter.EventuallyEq] @@ -126,14 +131,14 @@ lemma pullCount_mul (m : ℕ) _ = m := sum_mod_range_mul (Nat.pos_of_neZero K) m a lemma pullCount_eq_one - (h : IsAlgEnvSeqUntil O A Y (roundRobinAlgorithm K) (Environment.bandit ν) P K) (a : Fin K) : + (h : IsAlgEnvSeqUntil O A Y (Algorithm.roundRobin K) env P K) (a : Fin K) : pullCount A a K =ᵐ[P] fun _ ↦ 1 := by suffices pullCount A a (K * 1) =ᵐ[P] fun _ ↦ 1 by simpa using this - refine pullCount_mul 1 (P := P) (ν := ν) (O := O) (Y := Y) ?_ a + refine pullCount_mul 1 (P := P) (env := env) (O := O) (Y := Y) ?_ a simpa lemma time_gt_of_pullCount_gt_one - (h : IsAlgEnvSeqUntil O A Y (roundRobinAlgorithm K) (Environment.bandit ν) P K) (a : Fin K) : + (h : IsAlgEnvSeqUntil O A Y (Algorithm.roundRobin K) env P K) (a : Fin K) : ∀ᵐ ω ∂P, ∀ n, 1 < pullCount A a n ω → K < n := by filter_upwards [pullCount_eq_one h a] with h h_eq n hn rw [← h_eq] at hn @@ -141,7 +146,7 @@ lemma time_gt_of_pullCount_gt_one exact hn.not_ge (pullCount_mono _ h_lt _) lemma pullCount_pos_of_time_ge - (h : IsAlgEnvSeqUntil O A Y (roundRobinAlgorithm K) (Environment.bandit ν) P K) : + (h : IsAlgEnvSeqUntil O A Y (Algorithm.roundRobin K) env P K) : ∀ᵐ ω ∂P, ∀ n, K ≤ n → ∀ b : Fin K, 0 < pullCount A b n ω := by have h_ae a := pullCount_eq_one h a simp_rw [Filter.EventuallyEq, ← ae_all_iff] at h_ae @@ -151,7 +156,7 @@ lemma pullCount_pos_of_time_ge exact pullCount_mono _ hn _ lemma pullCount_pos_of_pullCount_gt_one - (h : IsAlgEnvSeqUntil O A Y (roundRobinAlgorithm K) (Environment.bandit ν) P K) (a : Fin K) : + (h : IsAlgEnvSeqUntil O A Y (Algorithm.roundRobin K) env P K) (a : Fin K) : ∀ᵐ ω ∂P, ∀ n, 1 < pullCount A a n ω → ∀ b : Fin K, 0 < pullCount A b n ω := by filter_upwards [time_gt_of_pullCount_gt_one h a, pullCount_pos_of_time_ge h] with ω h1 h2 n h_gt a exact h2 n (h1 n h_gt).le a diff --git a/LeanMachineLearning/SequentialLearning/Algorithms/Uniform.lean b/LeanMachineLearning/SequentialLearning/Algorithms/Uniform.lean index b636cf58..af7d7a09 100644 --- a/LeanMachineLearning/SequentialLearning/Algorithms/Uniform.lean +++ b/LeanMachineLearning/SequentialLearning/Algorithms/Uniform.lean @@ -16,11 +16,11 @@ An algorithm that chooses actions uniformly at random in every situation. ## Main definitions -* `uniformAlgorithm`: a uniform algorithm with actions in a finite non-empty type `𝓐`. +* `Algorithm.uniform`: a uniform algorithm with actions in a finite non-empty type `𝓐`. -## Main results +## Main statements -* `absolutelyContinuous_uniformAlgorithm`: every algorithm with actions in `𝓐` is absolutely +* `Algorithm.absolutelyContinuous_uniform`: every algorithm with actions in `𝓐` is absolutely continuous with respect to the uniform algorithm with the same type of feedback. -/ @@ -37,15 +37,15 @@ variable {𝓞 𝓐 𝓨 : Type*} {m𝓞 : MeasurableSpace 𝓞} {m𝓐 : Measur /-- The Uniform algorithm: actions are chosen uniformly at random. -/ noncomputable -def uniformAlgorithm [Finite 𝓐] [Nonempty 𝓐] : Algorithm 𝓞 𝓐 𝓨 := +def Algorithm.uniform [Finite 𝓐] [Nonempty 𝓐] : Algorithm 𝓞 𝓐 𝓨 := Algorithm.const (uniformOn Set.univ) -instance [Finite 𝓐] [Nonempty 𝓐] : (uniformAlgorithm : Algorithm 𝓞 𝓐 𝓨).IsMarkov := +instance [Finite 𝓐] [Nonempty 𝓐] : (Algorithm.uniform : Algorithm 𝓞 𝓐 𝓨).IsMarkov := inferInstanceAs (Algorithm.const (uniformOn Set.univ) : Algorithm 𝓞 𝓐 𝓨).IsMarkov -lemma absolutelyContinuous_uniformAlgorithm [Finite 𝓐] [Nonempty 𝓐] {alg : Algorithm 𝓞 𝓐 𝓨} : - alg ≪ₐ uniformAlgorithm where +lemma Algorithm.absolutelyContinuous_uniform [Finite 𝓐] [Nonempty 𝓐] (alg : Algorithm 𝓞 𝓐 𝓨) : + alg ≪ₐ Algorithm.uniform where policy n h := Measure.absolutelyContinuous_of_measure_singleton_ne_zero - (by simp [uniformAlgorithm, uniformOn, ← pos_iff_ne_zero, cond_pos_of_inter_ne_zero]) + (by simp [Algorithm.uniform, uniformOn, ← pos_iff_ne_zero, cond_pos_of_inter_ne_zero]) end Learning diff --git a/LeanMachineLearning/SequentialLearning/BayesStationaryEnv.lean b/LeanMachineLearning/SequentialLearning/BayesStationaryEnv.lean index e177abbd..db8fc628 100644 --- a/LeanMachineLearning/SequentialLearning/BayesStationaryEnv.lean +++ b/LeanMachineLearning/SequentialLearning/BayesStationaryEnv.lean @@ -14,43 +14,41 @@ public import LeanMachineLearning.SequentialLearning.StationaryEnv A Bayesian stationary environment is an environment that draws a parameter `e : 𝓔` from a prior `Q` before the first round and then behaves like the stationary environment -`Environment.bandit (κ.sectR e)`. Concretely, `bayesStationaryEnv Q κ : Environment 𝓔 𝓐 𝓨` announces -an observation `e` at every round and runs against `alg.comapObs (fun _ ↦ ())`, for +`Environment.bandit (κ.sectR e)`. Concretely, `Environment.bayesBandit Q κ : Environment 𝓔 𝓐 𝓨` +announces an observation `e` at every round and runs against `alg.comapObs (fun _ ↦ ())`, for an `alg : Algorithm Unit 𝓐 𝓨`, an algorithm that does not use the observation. ## Main definitions -* `bayesStationaryEnv Q κ`: the environment that draws a parameter from `Q` before the first - round, announces it as the observation of every round, and returns feedback `κ (e, a)` when the - parameter is `e` and the action is `a`. +* `Environment.bayesBandit Q κ`: the environment that draws a parameter from `Q` before the + first round, announces it as the observation of every round, and returns feedback `κ (e, a)` + when the parameter is `e` and the action is `a`. * `IsBayesAlgEnvSeq Q κ alg E A Y P`: states that the parameter `E : Ω → 𝓔` has law `Q` and that the sequences of actions `A : ℕ → Ω → 𝓐` and feedbacks `Y : ℕ → Ω → 𝓨` are generated by the - algorithm `alg : Algorithm Unit 𝓐 𝓨` interacting with `bayesStationaryEnv Q κ`, which it sees - through `Algorithm.comapObs (fun _ ↦ ())`. Equivalently, `A` and `Y` are generated by `alg` + algorithm `alg : Algorithm Unit 𝓐 𝓨` interacting with `Environment.bayesBandit Q κ`, which it + sees through `Algorithm.comapObs (fun _ ↦ ())`. Equivalently, `A` and `Y` are generated by `alg` interacting with the stationary environment `Environment.bandit (κ.sectR (E ω))`. -* `bayesTrajMeasure Q κ alg`: for any choice of probability measure `Q : Measure 𝓔`, Markov kernel - `κ : Kernel (𝓔 × 𝓐) 𝓨`, and algorithm `alg : Algorithm Unit 𝓐 𝓨`, provides a probability measure +* `IT.bayesTrajMeasure Q κ alg`: for any choice of probability measure `Q : Measure 𝓔`, Markov + kernel `κ : Kernel (𝓔 × 𝓐) 𝓨`, and algorithm `alg : Algorithm Unit 𝓐 𝓨`, a probability measure `P : Measure (ℕ → Round 𝓔 𝓐 𝓨)` on a space that carries `E`, `A`, and `Y` such that - `IsBayesAlgEnvSeq Q κ alg E A Y P`. -* `bayesTrajMeasurePosterior Q κ alg n`: a `Kernel (Hist Unit 𝓐 𝓨 n) 𝓔` that represents the + `IsBayesAlgEnvSeq Q κ alg E A Y P` (with `E = IT.obs 0`, `A = IT.action`, `Y = IT.feedback`). +* `IT.bayesTrajMeasurePosterior Q κ alg n`: a `Kernel (Hist Unit 𝓐 𝓨 n) 𝓔` that represents the posterior over `E` given the history before time `n` (the `n` first rounds) under the prior `Q` and the algorithm `alg`, assuming that the kernel `κ` specifies how `E` gives rise to the underlying (stationary) environment. See also `LeanMachineLearning/SequentialLearning/AlgorithmDensityBayes.lean`. -## Main results +## Main statements * `IsAlgEnvSeq.isBayesAlgEnvSeq`: a run of `alg.comapObs (fun _ ↦ ())` against - `bayesStationaryEnv Q κ` is a Bayesian algorithm-environment sequence for the announced parameter. -* `ae_IsAlgEnvSeq h`: if `h : IsBayesAlgEnvSeq Q κ alg E A Y P`, for `Q`-almost every `e : 𝓔`, - `IsAlgEnvSeq O' A' Y' alg (Environment.bandit (κ.sectR e)) (condDistrib (trajectory _ A Y) E P e)` - for some sequence of actions `A' : ℕ → (ℕ → Round Unit 𝓐 𝓨) → 𝓐` and sequence of feedbacks - `Y' : ℕ → (ℕ → Round Unit 𝓐 𝓨) → 𝓨`. Intuitively, if the observable trajectory is generated by an - underlying parameter `e : 𝓔`, the measure that carries the `IsBayesAlgEnvSeq` structure reveals a - measure that carries an `IsAlgEnvSeq` structure under the environment - `Environment.bandit (κ.sectR e)` and the same algorithm. This allows transferring results from - the `IsAlgEnvSeq` structure to the - `IsBayesAlgEnvSeq` structure. + `Environment.bayesBandit Q κ` is a Bayesian algorithm-environment sequence for the announced + parameter. +* `IsBayesAlgEnvSeq.ae_isAlgEnvSeq h`: if `h : IsBayesAlgEnvSeq Q κ alg E A Y P`, for `Q`-almost + every `e : 𝓔`, the coordinate processes `IT.obs`, `IT.action` and `IT.feedback` on + `ℕ → Round Unit 𝓐 𝓨` form an algorithm-environment sequence for `alg` and + `Environment.bandit (κ.sectR e)` under `condDistrib (trajectory (noObs Ω) A Y) E P e`, the + conditional law of the observable trajectory given `E = e`. This allows transferring results + from the `IsAlgEnvSeq` structure to the `IsBayesAlgEnvSeq` structure. -/ @@ -71,7 +69,7 @@ the observation of every round, and returns a feedback drawn from `κ (e, a)` wh `a`. The algorithm is meant to ignore the announced parameter, that is, to run through `Algorithm.comapObs (fun _ ↦ ())`. -/ noncomputable -def bayesStationaryEnv (Q : Measure 𝓔) [IsProbabilityMeasure Q] (κ : Kernel (𝓔 × 𝓐) 𝓨) +def Environment.bayesBandit (Q : Measure 𝓔) [IsProbabilityMeasure Q] (κ : Kernel (𝓔 × 𝓐) 𝓨) [IsMarkovKernel κ] : Environment 𝓔 𝓐 𝓨 where obs | 0 => Kernel.const _ Q @@ -82,22 +80,24 @@ def bayesStationaryEnv (Q : Measure 𝓔) [IsProbabilityMeasure Q] (κ : Kernel variable {Q : Measure 𝓔} [IsProbabilityMeasure Q] {κ : Kernel (𝓔 × 𝓐) 𝓨} [IsMarkovKernel κ] @[simp] -lemma obs_bayesStationaryEnv_zero : (bayesStationaryEnv Q κ).obs 0 = Kernel.const _ Q := rfl +lemma Environment.obs_bayesBandit_zero : + (Environment.bayesBandit Q κ).obs 0 = Kernel.const _ Q := rfl @[simp] -lemma obs_bayesStationaryEnv_succ (n : ℕ) : - (bayesStationaryEnv Q κ).obs (n + 1) +lemma Environment.obs_bayesBandit_succ (n : ℕ) : + (Environment.bayesBandit Q κ).obs (n + 1) = Kernel.deterministic (fun h : Hist 𝓔 𝓐 𝓨 (n + 1) ↦ (h 0).obs) (by fun_prop) := rfl @[simp] -lemma feedback_bayesStationaryEnv (n : ℕ) : - (bayesStationaryEnv Q κ).feedback n = κ.comap (fun p ↦ (p.1.2, p.2)) (by fun_prop) := rfl +lemma Environment.feedback_bayesBandit (n : ℕ) : + (Environment.bayesBandit Q κ).feedback n = κ.comap (fun p ↦ (p.1.2, p.2)) (by fun_prop) := rfl @[simp] -lemma obsZero_bayesStationaryEnv : (bayesStationaryEnv Q κ).obsZero = Q := rfl +lemma Environment.obsZero_bayesBandit : (Environment.bayesBandit Q κ).obsZero = Q := rfl @[simp] -lemma feedbackZero_bayesStationaryEnv : (bayesStationaryEnv Q κ).feedbackZero = κ := rfl +lemma Environment.feedbackZero_bayesBandit : + (Environment.bayesBandit Q κ).feedbackZero = κ := rfl end BayesEnv @@ -111,31 +111,31 @@ lemma measurable_announceHist (n : ℕ) : unfold announceHist fun_prop -/-- `IsBayesAlgEnvSeq Q κ alg E A Y P` states that there is a measure `P : Measure Ω` such -that the parameter `E : Ω → 𝓔` has law `Q` and that the sequences of actions `A : ℕ → Ω → 𝓐` -and feedbacks `Y : ℕ → Ω → 𝓨` are generated by the algorithm `alg : Algorithm Unit 𝓐 𝓨` -interacting with an underlying environment that depends on `E` and `κ` -(`Environment.bandit (κ.sectR (E ω))`). +/-- `IsBayesAlgEnvSeq Q κ alg E A Y P` states that, under the probability measure `P`, the +parameter `E : Ω → 𝓔` has law `Q` and the sequences of actions `A : ℕ → Ω → 𝓐` and feedbacks +`Y : ℕ → Ω → 𝓨` are generated by the algorithm `alg : Algorithm Unit 𝓐 𝓨` interacting with an +underlying environment that depends on `E` and `κ` (`Environment.bandit (κ.sectR (E ω))`). -This is `IsAlgEnvSeq` for the announcing environment `bayesStationaryEnv Q κ` and the algorithm -`alg.comapObs (fun _ ↦ ())` that ignores the announced parameter: the observation at every round -is `E ω`. -/ +This is `IsAlgEnvSeq` for the announcing environment `Environment.bayesBandit Q κ` and the +algorithm `alg.comapObs (fun _ ↦ ())` that ignores the announced parameter: the observation at every +round is `E ω`. -/ def IsBayesAlgEnvSeq (Q : Measure 𝓔) [IsProbabilityMeasure Q] (κ : Kernel (𝓔 × 𝓐) 𝓨) [IsMarkovKernel κ] (alg : Algorithm Unit 𝓐 𝓨) (E : Ω → 𝓔) (A : ℕ → Ω → 𝓐) (Y : ℕ → Ω → 𝓨) - (P : Measure Ω) [IsProbabilityMeasure P] : Prop := - IsAlgEnvSeq (fun _ ↦ E) A Y (alg.comapObs (fun _ : 𝓔 ↦ ())) (bayesStationaryEnv Q κ) P + (P : Measure Ω) : Prop := + IsAlgEnvSeq (fun _ ↦ E) A Y (alg.comapObs (fun _ : 𝓔 ↦ ())) (Environment.bayesBandit Q κ) P namespace IsBayesAlgEnvSeq variable {Q : Measure 𝓔} [IsProbabilityMeasure Q] {κ : Kernel (𝓔 × 𝓐) 𝓨} [IsMarkovKernel κ] - {alg : Algorithm Unit 𝓐 𝓨} {P : Measure Ω} [IsProbabilityMeasure P] + {alg : Algorithm Unit 𝓐 𝓨} {P : Measure Ω} {E : Ω → 𝓔} {A : ℕ → Ω → 𝓐} {Y : ℕ → Ω → 𝓨} /-- A Bayesian algorithm-environment sequence is an algorithm-environment sequence for the -announcing environment `bayesStationaryEnv Q κ`. -/ +announcing environment `Environment.bayesBandit Q κ`. -/ lemma isAlgEnvSeq (h : IsBayesAlgEnvSeq Q κ alg E A Y P) : - IsAlgEnvSeq (fun _ ↦ E) A Y (alg.comapObs (fun _ : 𝓔 ↦ ())) (bayesStationaryEnv Q κ) P := h + IsAlgEnvSeq (fun _ ↦ E) A Y (alg.comapObs (fun _ : 𝓔 ↦ ())) (Environment.bayesBandit Q κ) P := + h lemma measurable_param (h : IsBayesAlgEnvSeq Q κ alg E A Y P) : Measurable E := h.isAlgEnvSeq.measurable_obs 0 @@ -147,14 +147,15 @@ lemma measurable_feedback (h : IsBayesAlgEnvSeq Q κ alg E A Y P) (n : ℕ) : Me h.isAlgEnvSeq.measurable_feedback n /-- The parameter has law `Q`. -/ -lemma hasLaw_env (h : IsBayesAlgEnvSeq Q κ alg E A Y P) : HasLaw E Q P := by +lemma hasLaw_env [IsProbabilityMeasure P] (h : IsBayesAlgEnvSeq Q κ alg E A Y P) : + HasLaw E Q P := by have h0 := h.isAlgEnvSeq.hasCondDistrib_obs 0 rw [history_zero] at h0 exact h0.hasLaw_of_const' /-- The action at time `n` has the correct conditional distribution given the parameter and the history: it depends only on the history. -/ -lemma hasCondDistrib_action (h : IsBayesAlgEnvSeq Q κ alg E A Y P) (n : ℕ) : +lemma hasCondDistrib_action [SFinite P] (h : IsBayesAlgEnvSeq Q κ alg E A Y P) (n : ℕ) : HasCondDistrib (A n) (fun ω ↦ (E ω, (history (noObs Ω) A Y n ω, noObs Ω n ω))) ((alg.policy n).prodMkLeft _) P := HasCondDistrib.comp_right @@ -165,7 +166,7 @@ lemma hasCondDistrib_action (h : IsBayesAlgEnvSeq Q κ alg E A Y P) (n : ℕ) : /-- The feedback at time `n` has the correct conditional distribution given the history, the parameter and the action at time `n`: it depends only on the parameter and the action. -/ -lemma hasCondDistrib_feedback (h : IsBayesAlgEnvSeq Q κ alg E A Y P) (n : ℕ) : +lemma hasCondDistrib_feedback [SFinite P] (h : IsBayesAlgEnvSeq Q κ alg E A Y P) (n : ℕ) : HasCondDistrib (Y n) (fun ω ↦ ((history (noObs Ω) A Y n ω, noObs Ω n ω), (E ω, A n ω))) (κ.prodMkLeft _) P := HasCondDistrib.comp_right @@ -175,15 +176,15 @@ lemma hasCondDistrib_feedback (h : IsBayesAlgEnvSeq Q κ alg E A Y P) (n : ℕ) (Z := fun ω ↦ ((history (fun _ ↦ E) A Y n ω, E ω), A n ω)) (h.isAlgEnvSeq.hasCondDistrib_feedback n) -lemma hasCondDistrib_action' (h : IsBayesAlgEnvSeq Q κ alg E A Y P) (n : ℕ) : +lemma hasCondDistrib_action' [SFinite P] (h : IsBayesAlgEnvSeq Q κ alg E A Y P) (n : ℕ) : HasCondDistrib (A n) (fun ω ↦ (history (noObs Ω) A Y n ω, noObs Ω n ω)) (alg.policy n) P := (h.hasCondDistrib_action n).comp_right -lemma hasCondDistrib_feedback' (h : IsBayesAlgEnvSeq Q κ alg E A Y P) (n : ℕ) : +lemma hasCondDistrib_feedback' [SFinite P] (h : IsBayesAlgEnvSeq Q κ alg E A Y P) (n : ℕ) : HasCondDistrib (Y n) (fun ω ↦ (E ω, A n ω)) κ P := (h.hasCondDistrib_feedback n).comp_right -lemma hasLaw_action_zero (h : IsBayesAlgEnvSeq Q κ alg E A Y P) : +lemma hasLaw_action_zero [IsProbabilityMeasure P] (h : IsBayesAlgEnvSeq Q κ alg E A Y P) : HasLaw (A 0) (alg.policyZero ()) P := by have h0 : HasCondDistrib (A 0) (fun _ : Ω ↦ ((default : Hist Unit 𝓐 𝓨 0), ())) (alg.policy 0) P := by @@ -192,29 +193,25 @@ lemma hasLaw_action_zero (h : IsBayesAlgEnvSeq Q κ alg E A Y P) : exact h0.hasLaw_of_const' /-- The first action is independent of the parameter `E`, and has law `alg.policyZero ()`. -/ -lemma hasCondDistrib_action_zero (h : IsBayesAlgEnvSeq Q κ alg E A Y P) : +lemma hasCondDistrib_action_zero [SFinite P] (h : IsBayesAlgEnvSeq Q κ alg E A Y P) : HasCondDistrib (A 0) E (Kernel.const _ (alg.policyZero ())) P := hasCondDistrib_prodMk_right_unique_iff.mp (h.hasCondDistrib_action 0) /-- The posterior over the parameter given the empty history is the prior. -/ -lemma condDistrib_param_history_zero [StandardBorelSpace 𝓔] [Nonempty 𝓔] +lemma condDistrib_param_history_zero [IsProbabilityMeasure P] [StandardBorelSpace 𝓔] [Nonempty 𝓔] (h : IsBayesAlgEnvSeq Q κ alg E A Y P) : condDistrib E (history (noObs Ω) A Y 0) P = Kernel.const _ Q := by ext x : 1 rw [Unique.eq_default x, history_zero] have hc : HasCondDistrib E (fun _ : Ω ↦ (default : Hist Unit 𝓐 𝓨 0)) (Kernel.const _ Q) P := h.hasLaw_env.hasCondDistrib_const - have h_ae := hc.condDistrib_eq + have h_ae := hc.condDistrib_ae_eq rw [Measure.map_const, measure_univ, one_smul, Filter.EventuallyEq, ae_dirac_iff Subsingleton.measurableSet] at h_ae exact h_ae -variable [StandardBorelSpace 𝓐] [Nonempty 𝓐] [StandardBorelSpace 𝓨] [Nonempty 𝓨] - -lemma hasCondDistrib_IT_obs (_h : IsBayesAlgEnvSeq Q κ alg E A Y P) (n : ℕ) : - ∀ᵐ e ∂Q, HasCondDistrib (IT.obs n) (IT.hist n) (Kernel.const _ (Measure.dirac ())) - (condDistrib (trajectory (noObs Ω) A Y) E P e) := - ae_of_all _ fun _ ↦ hasCondDistrib_unit (IT.measurable_hist n).aemeasurable _ _ +variable [IsProbabilityMeasure P] [StandardBorelSpace 𝓐] [Nonempty 𝓐] [StandardBorelSpace 𝓨] + [Nonempty 𝓨] lemma hasCondDistrib_IT_action (h : IsBayesAlgEnvSeq Q κ alg E A Y P) (n : ℕ) : ∀ᵐ e ∂Q, HasCondDistrib (IT.action n) (fun τ ↦ (IT.hist n τ, IT.obs n τ)) (alg.policy n) @@ -254,13 +251,16 @@ lemma hasLaw_IT_hist (h : IsBayesAlgEnvSeq Q κ alg E A Y P) (n : ℕ) : exact ⟨(IT.measurable_hist n).aemeasurable, by rw [← Kernel.map_apply _ (IT.measurable_hist n), he]⟩ -lemma ae_IsAlgEnvSeq (h : IsBayesAlgEnvSeq Q κ alg E A Y P) : +/-- For `Q`-almost every `e`, under the conditional law of the observable trajectory given +`E = e`, the coordinate processes form an algorithm-environment sequence for `alg` and the +stationary environment `Environment.bandit (κ.sectR e)`. -/ +lemma ae_isAlgEnvSeq (h : IsBayesAlgEnvSeq Q κ alg E A Y P) : ∀ᵐ e ∂Q, IsAlgEnvSeq IT.obs IT.action IT.feedback alg (Environment.bandit (κ.sectR e)) (condDistrib (trajectory (noObs Ω) A Y) E P e) := by - filter_upwards [ae_all_iff.2 (hasCondDistrib_IT_obs h), - ae_all_iff.2 (hasCondDistrib_IT_action h), - ae_all_iff.2 (hasCondDistrib_IT_feedback h)] with _ hO hA hR - exact ⟨IT.measurable_obs, IT.measurable_action, IT.measurable_feedback, hO, hA, hR⟩ + filter_upwards [ae_all_iff.2 (hasCondDistrib_IT_action h), + ae_all_iff.2 (hasCondDistrib_IT_feedback h)] with _ hA hY + exact ⟨IT.measurable_obs, IT.measurable_action, IT.measurable_feedback, + fun n ↦ hasCondDistrib_unit (IT.measurable_hist n).aemeasurable _ _, hA, hY⟩ end IsBayesAlgEnvSeq @@ -268,32 +268,32 @@ section IsAlgEnvSeq variable {Q : Measure 𝓔} [IsProbabilityMeasure Q] {κ : Kernel (𝓔 × 𝓐) 𝓨} [IsMarkovKernel κ] variable {alg : Algorithm Unit 𝓐 𝓨} {O : ℕ → Ω → 𝓔} {A : ℕ → Ω → 𝓐} {Y : ℕ → Ω → 𝓨} -variable {P : Measure Ω} [IsProbabilityMeasure P] +variable {P : Measure Ω} [SFinite P] -/-- Under `bayesStationaryEnv Q κ`, the announced parameter is almost surely the same at every -round. -/ -lemma IsAlgEnvSeq.ae_obs_eq_obs_zero [StandardBorelSpace 𝓔] - (h : IsAlgEnvSeq O A Y (alg.comapObs (fun _ : 𝓔 ↦ ())) (bayesStationaryEnv Q κ) P) (n : ℕ) : +/-- Under `Environment.bayesBandit Q κ`, the announced parameter is almost surely the same at +every round. -/ +lemma IsAlgEnvSeq.ae_obs_eq_obs_zero_bayesBandit [MeasurableEq 𝓔] + (h : IsAlgEnvSeq O A Y (alg.comapObs (fun _ : 𝓔 ↦ ())) (Environment.bayesBandit Q κ) P) + (n : ℕ) : O 0 =ᵐ[P] O n := by cases n with | zero => rfl | succ n => have h1 := h.hasCondDistrib_obs (n + 1) - rw [obs_bayesStationaryEnv_succ] at h1 - have h2 := ae_eq_of_hasCondDistrib_deterministic (by fun_prop) - (h.measurable_history (n + 1)).aemeasurable (h.measurable_obs (n + 1)).aemeasurable h1 + rw [Environment.obs_bayesBandit_succ] at h1 + have h2 := h1.ae_eq_of_deterministic filter_upwards [h2] with ω hω rw [hω] simp [history_apply] /-- A run of `alg.comapObs (fun _ ↦ ())` against the announcing environment -`bayesStationaryEnv Q κ` is a Bayesian algorithm-environment sequence for the announced +`Environment.bayesBandit Q κ` is a Bayesian algorithm-environment sequence for the announced parameter. -/ -lemma IsAlgEnvSeq.isBayesAlgEnvSeq [StandardBorelSpace 𝓔] - (h : IsAlgEnvSeq O A Y (alg.comapObs (fun _ : 𝓔 ↦ ())) (bayesStationaryEnv Q κ) P) : +lemma IsAlgEnvSeq.isBayesAlgEnvSeq [MeasurableEq 𝓔] + (h : IsAlgEnvSeq O A Y (alg.comapObs (fun _ : 𝓔 ↦ ())) (Environment.bayesBandit Q κ) P) : IsBayesAlgEnvSeq Q κ alg (O 0) A Y P := h.congr (fun _ ↦ h.measurable_obs 0) h.measurable_action h.measurable_feedback - h.ae_obs_eq_obs_zero (fun _ ↦ .rfl) (fun _ ↦ .rfl) + h.ae_obs_eq_obs_zero_bayesBandit (fun _ ↦ .rfl) (fun _ ↦ .rfl) end IsAlgEnvSeq @@ -305,10 +305,10 @@ namespace IT noncomputable def bayesTrajMeasure (Q : Measure 𝓔) [IsProbabilityMeasure Q] (κ : Kernel (𝓔 × 𝓐) 𝓨) [IsMarkovKernel κ] (alg : Algorithm Unit 𝓐 𝓨) : Measure (ℕ → Round 𝓔 𝓐 𝓨) := - trajMeasure (alg.comapObs (fun _ : 𝓔 ↦ ())) (bayesStationaryEnv Q κ) + trajMeasure (alg.comapObs (fun _ : 𝓔 ↦ ())) (Environment.bayesBandit Q κ) deriving IsProbabilityMeasure -lemma isBayesAlgEnvSeq_bayesTrajMeasure [StandardBorelSpace 𝓔] +lemma isBayesAlgEnvSeq_bayesTrajMeasure [MeasurableEq 𝓔] (Q : Measure 𝓔) [IsProbabilityMeasure Q] (κ : Kernel (𝓔 × 𝓐) 𝓨) [IsMarkovKernel κ] (alg : Algorithm Unit 𝓐 𝓨) : IsBayesAlgEnvSeq Q κ alg (obs 0) action feedback (bayesTrajMeasure Q κ alg) := diff --git a/LeanMachineLearning/SequentialLearning/Comap.lean b/LeanMachineLearning/SequentialLearning/Comap.lean index bda9378f..2f079433 100644 --- a/LeanMachineLearning/SequentialLearning/Comap.lean +++ b/LeanMachineLearning/SequentialLearning/Comap.lean @@ -274,7 +274,7 @@ lemma Environment.feedbackZero_comap (env : Environment 𝓞 𝓐 𝓨) (hF : lemma Environment.comap_id (env : Environment 𝓞 𝓐 𝓨) : env.comap (fun _ ↦ id) (fun _ ↦ measurable_id) id measurable_id = env := rfl -lemma Environment.comap_comp (env : Environment 𝓞 𝓐 𝓨) (hF : ∀ n, Measurable (F n)) +lemma Environment.comap_comap (env : Environment 𝓞 𝓐 𝓨) (hF : ∀ n, Measurable (F n)) (hf : Measurable f) {G : (n : ℕ) → Hist 𝓞 𝓐'' 𝓨 n → Hist 𝓞 𝓐' 𝓨 n} (hG : ∀ n, Measurable (G n)) {g : 𝓐'' → 𝓐'} (hg : Measurable g) : @@ -317,8 +317,8 @@ lemma Environment.feedbackZero_comapAction (env : Environment 𝓞 𝓐 𝓨) (h lemma Environment.comapAction_id (env : Environment 𝓞 𝓐 𝓨) : env.comapAction id measurable_id = env := rfl -lemma Environment.comapAction_comp (env : Environment 𝓞 𝓐 𝓨) (hf : Measurable f) - (g : 𝓐'' → 𝓐') (hg : Measurable g) : +lemma Environment.comapAction_comapAction (env : Environment 𝓞 𝓐 𝓨) (hf : Measurable f) + {g : 𝓐'' → 𝓐'} (hg : Measurable g) : (env.comapAction f hf).comapAction g hg = env.comapAction (f ∘ g) (hf.comp hg) := rfl end ComapAction @@ -457,7 +457,7 @@ end Congr section Runs -variable {alg : Algorithm 𝓞 𝓐 𝓨} {P : Measure Ω} [IsFiniteMeasure P] +variable {alg : Algorithm 𝓞 𝓐 𝓨} {P : Measure Ω} [SFinite P] {A : ℕ → Ω → 𝓐} {Y : ℕ → Ω → 𝓨} namespace IsAlgEnvSeq diff --git a/LeanMachineLearning/SequentialLearning/Deterministic.lean b/LeanMachineLearning/SequentialLearning/Deterministic.lean index ab7824b0..fba22991 100644 --- a/LeanMachineLearning/SequentialLearning/Deterministic.lean +++ b/LeanMachineLearning/SequentialLearning/Deterministic.lean @@ -107,58 +107,56 @@ lemma policyZero_eq_deterministic (alg : Algorithm 𝓞 𝓐 𝓨) [alg.IsDeterm end Algorithm -namespace Algorithm.IsDeterministic +section IsDeterministic + +/-! ### Runs of a deterministic algorithm -/ variable {Ω : Type*} {mΩ : MeasurableSpace Ω} - {alg : Algorithm 𝓞 𝓐 𝓨} {env : Environment 𝓞 𝓐 𝓨} {P : Measure Ω} [IsFiniteMeasure P] + {alg : Algorithm 𝓞 𝓐 𝓨} {env : Environment 𝓞 𝓐 𝓨} {P : Measure Ω} [SFinite P] {O : ℕ → Ω → 𝓞} {A : ℕ → Ω → 𝓐} {Y : ℕ → Ω → 𝓨} {n N : ℕ} -lemma action_ae_eq_of_IsAlgEnvSeqUntil [MeasurableEq 𝓐] +lemma IsAlgEnvSeqUntil.action_ae_eq_nextAction [MeasurableEq 𝓐] [h_det : alg.IsDeterministic] (h : IsAlgEnvSeqUntil O A Y alg env P N) (hn : n < N) : A n =ᵐ[P] fun ω ↦ alg.nextAction n (history O A Y n ω, O n ω) := by have h_eq := (h.hasCondDistrib_action n hn) rw [alg.policy_eq_deterministic n] at h_eq - have hO := h.measurable_obs - have hA := h.measurable_action - have hY := h.measurable_feedback - exact ae_eq_of_hasCondDistrib_deterministic (measurable_nextAction _ _) (by fun_prop) - (by fun_prop) h_eq - -lemma action_zero_of_IsAlgEnvSeqUntil [MeasurableEq 𝓐] [h_det : alg.IsDeterministic] - (h : IsAlgEnvSeqUntil O A Y alg env P N) (hN : 0 < N) : + exact h_eq.ae_eq_of_deterministic + +lemma IsAlgEnvSeqUntil.action_zero_ae_eq_actionZero [MeasurableEq 𝓐] + [h_det : alg.IsDeterministic] (h : IsAlgEnvSeqUntil O A Y alg env P N) (hN : 0 < N) : A 0 =ᵐ[P] fun ω ↦ alg.actionZero (O 0 ω) := by - filter_upwards [action_ae_eq_of_IsAlgEnvSeqUntil h hN] with ω hω - rw [hω, nextAction_zero] + filter_upwards [h.action_ae_eq_nextAction hN] with ω hω + rw [hω, Algorithm.nextAction_zero] -lemma hasCondDistrib_action_zero_of_IsAlgEnvSeqUntil [h_det : alg.IsDeterministic] - (h : IsAlgEnvSeqUntil O A Y alg env P N) (hN : 0 < N) : +lemma IsAlgEnvSeqUntil.hasCondDistrib_action_zero_actionZero + [h_det : alg.IsDeterministic] (h : IsAlgEnvSeqUntil O A Y alg env P N) (hN : 0 < N) : HasCondDistrib (A 0) (O 0) (Kernel.deterministic alg.actionZero alg.measurable_actionZero) P := by - rw [← policyZero_eq_deterministic] + rw [← Algorithm.policyZero_eq_deterministic] exact h.hasCondDistrib_action_zero hN -lemma hasCondDistrib_action_zero [h_det : alg.IsDeterministic] +lemma IsAlgEnvSeq.hasCondDistrib_action_zero_actionZero [h_det : alg.IsDeterministic] (h : IsAlgEnvSeq O A Y alg env P) : HasCondDistrib (A 0) (O 0) (Kernel.deterministic alg.actionZero alg.measurable_actionZero) P := - hasCondDistrib_action_zero_of_IsAlgEnvSeqUntil (h.isAlgEnvSeqUntil 1) zero_lt_one + (h.isAlgEnvSeqUntil 1).hasCondDistrib_action_zero_actionZero zero_lt_one -lemma action_ae_eq [MeasurableEq 𝓐] [h_det : alg.IsDeterministic] - (h : IsAlgEnvSeq O A Y alg env P) (n : ℕ) : +lemma IsAlgEnvSeq.action_ae_eq_nextAction [MeasurableEq 𝓐] + [h_det : alg.IsDeterministic] (h : IsAlgEnvSeq O A Y alg env P) (n : ℕ) : A n =ᵐ[P] fun ω ↦ alg.nextAction n (history O A Y n ω, O n ω) := - action_ae_eq_of_IsAlgEnvSeqUntil (h.isAlgEnvSeqUntil (n + 1)) n.lt_succ_self + (h.isAlgEnvSeqUntil (n + 1)).action_ae_eq_nextAction n.lt_succ_self -lemma action_zero_ae_eq [MeasurableEq 𝓐] [h_det : alg.IsDeterministic] - (h : IsAlgEnvSeq O A Y alg env P) : +lemma IsAlgEnvSeq.action_zero_ae_eq_actionZero [MeasurableEq 𝓐] + [h_det : alg.IsDeterministic] (h : IsAlgEnvSeq O A Y alg env P) : A 0 =ᵐ[P] fun ω ↦ alg.actionZero (O 0 ω) := - action_zero_of_IsAlgEnvSeqUntil (h.isAlgEnvSeqUntil 1) zero_lt_one + (h.isAlgEnvSeqUntil 1).action_zero_ae_eq_actionZero zero_lt_one -lemma action_ae_all_eq [MeasurableEq 𝓐] [h_det : alg.IsDeterministic] - (h : IsAlgEnvSeq O A Y alg env P) : +lemma IsAlgEnvSeq.action_ae_all_eq_nextAction [MeasurableEq 𝓐] + [h_det : alg.IsDeterministic] (h : IsAlgEnvSeq O A Y alg env P) : ∀ᵐ ω ∂P, ∀ n, A n ω = alg.nextAction n (history O A Y n ω, O n ω) := - ae_all_iff.mpr (action_ae_eq h) + ae_all_iff.mpr h.action_ae_eq_nextAction -end Algorithm.IsDeterministic +end IsDeterministic /-- An environment has deterministic feedback if its feedbacks are determined by measurable functions of the history, the observation and the action (and not possibly random kernels). -/ @@ -210,36 +208,34 @@ lemma feedbackZero_eq_deterministic (env : Environment 𝓞 𝓐 𝓨) [env.HasD end Environment -namespace Environment.HasDeterministicFeedback +section HasDeterministicFeedback + +/-! ### Runs in an environment with deterministic feedback -/ variable {Ω : Type*} {mΩ : MeasurableSpace Ω} - {alg : Algorithm 𝓞 𝓐 𝓨} {env : Environment 𝓞 𝓐 𝓨} {P : Measure Ω} [IsFiniteMeasure P] + {alg : Algorithm 𝓞 𝓐 𝓨} {env : Environment 𝓞 𝓐 𝓨} {P : Measure Ω} {O : ℕ → Ω → 𝓞} {A : ℕ → Ω → 𝓐} {Y : ℕ → Ω → 𝓨} -lemma hasCondDistrib_feedback [h_det : env.HasDeterministicFeedback] +lemma IsAlgEnvSeq.hasCondDistrib_feedback_feedbackFun [h_det : env.HasDeterministicFeedback] (h : IsAlgEnvSeq O A Y alg env P) (n : ℕ) : HasCondDistrib (Y n) (fun ω ↦ ((history O A Y n ω, O n ω), A n ω)) (Kernel.deterministic (env.feedbackFun n) (env.measurable_feedbackFun n)) P := by - rw [← feedback_eq_deterministic] + rw [← Environment.feedback_eq_deterministic] exact h.hasCondDistrib_feedback n -lemma hasCondDistrib_feedback_zero [h_det : env.HasDeterministicFeedback] - (h : IsAlgEnvSeq O A Y alg env P) : +lemma IsAlgEnvSeq.hasCondDistrib_feedback_zero_feedbackFunZero [SFinite P] + [h_det : env.HasDeterministicFeedback] (h : IsAlgEnvSeq O A Y alg env P) : HasCondDistrib (Y 0) (fun ω ↦ (O 0 ω, A 0 ω)) (Kernel.deterministic env.feedbackFunZero env.measurable_feedbackFunZero) P := by - rw [← feedbackZero_eq_deterministic] + rw [← Environment.feedbackZero_eq_deterministic] exact h.hasCondDistrib_feedback_zero -lemma feedback_ae_eq [MeasurableEq 𝓨] [h_det : env.HasDeterministicFeedback] - (h : IsAlgEnvSeq O A Y alg env P) (n : ℕ) : - Y n =ᵐ[P] fun ω ↦ env.feedbackFun n ((history O A Y n ω, O n ω), A n ω) := by - have hO := h.measurable_obs - have hA := h.measurable_action - have hY := h.measurable_feedback - exact ae_eq_of_hasCondDistrib_deterministic (measurable_feedbackFun _ _) (by fun_prop) - (by fun_prop) (hasCondDistrib_feedback h n) +lemma IsAlgEnvSeq.feedback_ae_eq_feedbackFun [SFinite P] [MeasurableEq 𝓨] + [h_det : env.HasDeterministicFeedback] (h : IsAlgEnvSeq O A Y alg env P) (n : ℕ) : + Y n =ᵐ[P] fun ω ↦ env.feedbackFun n ((history O A Y n ω, O n ω), A n ω) := + (h.hasCondDistrib_feedback_feedbackFun n).ae_eq_of_deterministic -end Environment.HasDeterministicFeedback +end HasDeterministicFeedback variable {nextA : (n : ℕ) → (Hist 𝓞 𝓐 𝓨 n × 𝓞) → 𝓐} {h_next : ∀ n, Measurable (nextA n)} {env : Environment 𝓞 𝓐 𝓨} @@ -312,9 +308,7 @@ lemma feedbackFunZero_detFeedback [MeasurableSpace.SeparatesPoints 𝓨] : namespace IsAlgEnvSeq -variable {Ω : Type*} {mΩ : MeasurableSpace Ω} - {alg : Algorithm 𝓞 𝓐 𝓨} {ν : Kernel (𝓞 × 𝓐) 𝓨} [IsMarkovKernel ν] - {P : Measure Ω} [IsProbabilityMeasure P] +variable {Ω : Type*} {mΩ : MeasurableSpace Ω} {P : Measure Ω} [SFinite P] {O : ℕ → Ω → 𝓞} {A : ℕ → Ω → 𝓐} {Y : ℕ → Ω → 𝓨} lemma hasCondDistrib_action_zero_deterministic @@ -325,28 +319,26 @@ lemma hasCondDistrib_action_zero_deterministic rw [← policyZero_deterministic] exact h.hasCondDistrib_action_zero -lemma action_deterministic_ae_eq [MeasurableEq 𝓐] +lemma action_ae_eq_deterministic [MeasurableEq 𝓐] (h : IsAlgEnvSeq O A Y (Algorithm.deterministic nextA h_next) env P) (n : ℕ) : A n =ᵐ[P] fun ω ↦ nextA n (history O A Y n ω, O n ω) := - (Algorithm.IsDeterministic.action_ae_eq h n).trans (by simp) + (h.action_ae_eq_nextAction n).trans (by simp) -lemma action_zero_deterministic [MeasurableEq 𝓐] +lemma action_zero_ae_eq_deterministic [MeasurableEq 𝓐] (h : IsAlgEnvSeq O A Y (Algorithm.deterministic nextA h_next) env P) : A 0 =ᵐ[P] fun ω ↦ nextA 0 (default, O 0 ω) := - (Algorithm.IsDeterministic.action_zero_ae_eq h).trans (by simp) + h.action_zero_ae_eq_actionZero.trans (by simp) -lemma action_deterministic_ae_all_eq [MeasurableEq 𝓐] +lemma action_ae_all_eq_deterministic [MeasurableEq 𝓐] (h : IsAlgEnvSeq O A Y (Algorithm.deterministic nextA h_next) env P) : ∀ᵐ ω ∂P, ∀ n, A n ω = nextA n (history O A Y n ω, O n ω) := - ae_all_iff.mpr (action_deterministic_ae_eq h) + ae_all_iff.mpr h.action_ae_eq_deterministic end IsAlgEnvSeq namespace IsAlgEnvSeqUntil -variable {Ω : Type*} {mΩ : MeasurableSpace Ω} - {alg : Algorithm 𝓞 𝓐 𝓨} {ν : Kernel (𝓞 × 𝓐) 𝓨} [IsMarkovKernel ν] - {P : Measure Ω} [IsProbabilityMeasure P] +variable {Ω : Type*} {mΩ : MeasurableSpace Ω} {P : Measure Ω} [SFinite P] {O : ℕ → Ω → 𝓞} {A : ℕ → Ω → 𝓐} {Y : ℕ → Ω → 𝓨} {N n : ℕ} lemma hasCondDistrib_action_zero_deterministic @@ -357,15 +349,15 @@ lemma hasCondDistrib_action_zero_deterministic rw [← policyZero_deterministic] exact h.hasCondDistrib_action_zero hN -lemma action_deterministic_ae_eq [MeasurableEq 𝓐] +lemma action_ae_eq_deterministic [MeasurableEq 𝓐] (h : IsAlgEnvSeqUntil O A Y (Algorithm.deterministic nextA h_next) env P N) (hn : n < N) : A n =ᵐ[P] fun ω ↦ nextA n (history O A Y n ω, O n ω) := - (Algorithm.IsDeterministic.action_ae_eq_of_IsAlgEnvSeqUntil h hn).trans (by simp) + (h.action_ae_eq_nextAction hn).trans (by simp) -lemma action_zero_deterministic [MeasurableEq 𝓐] +lemma action_zero_ae_eq_deterministic [MeasurableEq 𝓐] (h : IsAlgEnvSeqUntil O A Y (Algorithm.deterministic nextA h_next) env P N) (hN : 0 < N) : A 0 =ᵐ[P] fun ω ↦ nextA 0 (default, O 0 ω) := - (Algorithm.IsDeterministic.action_zero_of_IsAlgEnvSeqUntil h hN).trans (by simp) + (h.action_zero_ae_eq_actionZero hN).trans (by simp) end IsAlgEnvSeqUntil diff --git a/LeanMachineLearning/SequentialLearning/DivergenceDecomposition.lean b/LeanMachineLearning/SequentialLearning/DivergenceDecomposition.lean index d80f6b19..75ae3aff 100644 --- a/LeanMachineLearning/SequentialLearning/DivergenceDecomposition.lean +++ b/LeanMachineLearning/SequentialLearning/DivergenceDecomposition.lean @@ -9,6 +9,7 @@ public import LeanMachineLearning.ForMathlib.InformationTheory.KullbackLeibler.C public import LeanMachineLearning.ForMathlib.InformationTheory.KullbackLeibler.CompProd public import LeanMachineLearning.ForMathlib.InformationTheory.KullbackLeibler.MapSequence public import LeanMachineLearning.ForMathlib.InformationTheory.KullbackLeibler.Restrict +public import LeanMachineLearning.ForMathlib.MeasureTheory.MeasurableSpace.Constructions public import LeanMachineLearning.SequentialLearning.StationaryEnv /-! @@ -24,10 +25,10 @@ so that term measures only how the two step kernels differ. The same identity holds for the whole trajectory `trajectory O A Y : Ω → (ℕ → Round 𝓞 𝓐 𝓨)`, with a series in place of the finite sum. -For a single algorithm run against two stationary environments with reward kernels `κ` and -`κ'`, the two step kernels share the observation kernel and the policy and differ only in the -reward kernel, so the conditional divergence of a step is the conditional divergence of the reward -given the played action. +For a single algorithm run against two stationary bandit environments `Environment.bandit κ` and +`Environment.bandit κ'`, the two step kernels share the observation kernel and the policy and +differ only in the reward kernel, so the conditional divergence of a step is the conditional +divergence of the reward given the played action. This is the *divergence decomposition* of bandit lower bounds. ## Main statements @@ -35,17 +36,18 @@ This is the *divergence decomposition* of bandit lower bounds. * `IsAlgEnvSeq.klDiv_map_history_stepKernel`, `IsAlgEnvSeq.klDiv_map_trajectory_stepKernel`: the chain rule for the law of the history of the first `M` rounds and for the law of the trajectory. -* `IsAlgEnvSeq.klDiv_map_history_compProd`, `IsAlgEnvSeq.klDiv_map_history`: the divergence - decomposition for two stationary environments, in composition-product and in integral form. -* `IsAlgEnvSeq.klDiv_map_trajectory_compProd`, `IsAlgEnvSeq.klDiv_map_trajectory`: the same two - forms for the trajectory. +* `IsAlgEnvSeq.klDiv_map_history_compProd_bandit`, `IsAlgEnvSeq.klDiv_map_history_bandit`: the + divergence decomposition for two stationary bandit environments, in composition-product and in + integral form. +* `IsAlgEnvSeq.klDiv_map_trajectory_compProd_bandit`, `IsAlgEnvSeq.klDiv_map_trajectory_bandit`: + the same two forms for the trajectory. -/ @[expose] public section open MeasureTheory ProbabilityTheory InformationTheory Finset -open scoped ENNReal RealInnerProductSpace ENat +open scoped ENNReal namespace Learning @@ -57,41 +59,6 @@ variable {𝓞 𝓐 𝓨 : Type*} {m𝓞 : MeasurableSpace 𝓞} {m𝓐 : Measur {O' : ℕ → Ω' → 𝓞} {A' : ℕ → Ω' → 𝓐} {Y' : ℕ → Ω' → 𝓨} {alg alg' : Algorithm 𝓞 𝓐 𝓨} {env env' : Environment 𝓞 𝓐 𝓨} -section - -variable {α β γ δ : Type*} {mα : MeasurableSpace α} {mβ : MeasurableSpace β} - {mγ : MeasurableSpace γ} {mδ : MeasurableSpace δ} {μ : Measure α} [IsFiniteMeasure μ] - -/-- The divergence of one step of a policy/reward decomposition, in composition-product form: -the policy `π` is shared and the reward kernels `κ`, `η` (which ignore the history) differ, so -the divergence is the conditional divergence of the reward kernels given the played action, -whose law is `π ∘ₘ μ`. -/ -lemma klDiv_compProd_compProd_prodMkLeft_eq_klDiv_comp_compProd (μ : Measure α) - [IsFiniteMeasure μ] (π : Kernel α β) [IsMarkovKernel π] (κ η : Kernel β γ) [IsFiniteKernel κ] - [IsFiniteKernel η] : - klDiv (μ ⊗ₘ (π ⊗ₖ κ.prodMkLeft α)) (μ ⊗ₘ (π ⊗ₖ η.prodMkLeft α)) = - klDiv ((π ∘ₘ μ) ⊗ₘ κ) ((π ∘ₘ μ) ⊗ₘ η) := by - rw [← klDiv_map_measurableEquiv _ _ MeasurableEquiv.prodAssoc.symm, Measure.compProd_assoc, - Measure.compProd_assoc, ← Measure.snd_compProd, Measure.snd] - exact klDiv_compProd_comap _ _ _ measurable_snd - -/-- The divergence of one step of an observation/policy/reward decomposition, in -composition-product form: the observation kernel `o` and the policy `π` are shared and the reward -kernels `κ`, `η` (which ignore the history and the observation) differ, so the divergence is the -conditional divergence of the reward kernels given the played action, whose law is -`π ∘ₘ (μ ⊗ₘ o)`. -/ -lemma klDiv_compProd_compProd_compProd_prodMkLeft_eq_klDiv_comp_compProd (μ : Measure α) - [IsFiniteMeasure μ] (o : Kernel α β) [IsMarkovKernel o] (π : Kernel (α × β) γ) - [IsMarkovKernel π] (κ η : Kernel γ δ) [IsFiniteKernel κ] [IsFiniteKernel η] : - klDiv (μ ⊗ₘ (o ⊗ₖ (π ⊗ₖ κ.prodMkLeft (α × β)))) - (μ ⊗ₘ (o ⊗ₖ (π ⊗ₖ η.prodMkLeft (α × β)))) = - klDiv ((π ∘ₘ (μ ⊗ₘ o)) ⊗ₘ κ) ((π ∘ₘ (μ ⊗ₘ o)) ⊗ₘ η) := by - rw [← klDiv_map_measurableEquiv _ _ MeasurableEquiv.prodAssoc.symm, Measure.compProd_assoc, - Measure.compProd_assoc] - exact klDiv_compProd_compProd_prodMkLeft_eq_klDiv_comp_compProd _ _ _ _ - -end - /-- **Chain rule for histories.** For two algorithms `alg`, `alg'` run against two environments `env`, `env'`, the divergence between the laws of the histories of the first `M` rounds is the sum over the rounds `t < M` of the conditional divergences of the step at round `t` given @@ -152,13 +119,15 @@ lemma IsAlgEnvSeq.klDiv_map_trajectory_stepKernel (h : IsAlgEnvSeq O A Y alg env h'.measurable_obs h'.measurable_action h'.measurable_feedback, ENNReal.tsum_eq_iSup_nat] exact iSup_congr fun n ↦ h.klDiv_map_history_stepKernel h' n -section StationaryEnv +section Bandit variable {O : ℕ → Ω → Unit} {O' : ℕ → Ω' → Unit} {alg : Algorithm Unit 𝓐 𝓨} {κ κ' : Kernel 𝓐 𝓨} [IsMarkovKernel κ] [IsMarkovKernel κ'] -/-- Chain rule for histories of a single algorithm versus two stationary environments. -/ -lemma IsAlgEnvSeq.klDiv_map_history_compProd (h : IsAlgEnvSeq O A Y alg (Environment.bandit κ) P) +/-- **Divergence decomposition** for histories of a single algorithm against two stationary bandit +environments. -/ +lemma IsAlgEnvSeq.klDiv_map_history_compProd_bandit + (h : IsAlgEnvSeq O A Y alg (Environment.bandit κ) P) (h' : IsAlgEnvSeq O' A' Y' alg (Environment.bandit κ') P') (M : ℕ) : klDiv (P.map (history O A Y M)) (P'.map (history O' A' Y' M)) = ∑ t ∈ range M, klDiv (P.map (A t) ⊗ₘ κ) (P.map (A t) ⊗ₘ κ') := by @@ -170,37 +139,41 @@ lemma IsAlgEnvSeq.klDiv_map_history_compProd (h : IsAlgEnvSeq O A Y alg (Environ klDiv_compProd_compProd_compProd_prodMkLeft_eq_klDiv_comp_compProd, ← h_obs, ← (h.hasCondDistrib_action t).hasLaw_comp.map_eq] -/-- Chain rule for histories of a single algorithm versus two stationary environments. -/ -lemma IsAlgEnvSeq.klDiv_map_history [MeasurableSpace.CountablyGenerated 𝓨] +/-- **Divergence decomposition** for histories of a single algorithm against two stationary bandit +environments. -/ +lemma IsAlgEnvSeq.klDiv_map_history_bandit [MeasurableSpace.CountablyGenerated 𝓨] (h : IsAlgEnvSeq O A Y alg (Environment.bandit κ) P) (h' : IsAlgEnvSeq O' A' Y' alg (Environment.bandit κ') P') (M : ℕ) : klDiv (P.map (history O A Y M)) (P'.map (history O' A' Y' M)) = ∑ t ∈ range M, ∫⁻ ω, klDiv (κ (A t ω)) (κ' (A t ω)) ∂P := by - rw [h.klDiv_map_history_compProd h'] + rw [h.klDiv_map_history_compProd_bandit h'] refine sum_congr rfl fun t _ ↦ ?_ rw [klDiv_compProd_right_eq_lintegral, lintegral_map (measurable_klDiv_kernel κ κ') (h.measurable_action t)] -/-- Chain rule for trajectories of a single algorithm versus two stationary environments. -/ -lemma IsAlgEnvSeq.klDiv_map_trajectory_compProd (h : IsAlgEnvSeq O A Y alg (Environment.bandit κ) P) +/-- **Divergence decomposition** for trajectories of a single algorithm against two stationary +bandit environments. -/ +lemma IsAlgEnvSeq.klDiv_map_trajectory_compProd_bandit + (h : IsAlgEnvSeq O A Y alg (Environment.bandit κ) P) (h' : IsAlgEnvSeq O' A' Y' alg (Environment.bandit κ') P') : klDiv (P.map (trajectory O A Y)) (P'.map (trajectory O' A' Y')) = ∑' t : ℕ, klDiv (P.map (A t) ⊗ₘ κ) (P.map (A t) ⊗ₘ κ') := by rw [klDiv_map_trajectory_eq_iSup h.measurable_obs h.measurable_action h.measurable_feedback h'.measurable_obs h'.measurable_action h'.measurable_feedback, ENNReal.tsum_eq_iSup_nat] - exact iSup_congr fun n ↦ h.klDiv_map_history_compProd h' n + exact iSup_congr fun n ↦ h.klDiv_map_history_compProd_bandit h' n -/-- Chain rule for trajectories of a single algorithm versus two stationary environments. -/ -lemma IsAlgEnvSeq.klDiv_map_trajectory [MeasurableSpace.CountablyGenerated 𝓨] +/-- **Divergence decomposition** for trajectories of a single algorithm against two stationary +bandit environments. -/ +lemma IsAlgEnvSeq.klDiv_map_trajectory_bandit [MeasurableSpace.CountablyGenerated 𝓨] (h : IsAlgEnvSeq O A Y alg (Environment.bandit κ) P) (h' : IsAlgEnvSeq O' A' Y' alg (Environment.bandit κ') P') : klDiv (P.map (trajectory O A Y)) (P'.map (trajectory O' A' Y')) = ∑' t : ℕ, ∫⁻ ω, klDiv (κ (A t ω)) (κ' (A t ω)) ∂P := by - rw [h.klDiv_map_trajectory_compProd h'] + rw [h.klDiv_map_trajectory_compProd_bandit h'] refine tsum_congr fun t ↦ ?_ rw [klDiv_compProd_right_eq_lintegral, lintegral_map (measurable_klDiv_kernel κ κ') (h.measurable_action t)] -end StationaryEnv +end Bandit end Learning diff --git a/LeanMachineLearning/SequentialLearning/EvaluationEnv.lean b/LeanMachineLearning/SequentialLearning/EvaluationEnv.lean index d60e522a..1218319c 100644 --- a/LeanMachineLearning/SequentialLearning/EvaluationEnv.lean +++ b/LeanMachineLearning/SequentialLearning/EvaluationEnv.lean @@ -7,7 +7,6 @@ module public import LeanMachineLearning.SequentialLearning.Deterministic public import LeanMachineLearning.SequentialLearning.StationaryEnv -public import LeanMachineLearning.ForMathlib.Probability.Independence.CondDistrib /-! # Function evaluation environments @@ -18,10 +17,12 @@ to change at every time step, while the second one uses a fixed function at ever ## Main definitions -* `Environment.evalSeq g hg`: A stationary environment where the feedback at time `n` is given by a - deterministic kernel that evaluates the measurable function `g n` at the chosen action. -* `Environment.eval f hf`: A stationary environment where the feedback is given by a deterministic - kernel that evaluates a fixed measurable function `f` at the chosen action. +* `Environment.evalSeq g hg`: an oblivious environment without observations where the feedback at + time `n` is given by a deterministic kernel that evaluates the measurable function `g n` at the + chosen action. +* `Environment.eval f hf`: a stationary environment without observations where the feedback is + given by a deterministic kernel that evaluates a fixed measurable function `f` at the chosen + action. They both satisfy the typeclasses `Environment.IsOblivious` and `Environment.HasDeterministicFeedback`, and `Environment.eval f hf` is also @@ -29,9 +30,9 @@ They both satisfy the typeclasses `Environment.IsOblivious` and ## Main statements -* `forall_feedback_evalSeq_ae_eq_eval_action`: For almost all `ω`, the feedback at time `n` is +* `IsAlgEnvSeq.feedback_ae_all_eq_evalSeq`: For almost all `ω`, the feedback at time `n` is equal to `g n` evaluated at the action taken at time `n`. -* `forall_feedback_eval_ae_eq_eval_action`: For almost all `ω`, the feedback at time `n` is equal +* `IsAlgEnvSeq.feedback_ae_all_eq_eval`: For almost all `ω`, the feedback at time `n` is equal to `f` evaluated at the action taken at time `n`. -/ @@ -46,9 +47,10 @@ variable {𝓐 𝓨 : Type*} {m𝓐 : MeasurableSpace 𝓐} {m𝓨 : MeasurableS {g : ℕ → 𝓐 → 𝓨} {hg : ∀ n, Measurable (g n)} {f : 𝓐 → 𝓨} {hf : Measurable f} -/-- The evaluation environment where the feedback is given by evaluating a fixed measurable function -`f` at the chosen action. -/ -noncomputable def Environment.evalSeq (g : ℕ → 𝓐 → 𝓨) (hg : ∀ n, Measurable (g n)) := +/-- The evaluation environment where the feedback at time `n` is given by evaluating the measurable +function `g n` at the chosen action. -/ +noncomputable def Environment.evalSeq (g : ℕ → 𝓐 → 𝓨) (hg : ∀ n, Measurable (g n)) : + Environment Unit 𝓐 𝓨 := Environment.banditSeq (fun n ↦ Kernel.deterministic (g n) (hg n)) instance : (Environment.evalSeq g hg).IsOblivious := @@ -57,6 +59,15 @@ instance : (Environment.evalSeq g hg).IsOblivious := instance : (Environment.evalSeq g hg).HasDeterministicFeedback where exists_f n := ⟨fun p ↦ g n p.2, by fun_prop, rfl⟩ +@[simp] +lemma obs_evalSeq (n : ℕ) : + (Environment.evalSeq g hg).obs n = Kernel.const _ (Measure.dirac ()) := rfl + +@[simp] +lemma feedback_evalSeq (n : ℕ) : + (Environment.evalSeq g hg).feedback n + = Kernel.deterministic (fun p ↦ g n p.2) (by fun_prop) := rfl + @[simp] lemma feedbackCondObsAction_evalSeq (n : ℕ) : (Environment.evalSeq g hg).feedbackCondObsAction n @@ -76,37 +87,34 @@ lemma feedbackFunZero_evalSeq [MeasurableSpace.SeparatesPoints 𝓨] : unfold Environment.feedbackFunZero rw [feedbackFun_evalSeq] -section OnlineEvalEnv +section EvalSeq variable {Ω : Type*} {mΩ : MeasurableSpace Ω} {alg : Algorithm Unit 𝓐 𝓨} - {g : ℕ → 𝓐 → 𝓨} {hg : ∀ n, Measurable (g n)} - {P : Measure Ω} [IsProbabilityMeasure P] + {P : Measure Ω} [SFinite P] {O : ℕ → Ω → Unit} {A : ℕ → Ω → 𝓐} {Y : ℕ → Ω → 𝓨} -lemma hasCondDistrib_feedback_evalSeq +lemma IsAlgEnvSeq.hasCondDistrib_feedback_evalSeq (h : IsAlgEnvSeq O A Y alg (Environment.evalSeq g hg) P) (n : ℕ) : HasCondDistrib (Y n) (A n) (Kernel.deterministic (g n) (hg n)) P := h.hasCondDistrib_feedback_banditSeq n -lemma feedback_evalSeq_ae_eq_eval_action [StandardBorelSpace 𝓨] [Nonempty 𝓨] +lemma IsAlgEnvSeq.feedback_ae_eq_evalSeq [MeasurableEq 𝓨] (h : IsAlgEnvSeq O A Y alg (Environment.evalSeq g hg) P) (n : ℕ) : Y n =ᵐ[P] g n ∘ A n := - ae_eq_of_condDistrib_eq_deterministic (hg n) (h.measurable_action n).aemeasurable - (h.measurable_feedback n).aemeasurable - (hasCondDistrib_feedback_evalSeq h n).condDistrib_eq + (h.hasCondDistrib_feedback_evalSeq n).ae_eq_of_deterministic -lemma forall_feedback_evalSeq_ae_eq_eval_action [StandardBorelSpace 𝓨] [Nonempty 𝓨] +lemma IsAlgEnvSeq.feedback_ae_all_eq_evalSeq [MeasurableEq 𝓨] (h : IsAlgEnvSeq O A Y alg (Environment.evalSeq g hg) P) : ∀ᵐ ω ∂P, ∀ n, Y n ω = g n (A n ω) := by rw [ae_all_iff] intro n - exact feedback_evalSeq_ae_eq_eval_action h n + exact h.feedback_ae_eq_evalSeq n -end OnlineEvalEnv +end EvalSeq /-- The evaluation environment where the feedback is given by evaluating a fixed measurable function `f` at the chosen action. -/ -noncomputable def Environment.eval (f : 𝓐 → 𝓨) (hf : Measurable f) := +noncomputable def Environment.eval (f : 𝓐 → 𝓨) (hf : Measurable f) : Environment Unit 𝓐 𝓨 := Environment.evalSeq (fun _ ↦ f) (fun _ ↦ hf) instance : (Environment.eval f hf).IsStationary where @@ -119,6 +127,13 @@ instance : (Environment.eval f hf).IsOblivious := by unfold Environment.eval; in instance : (Environment.eval f hf).HasDeterministicFeedback := by unfold Environment.eval; infer_instance +@[simp] +lemma obs_eval (n : ℕ) : (Environment.eval f hf).obs n = Kernel.const _ (Measure.dirac ()) := rfl + +@[simp] +lemma feedback_eval (n : ℕ) : + (Environment.eval f hf).feedback n = Kernel.deterministic (fun p ↦ f p.2) (by fun_prop) := rfl + @[simp] lemma feedbackCondObsAction_eval (n : ℕ) : (Environment.eval f hf).feedbackCondObsAction n @@ -133,32 +148,32 @@ lemma feedbackFunZero_eval [MeasurableSpace.SeparatesPoints 𝓨] : lemma feedbackFun_eval [MeasurableSpace.SeparatesPoints 𝓨] (n : ℕ) : (Environment.eval f hf).feedbackFun n = fun p ↦ f p.2 := by simp [Environment.eval] -section EvalEnv +section Eval variable {Ω : Type*} {mΩ : MeasurableSpace Ω} {alg : Algorithm Unit 𝓐 𝓨} - {f : 𝓐 → 𝓨} {hf : Measurable f} - {P : Measure Ω} [IsProbabilityMeasure P] + {P : Measure Ω} [SFinite P] {O : ℕ → Ω → Unit} {A : ℕ → Ω → 𝓐} {Y : ℕ → Ω → 𝓨} -lemma hasCondDistrib_feedback_eval (h : IsAlgEnvSeq O A Y alg (Environment.eval f hf) P) (n : ℕ) : +lemma IsAlgEnvSeq.hasCondDistrib_feedback_eval (h : IsAlgEnvSeq O A Y alg (Environment.eval f hf) P) + (n : ℕ) : HasCondDistrib (Y n) (A n) (Kernel.deterministic f hf) P := h.hasCondDistrib_feedback_banditSeq n -lemma feedback_eval_ae_eq_eval_action [StandardBorelSpace 𝓨] [Nonempty 𝓨] - (h : IsAlgEnvSeq O A Y alg (Environment.eval f hf) P) (n : ℕ) : - Y n =ᵐ[P] f ∘ A n := feedback_evalSeq_ae_eq_eval_action h n +lemma IsAlgEnvSeq.feedback_ae_eq_eval [MeasurableEq 𝓨] + (h : IsAlgEnvSeq O A Y alg (Environment.eval f hf) P) (n : ℕ) : + Y n =ᵐ[P] f ∘ A n := h.feedback_ae_eq_evalSeq n -lemma forall_feedback_eval_ae_eq_eval_action [StandardBorelSpace 𝓨] [Nonempty 𝓨] +lemma IsAlgEnvSeq.feedback_ae_all_eq_eval [MeasurableEq 𝓨] (h : IsAlgEnvSeq O A Y alg (Environment.eval f hf) P) : - ∀ᵐ ω ∂P, ∀ n, Y n ω = f (A n ω) := forall_feedback_evalSeq_ae_eq_eval_action h + ∀ᵐ ω ∂P, ∀ n, Y n ω = f (A n ω) := h.feedback_ae_all_eq_evalSeq open Finset in -lemma feedback_eval_ae_eq_eval_action_comp {β : Type*} [StandardBorelSpace 𝓨] [Nonempty 𝓨] +lemma IsAlgEnvSeq.comp_feedback_ae_eq_eval {β : Type*} [MeasurableEq 𝓨] (h : IsAlgEnvSeq O A Y alg (Environment.eval f hf) P) {n : ℕ} (g : (Iic n → 𝓨) → β) : ∀ᵐ ω ∂P, g (fun i ↦ Y i ω) = g (fun i ↦ f (A i ω)) := by - filter_upwards [forall_feedback_eval_ae_eq_eval_action h] with ω hω + filter_upwards [h.feedback_ae_all_eq_eval] with ω hω simp_rw [hω] -end EvalEnv +end Eval end Learning diff --git a/LeanMachineLearning/SequentialLearning/FeedbackMartingale.lean b/LeanMachineLearning/SequentialLearning/FeedbackMartingale.lean index 28e3be86..bc2ea179 100644 --- a/LeanMachineLearning/SequentialLearning/FeedbackMartingale.lean +++ b/LeanMachineLearning/SequentialLearning/FeedbackMartingale.lean @@ -11,6 +11,22 @@ public import LeanMachineLearning.SequentialLearning.Means /-! # Martingale decomposition of the sum of rewards +The sum of the rewards obtained when choosing action `k`, `sumRewards A Y k`, is the sum of a +martingale part `noiseSum env O A Y k` and of a predictable part `meanSum env O A Y k`, for the +filtration `IsAlgEnvSeq.filtrationAction` generated by the history, the observation and the action. + +## Main definitions + +* `noiseSum env O A Y k n`: the sum over the times `m < n` at which action `k` is chosen of the + differences between the reward and its conditional mean `env.means O A Y k m`. +* `meanSum env O A Y k n`: the sum over the times `m < n` at which action `k` is chosen of the + conditional means of the rewards. + +## Main statements + +* `noiseSum_add_meanSum`: `noiseSum env O A Y k n + meanSum env O A Y k n = sumRewards A Y k n`. +* `IsAlgEnvSeq.martingale_noiseSum`: `noiseSum env O A Y k` is a martingale. +* `IsAlgEnvSeq.isStronglyPredictable_meanSum`: `meanSum env O A Y k` is predictable. -/ @[expose] public section @@ -24,7 +40,7 @@ namespace Learning variable {Ω 𝓞 𝓐 𝓨 : Type*} {mΩ : MeasurableSpace Ω} {m𝓞 : MeasurableSpace 𝓞} {m𝓐 : MeasurableSpace 𝓐} {m𝓨 : MeasurableSpace 𝓨} [NormedAddCommGroup 𝓨] [NormedSpace ℝ 𝓨] - {P : Measure Ω} [IsFiniteMeasure P] + {P : Measure Ω} {O : ℕ → Ω → 𝓞} {A : ℕ → Ω → 𝓐} {Y : ℕ → Ω → 𝓨} {alg : Algorithm 𝓞 𝓐 𝓨} {env : Environment 𝓞 𝓐 𝓨} @@ -59,87 +75,86 @@ lemma noiseSum_add_meanSum [DecidableEq 𝓐] (k : 𝓐) (n : ℕ) (ω : Ω) : by_cases h : A m ω = k <;> simp [h] @[simp] -lemma noiseSum_zero (k : 𝓐) : noiseSum env O A Y k 0 = fun _ ↦ 0 := by unfold noiseSum; simp +lemma noiseSum_zero (k : 𝓐) : noiseSum env O A Y k 0 = 0 := by ext; simp [noiseSum] @[simp] -lemma meanSum_zero (k : 𝓐) : meanSum env O A Y k 0 = fun _ ↦ 0 := by unfold meanSum; simp +lemma meanSum_zero (k : 𝓐) : meanSum env O A Y k 0 = 0 := by ext; simp [meanSum] -lemma noiseSum_succ (k : 𝓐) (n : ℕ) : +lemma noiseSum_add_one (k : 𝓐) (n : ℕ) : noiseSum env O A Y k (n + 1) = noiseSum env O A Y k n + {ω | A n ω = k}.indicator (fun ω ↦ Y n ω - env.means O A Y (A n ω) n ω) := by ext ω simp [noiseSum, Finset.sum_range_succ] -lemma noiseSum_succ_sub (k : 𝓐) (n : ℕ) (ω : Ω) : +lemma noiseSum_add_one_sub (k : 𝓐) (n : ℕ) (ω : Ω) : noiseSum env O A Y k (n + 1) ω - noiseSum env O A Y k n ω = {ω | A n ω = k}.indicator (fun ω ↦ Y n ω - env.means O A Y (A n ω) n ω) ω := by - simp [noiseSum_succ] + simp [noiseSum_add_one] -lemma meanSum_succ (k : 𝓐) (n : ℕ) : +lemma meanSum_add_one (k : 𝓐) (n : ℕ) : meanSum env O A Y k (n + 1) = meanSum env O A Y k n + {ω | A n ω = k}.indicator (fun ω ↦ env.means O A Y (A n ω) n ω) := by ext ω simp [meanSum, Finset.sum_range_succ] -lemma meanSum_succ_sub (k : 𝓐) (n : ℕ) (ω : Ω) : +lemma meanSum_add_one_sub (k : 𝓐) (n : ℕ) (ω : Ω) : meanSum env O A Y k (n + 1) ω - meanSum env O A Y k n ω = {ω | A n ω = k}.indicator (fun ω ↦ env.means O A Y (A n ω) n ω) ω := by - simp [meanSum_succ] + simp [meanSum_add_one] variable [MeasurableSingletonClass 𝓐] [SecondCountableTopology 𝓨] @[fun_prop] -lemma IsAlgEnvSeq.integrable_noiseSum_increment [OpensMeasurableSpace 𝓨] +lemma IsAlgEnvSeq.integrable_noiseSum_increment [SFinite P] [OpensMeasurableSpace 𝓨] {m : ℕ} (h : IsAlgEnvSeq O A Y alg env P) (hint : Integrable (Y m) P) (k : 𝓐) : Integrable (fun ω ↦ {ω | A m ω = k}.indicator - (fun ω ↦ Y m ω - env.means O A Y (A m ω) m ω) ω) P := by - exact (hint.sub (h.integrable_means_action hint)).indicator + (fun ω ↦ Y m ω - env.means O A Y (A m ω) m ω) ω) P := + (hint.sub (h.integrable_means_action hint)).indicator (h.measurable_action _ (measurableSet_singleton k)) @[fun_prop] -lemma IsAlgEnvSeq.integrable_meanSum_increment [OpensMeasurableSpace 𝓨] +lemma IsAlgEnvSeq.integrable_meanSum_increment [SFinite P] [OpensMeasurableSpace 𝓨] {m : ℕ} (h : IsAlgEnvSeq O A Y alg env P) (hint : Integrable (Y m) P) (k : 𝓐) : - Integrable (fun ω ↦ {ω | A m ω = k}.indicator (fun ω ↦ env.means O A Y (A m ω) m ω) ω) P := by - exact (h.integrable_means_action hint).indicator - (h.measurable_action _ (measurableSet_singleton k)) + Integrable (fun ω ↦ {ω | A m ω = k}.indicator (fun ω ↦ env.means O A Y (A m ω) m ω) ω) P := + (h.integrable_means_action hint).indicator (h.measurable_action _ (measurableSet_singleton k)) @[fun_prop] -lemma IsAlgEnvSeq.integrable_noiseSum [OpensMeasurableSpace 𝓨] +lemma IsAlgEnvSeq.integrable_noiseSum [SFinite P] [OpensMeasurableSpace 𝓨] (h : IsAlgEnvSeq O A Y alg env P) (hint : ∀ n, Integrable (Y n) P) (k : 𝓐) (n : ℕ) : Integrable (noiseSum env O A Y k n) P := integrable_finsetSum _ fun m _ ↦ h.integrable_noiseSum_increment (hint m) k @[fun_prop] -lemma IsAlgEnvSeq.integrable_meanSum [OpensMeasurableSpace 𝓨] +lemma IsAlgEnvSeq.integrable_meanSum [SFinite P] [OpensMeasurableSpace 𝓨] (h : IsAlgEnvSeq O A Y alg env P) (hint : ∀ n, Integrable (Y n) P) (k : 𝓐) (n : ℕ) : Integrable (meanSum env O A Y k n) P := integrable_finsetSum _ fun m _ ↦ h.integrable_meanSum_increment (hint m) k -lemma IsAlgEnvSeq.memLp_noiseSum_increment [BorelSpace 𝓨] - {m : ℕ} (k : 𝓐) (h : IsAlgEnvSeq O A Y alg env P) {p : ℝ≥0∞} (hp1 : 1 ≤ p) (hp_top : p ≠ ∞) - (hY : MemLp (Y m) p P) : +lemma IsAlgEnvSeq.memLp_noiseSum_increment [SFinite P] [BorelSpace 𝓨] + {m : ℕ} (h : IsAlgEnvSeq O A Y alg env P) {p : ℝ≥0∞} (hp1 : 1 ≤ p) (hp_top : p ≠ ∞) + (hY : MemLp (Y m) p P) (k : 𝓐) : MemLp ({ω | A m ω = k}.indicator (fun ω ↦ Y m ω - env.means O A Y (A m ω) m ω)) p P := by refine (hY.sub ?_).indicator (h.measurable_action _ (measurableSet_singleton k)).nullMeasurableSet exact h.memLp_means_action hp1 hp_top hY -lemma IsAlgEnvSeq.memLp_meanSum_increment [BorelSpace 𝓨] - {m : ℕ} (k : 𝓐) (h : IsAlgEnvSeq O A Y alg env P) {p : ℝ≥0∞} (hp1 : 1 ≤ p) (hp_top : p ≠ ∞) - (hY : MemLp (Y m) p P) : - MemLp ({ω | A m ω = k}.indicator (fun ω ↦ env.means O A Y (A m ω) m ω)) p P := by - exact (h.memLp_means_action hp1 hp_top hY).indicator +lemma IsAlgEnvSeq.memLp_meanSum_increment [SFinite P] [BorelSpace 𝓨] + {m : ℕ} (h : IsAlgEnvSeq O A Y alg env P) {p : ℝ≥0∞} (hp1 : 1 ≤ p) (hp_top : p ≠ ∞) + (hY : MemLp (Y m) p P) (k : 𝓐) : + MemLp ({ω | A m ω = k}.indicator (fun ω ↦ env.means O A Y (A m ω) m ω)) p P := + (h.memLp_means_action hp1 hp_top hY).indicator (h.measurable_action _ (measurableSet_singleton k)).nullMeasurableSet -lemma IsAlgEnvSeq.memLp_noiseSum [BorelSpace 𝓨] +lemma IsAlgEnvSeq.memLp_noiseSum [SFinite P] [BorelSpace 𝓨] (h : IsAlgEnvSeq O A Y alg env P) {p : ℝ≥0∞} (hp1 : 1 ≤ p) (hp_top : p ≠ ∞) (hY : ∀ n, MemLp (Y n) p P) (k : 𝓐) (n : ℕ) : MemLp (noiseSum env O A Y k n) p P := - memLp_finsetSum _ fun m _ ↦ memLp_noiseSum_increment k h hp1 hp_top (hY m) + memLp_finsetSum _ fun m _ ↦ h.memLp_noiseSum_increment hp1 hp_top (hY m) k -lemma IsAlgEnvSeq.memLp_meanSum [BorelSpace 𝓨] +lemma IsAlgEnvSeq.memLp_meanSum [SFinite P] [BorelSpace 𝓨] (h : IsAlgEnvSeq O A Y alg env P) {p : ℝ≥0∞} (hp1 : 1 ≤ p) (hp_top : p ≠ ∞) (hY : ∀ n, MemLp (Y n) p P) (k : 𝓐) (n : ℕ) : MemLp (meanSum env O A Y k n) p P := - memLp_finsetSum _ fun m _ ↦ memLp_meanSum_increment k h hp1 hp_top (hY m) + memLp_finsetSum _ fun m _ ↦ h.memLp_meanSum_increment hp1 hp_top (hY m) k section Martingale @@ -170,7 +185,7 @@ lemma IsAlgEnvSeq.isStronglyPredictable_meanSum (h : IsAlgEnvSeq O A Y alg env P refine StronglyMeasurable.indicator ?_ (hAm (measurableSet_singleton k)) exact (h.stronglyAdapted_means_filtrationAction m).mono (h.filtrationAction.mono (by grind)) -lemma IsAlgEnvSeq.condExp_noiseSum_increment [CompleteSpace 𝓨] +lemma IsAlgEnvSeq.condExp_noiseSum_increment [IsFiniteMeasure P] [CompleteSpace 𝓨] (h : IsAlgEnvSeq O A Y alg env P) (k : 𝓐) (i : ℕ) (hint : Integrable (Y i) P) : P[{ω | A i ω = k}.indicator (fun ω ↦ Y i ω - env.means O A Y (A i ω) i ω) | h.filtrationAction i] =ᵐ[P] 0 := by @@ -180,13 +195,12 @@ lemma IsAlgEnvSeq.condExp_noiseSum_increment [CompleteSpace 𝓨] = {ω | A i ω = k}.indicator (fun ω ↦ Y i ω - env.means O A Y (A i ω) i ω) := by ext ω by_cases hω : A i ω = k <;> simp [c, g, actionIndicator, hω] - have hAG : Measurable[h.filtrationAction i] (A i) := h.adapted_action_filtrationAction i have hcG : StronglyMeasurable[h.filtrationAction i] c := (h.adapted_actionIndicator_filtrationAction k i).stronglyMeasurable have hgint : Integrable g P := hint.sub (h.integrable_means_action hint) have hcint : Integrable (c • g) P := by rw [h_smul] - exact integrable_noiseSum_increment h hint k + exact h.integrable_noiseSum_increment hint k have hcondg : P[g | h.filtrationAction i] =ᵐ[P] 0 := by refine (condExp_sub hint (h.integrable_means_action hint) _).trans ?_ have h1 := h.condExp_feedback i hint @@ -203,19 +217,19 @@ lemma IsAlgEnvSeq.condExp_noiseSum_increment [CompleteSpace 𝓨] · simp · simp [c, actionIndicator, hak] -lemma IsAlgEnvSeq.martingale_noiseSum [CompleteSpace 𝓨] +lemma IsAlgEnvSeq.martingale_noiseSum [IsFiniteMeasure P] [CompleteSpace 𝓨] (h : IsAlgEnvSeq O A Y alg env P) (hint : ∀ n, Integrable (Y n) P) (k : 𝓐) : Martingale (noiseSum env O A Y k) h.filtrationAction P := by - have hInt : ∀ n, Integrable (noiseSum env O A Y k n) P := h.integrable_noiseSum (hint) k + have hInt : ∀ n, Integrable (noiseSum env O A Y k n) P := h.integrable_noiseSum hint k refine martingale_nat (h.stronglyAdapted_noiseSum k) hInt fun i ↦ ?_ - rw [noiseSum_succ] + rw [noiseSum_add_one] symm have hadd := condExp_add (hInt i) - (integrable_noiseSum_increment h (hint i) k) (h.filtrationAction i) + (h.integrable_noiseSum_increment (hint i) k) (h.filtrationAction i) have hself : P[noiseSum env O A Y k i | h.filtrationAction i] = noiseSum env O A Y k i := condExp_of_stronglyMeasurable (h.filtrationAction.le i) (h.stronglyAdapted_noiseSum k i) (hInt i) - have hincr := condExp_noiseSum_increment h k i (hint i) + have hincr := h.condExp_noiseSum_increment k i (hint i) filter_upwards [hadd, hincr] with ω ha hin rw [ha, Pi.add_apply, congrFun hself ω] simp only [add_eq_left] diff --git a/LeanMachineLearning/SequentialLearning/FiniteActions.lean b/LeanMachineLearning/SequentialLearning/FiniteActions.lean index 22a4f2bd..d385b2f8 100644 --- a/LeanMachineLearning/SequentialLearning/FiniteActions.lean +++ b/LeanMachineLearning/SequentialLearning/FiniteActions.lean @@ -9,17 +9,33 @@ public import LeanMachineLearning.SequentialLearning.Algorithm public import Mathlib.Order.CompletePartialOrder public import Mathlib.Probability.Martingale.BorelCantelli +import LeanMachineLearning.ForMathlib.Probability.Process.HittingTime + /-! -# Bookkeeping definitions for finite action space sequential learning problems +# Bookkeeping definitions for sequential learning problems with discrete actions + +We define the number of times each action was chosen, the time at which an action was chosen for +the `m`-th time and the reward obtained at that time. +The sums of rewards and empirical means are in `SequentialLearning/SumRewards.lean`. + +For each definition that takes as arguments a time `t : ℕ`, an outcome `ω : Ω`, and possibly +other parameters, we put the time and the outcome at the end in this order, so that the definition +can be seen as a stochastic process indexed by time `t`. + +## Main definitions -If the number of actions is finite, it makes sense to define the number of times each action was -chosen, the time at which an action was chosen for the nth time, the value of the reward at that -time, the sum of rewards obtained for each action, the empirical mean reward for each action, etc. +* `pullCount A a t ω`: number of times action `a` was chosen before time `t`. `pullCount'` is the + same quantity, as a function of the history. +* `stepsUntil A a m ω`: the time at which action `a` is chosen for the `m`-th time, or `⊤` if it + is never chosen `m` times. +* `rewardByCount A R' a m ω`: the reward obtained when choosing action `a` for the `m`-th time. +* `rewardByCountUntil A R' t ω`: the array of rewards by count, truncated at time `t`. -For each definition that take as arguments a time `t : ℕ`, a history `h : ℕ → 𝓐 × R`, and possibly -other parameters, we put the time and history at the end in this order, so that the definition can -be seen as a stochastic process indexed by time `t` on the measurable space `ℕ → 𝓐 × R`. +## Main statements +* `IsAlgEnvSeq.isStronglyPredictable_pullCount`: `pullCount A a` is predictable. +* `IsAlgEnvSeq.isStoppingTime_stepsUntil`: `stepsUntil A a m` is a stopping time. +* `sum_pullCount`: the pull counts of all actions sum to the time. -/ @[expose] public section @@ -32,7 +48,7 @@ variable {𝓞 𝓐 R Ω : Type*} {m𝓞 : MeasurableSpace 𝓞} {m𝓐 : Measur {mR : MeasurableSpace R} {mΩ : MeasurableSpace Ω} [DecidableEq 𝓐] {alg : Algorithm 𝓞 𝓐 R} {env : Environment 𝓞 𝓐 R} - {P : Measure Ω} [IsProbabilityMeasure P] + {P : Measure Ω} {O : ℕ → Ω → 𝓞} {A : ℕ → Ω → 𝓐} {R' : ℕ → Ω → R} {a : 𝓐} {m n t : ℕ} {ω : Ω} @@ -46,7 +62,7 @@ def pullCount (A : ℕ → Ω → 𝓐) (a : 𝓐) (t : ℕ) (ω : Ω) : ℕ := /-- Number of pulls of arm `a` in the history before time `n`. This is the number of entries in `h` in which the arm is `a`. -/ noncomputable -def pullCount' (n : ℕ) (h : Hist 𝓞 𝓐 R n) (a : 𝓐) := #{s | (h s).action = a} +def pullCount' (n : ℕ) (h : Hist 𝓞 𝓐 R n) (a : 𝓐) : ℕ := #{s | (h s).action = a} @[simp] lemma pullCount_zero (a : 𝓐) : pullCount A a 0 = 0 := by ext; simp [pullCount] @@ -99,6 +115,15 @@ lemma pullCount_eq_comp_history (a : 𝓐) (n : ℕ) : ext ω exact pullCount_eq_pullCount' +/-- `pullCount A a n` is a function of the trajectory. -/ +lemma pullCount_eq_comp_trajectory (a : 𝓐) (n : ℕ) : + pullCount A a n = + (fun p : ℕ → Round 𝓞 𝓐 R ↦ ∑ i ∈ range n, if (p i).action = a then 1 else 0) ∘ + trajectory O A R' := by + ext + simp [pullCount, trajectory] + rfl + lemma pullCount'_mono {n m : ℕ} (hnm : n ≤ m) : pullCount' n (history O A R' n ω) a ≤ pullCount' m (history O A R' m ω) a := by rw [← pullCount_eq_pullCount' (O := O), ← pullCount_eq_pullCount' (O := O)] @@ -193,12 +218,11 @@ lemma measurable_uncurry_pullCount [MeasurableEq 𝓐] lemma measurable_uncurry_pullCount_comp [Countable 𝓐] [MeasurableSingletonClass 𝓐] (hA : ∀ n, Measurable (A n)) {f : Ω → 𝓐} (hf : Measurable f) {g : Ω → ℕ} (hg : Measurable g) : Measurable (fun ω ↦ pullCount A (f ω) (g ω) ω) := by - change Measurable ((fun aω ↦ pullCount A aω.1 (g aω.2) aω.2) ∘ fun ω ↦ (f ω, ω)) - apply Measurable.comp _ (by fun_prop) - refine measurable_from_prod_countable_right fun a ↦ ?_ - change Measurable ((fun tω ↦ pullCount A a tω.1 tω.2) ∘ fun ω ↦ (g ω, ω)) - apply Measurable.comp _ (by fun_prop) - exact measurable_from_prod_countable_right (fun t ↦ measurable_pullCount hA a t) + have h_meas a : Measurable (fun ω ↦ pullCount A a (g ω) ω) := + (measurable_from_prod_countable_right (f := fun p : ℕ × Ω ↦ pullCount A a p.1 p.2) + (measurable_pullCount hA a)).comp (hg.prodMk measurable_id) + exact (measurable_from_prod_countable_right (f := fun p : 𝓐 × Ω ↦ pullCount A p.1 (g p.2) p.2) + h_meas).comp (hf.prodMk measurable_id) @[fun_prop] lemma measurable_pullCount' [MeasurableSingletonClass 𝓐] (n : ℕ) (a : 𝓐) : @@ -219,25 +243,24 @@ lemma measurable_uncurry_pullCount' [MeasurableEq 𝓐] (n : ℕ) : exact measurableSet_eq_fun (by fun_prop) (by fun_prop) fun_prop -lemma adapted_pullCount_add_one [MeasurableSingletonClass 𝓐] +lemma IsAlgEnvSeq.adapted_pullCount_add_one [MeasurableSingletonClass 𝓐] (h : IsAlgEnvSeq O A R' alg env P) (a : 𝓐) : Adapted h.filtration (fun n ↦ pullCount A a (n + 1)) := by intro n - change Measurable[h.filtration n] (pullCount A a (n + 1)) - rw [measurable_iff_comap_le, h.filtration_eq_comap, pullCount_eq_comp_history (O := O) (R' := R'), - ← measurable_iff_comap_le] + beta_reduce + rw [h.filtration_eq_comap, pullCount_eq_comp_history (O := O) (R' := R')] exact measurable_comp_comap _ (measurable_pullCount' (n + 1) a) -lemma stronglyAdapted_pullCount_add_one [MeasurableSingletonClass 𝓐] +lemma IsAlgEnvSeq.stronglyAdapted_pullCount_add_one [MeasurableSingletonClass 𝓐] (h : IsAlgEnvSeq O A R' alg env P) (a : 𝓐) : StronglyAdapted h.filtration (fun n ↦ pullCount A a (n + 1)) := - (adapted_pullCount_add_one h a).stronglyAdapted + (h.adapted_pullCount_add_one a).stronglyAdapted -lemma isStronglyPredictable_pullCount [MeasurableSingletonClass 𝓐] +lemma IsAlgEnvSeq.isStronglyPredictable_pullCount [MeasurableSingletonClass 𝓐] (h : IsAlgEnvSeq O A R' alg env P) (a : 𝓐) : IsStronglyPredictable h.filtration (pullCount A a) := by rw [IsStronglyPredictable.iff_measurable_add_one] - refine ⟨?_, stronglyAdapted_pullCount_add_one h a⟩ + refine ⟨?_, h.stronglyAdapted_pullCount_add_one a⟩ simp only [pullCount_zero] fun_prop @@ -264,7 +287,7 @@ lemma setOf_action_eq_and_pullCount_eq_eq_preimage (n : ℕ) (b : 𝓐) (k : ℕ simp only [Set.mem_ofPred_eq, Set.mem_preimage] rw [pullCount_eq_pullCount' (O := O) (R' := R')] -lemma integrable_pullCount [MeasurableSingletonClass 𝓐] +lemma integrable_pullCount [IsFiniteMeasure P] [MeasurableSingletonClass 𝓐] (hA : ∀ n, Measurable (A n)) (a : 𝓐) (n : ℕ) : Integrable (fun ω ↦ (pullCount A a n ω : ℝ)) P := by refine integrable_of_le_of_le (g₁ := 0) (g₂ := fun _ ↦ n) (by fun_prop) @@ -328,42 +351,6 @@ lemma stepsUntil_eq_dite (a : 𝓐) (m : ℕ) (ω : Ω) ext s simpa using (h' s) -set_option backward.isDefEq.respectTransparency false in -lemma stepsUntil_eq_leastGE (a : 𝓐) (hm : m ≠ 0) : - stepsUntil A a m = leastGE (fun n (ω : Ω) ↦ pullCount A a (n + 1) ω) m := by - classical - ext ω - rw [stepsUntil_eq_dite] - unfold leastGE hittingAfter - simp only [Nat.bot_eq_zero, zero_le, Set.mem_Ici, true_and] - have h_iff : (∃ s, pullCount A a (s + 1) ω = m) ↔ (∃ s, m ≤ pullCount A a (s + 1) ω) := by - refine ⟨fun ⟨s, hs⟩ ↦ ⟨s, hs.ge⟩, fun ⟨s, hs⟩ ↦ ?_⟩ - exact exists_pullCount_eq_of_le hs hm - by_cases h_exists : ∃ s, m ≤ pullCount A a (s + 1) ω - swap; · simp_rw [h_iff]; simp [h_exists] - rw [ite_eq_left h_exists, dite_eq_left] - swap; · rwa [h_iff] - simp only [ENat.some_eq_natCast, Nat.cast_inj] - rw [Nat.find_eq_iff] - constructor - · apply le_antisymm - · by_contra! h_contra - obtain ⟨s, hs⟩ : ∃ s, pullCount A a (s + 1) ω = m := exists_pullCount_eq_of_le h_contra.le hm - rw [← hs] at h_contra - refine h_contra.not_ge ?_ - gcongr - exact csInf_le (by simp) (by simp) - · exact Nat.sInf_mem (s := {j | m ≤ pullCount A a (j + 1) ω}) h_exists - · intro n hn h_contra - refine hn.not_ge ?_ - exact csInf_le (by simp) (by simp [h_contra]) - -lemma stepsUntil_mono (a : 𝓐) (ω : Ω) {n m : ℕ} (hn : n ≠ 0) (hnm : n ≤ m) : - stepsUntil A a n ω ≤ stepsUntil A a m ω := by - rw [stepsUntil_eq_leastGE a hn, stepsUntil_eq_leastGE a (by lia)] - simp_rw [leastGE] - exact hittingAfter_anti (fun n ω ↦ (pullCount A a (n + 1) ω)) 0 (fun x ↦ by grind) ω - lemma stepsUntil_pullCount_le (ω : Ω) (a : 𝓐) (t : ℕ) : stepsUntil A a (pullCount A a (t + 1) ω) ω ≤ t := by rw [stepsUntil] @@ -449,7 +436,7 @@ lemma pullCount_stepsUntil (hm : m ≠ 0) (h_exists : ∃ s, pullCount A a (s + swap; · simpa [stepsUntil_eq_top_iff] grind -lemma pullCount_lt_of_le_stepsUntil (a : 𝓐) {n m : ℕ} (ω : Ω) +lemma pullCount_lt_of_lt_stepsUntil (a : 𝓐) {n m : ℕ} (ω : Ω) (h_exists : ∃ s, pullCount A a (s + 1) ω = m) (hn : n < stepsUntil A a m ω) : pullCount A a (n + 1) ω < m := by classical @@ -490,7 +477,7 @@ lemma stepsUntil_eq_iff {ω : Ω} (n : ℕ) : refine ⟨fun h ↦ ?_, fun h ↦ ?_⟩ · have h_exists : ∃ s, pullCount A a (s + 1) ω = m := exists_pullCount_eq (by simp [h]) refine ⟨pullCount_add_one_eq_of_stepsUntil_eq_coe h, fun k hk ↦ ?_⟩ - exact pullCount_lt_of_le_stepsUntil a ω h_exists (by rw [h]; exact mod_cast hk) + exact pullCount_lt_of_lt_stepsUntil a ω h_exists (by rw [h]; exact mod_cast hk) · classical rw [stepsUntil_eq_dite a m ω, dite_eq_left ⟨n, h.1⟩] simp only [Nat.cast_inj] @@ -526,9 +513,33 @@ lemma stepsUntil_eq_congr {ω' : Ω} (h_eq : ∀ i ≤ n, A i ω = A i ω') : rw [pullCount_congr] grind +lemma stepsUntil_eq_leastGE (a : 𝓐) (hm : m ≠ 0) : + stepsUntil A a m = leastGE (fun n (ω : Ω) ↦ pullCount A a (n + 1) ω) m := by + ext ω + rw [leastGE] + cases h : hittingAfter (fun n ω ↦ pullCount A a (n + 1) ω) (Set.Ici m) ⊥ ω with + | top => + rw [hittingAfter_eq_top_iff] at h + exact stepsUntil_eq_top_iff.2 fun s hs ↦ h s bot_le (by simp [hs]) + | coe n => + rw [hittingAfter_eq_coe_iff] at h + simp only [Set.mem_Ici, Set.mem_Ico, Nat.bot_eq_zero, zero_le, true_and, not_le] at h + -- the count increases by at most one at each step, so it reaches `m` exactly at time `n` + refine (stepsUntil_eq_iff n).2 ⟨le_antisymm ?_ h.1, h.2⟩ + rw [pullCount_add_one] + cases n with + | zero => rw [pullCount_zero_apply]; split_ifs <;> omega + | succ n => have := h.2 n (by omega); split_ifs <;> omega + +lemma stepsUntil_mono (a : 𝓐) (ω : Ω) {n m : ℕ} (hn : n ≠ 0) (hnm : n ≤ m) : + stepsUntil A a n ω ≤ stepsUntil A a m ω := by + rw [stepsUntil_eq_leastGE a hn, stepsUntil_eq_leastGE a (by lia)] + simp_rw [leastGE] + exact hittingAfter_anti (fun n ω ↦ (pullCount A a (n + 1) ω)) 0 (fun x ↦ by grind) ω + section Measurability -lemma isStoppingTime_stepsUntil [MeasurableSingletonClass 𝓐] +lemma IsAlgEnvSeq.isStoppingTime_stepsUntil [MeasurableSingletonClass 𝓐] (h : IsAlgEnvSeq O A R' alg env P) (a : 𝓐) (hm : m ≠ 0) : IsStoppingTime h.filtration (stepsUntil A a m) := by rw [stepsUntil_eq_leastGE _ hm] @@ -536,41 +547,26 @@ lemma isStoppingTime_stepsUntil [MeasurableSingletonClass 𝓐] suffices StronglyMeasurable[h.filtration n] (pullCount A a (n + 1)) by fun_prop refine Measurable.stronglyMeasurable ?_ - exact adapted_pullCount_add_one h a n + exact h.adapted_pullCount_add_one a n --- todo: get this from the stopping time property? @[fun_prop] lemma measurable_stepsUntil [MeasurableSingletonClass 𝓐] (hA : ∀ n, Measurable (A n)) (a : 𝓐) (m : ℕ) : Measurable (stepsUntil A a m) := by - classical - have h_union : {h' : Ω | ∃ s, pullCount A a (s + 1) h' = m} - = ⋃ s : ℕ, {h' | pullCount A a (s + 1) h' = m} := by ext; simp - have h_meas_set : MeasurableSet {h' : Ω | ∃ s, pullCount A a (s + 1) h' = m} := by - rw [h_union] - refine MeasurableSet.iUnion fun s ↦ (measurableSet_singleton _).preimage ?_ - exact measurable_pullCount hA a (s + 1) - suffices Measurable fun k ↦ if h : k ∈ {k' | ∃ s, pullCount A a (s + 1) k' = m} - then (Nat.find h : ℕ∞) else ⊤ by - convert this with ω - rw [stepsUntil_eq_dite a m ω] - rfl - refine Measurable.dite (s := {k' : Ω | ∃ s, pullCount A a (s + 1) k' = m}) - (f := fun x ↦ (Nat.find x.2 : ℕ∞)) (g := fun _ ↦ ⊤) ?_ (by fun_prop) h_meas_set - refine Measurable.coe_nat_enat ?_ - refine measurable_find _ fun k ↦ ?_ - suffices MeasurableSet {x : Ω | pullCount A a (k + 1) x = m} by - have : Subtype.val '' {x : {k' : Ω | - ∃ s, pullCount A a (s + 1) k' = m} | pullCount A a (k + 1) (x : Ω) = m} - = {x : Ω | pullCount A a (k + 1) x = m} := by - ext x - simp only [Set.mem_ofPred_eq, Set.coe_ofPred, Set.mem_image, Subtype.exists, exists_and_left, - exists_prop, exists_eq_right_right, and_iff_left_iff_imp] - exact fun h ↦ ⟨_, h⟩ - refine (MeasurableEmbedding.subtype_coe h_meas_set).measurableSet_image.mp ?_ + refine measurable_to_countable' fun x ↦ ?_ + induction x using ENat.recTopCoe with + | top => + have : stepsUntil A a m ⁻¹' {⊤} = ⋂ s, {ω | pullCount A a (s + 1) ω = m}ᶜ := by + ext; simp [stepsUntil_eq_top_iff] rw [this] - exact (measurableSet_singleton _).preimage (by fun_prop) - exact (measurableSet_singleton _).preimage (by fun_prop) + exact .iInter fun s ↦ (measurableSet_eq_fun (by fun_prop) (by fun_prop)).compl + | coe n => + have : stepsUntil A a m ⁻¹' {(n : ℕ∞)} = {ω | pullCount A a (n + 1) ω = m} ∩ + ⋂ k < n, {ω | pullCount A a (k + 1) ω < m} := by + ext; simp [stepsUntil_eq_iff] + rw [this] + exact (measurableSet_eq_fun (by fun_prop) (by fun_prop)).inter + (.iInter fun k ↦ .iInter fun _ ↦ measurableSet_lt (by fun_prop) (by fun_prop)) lemma measurable_stepsUntil' [MeasurableSingletonClass 𝓐] (hA : ∀ n, Measurable (A n)) (a : 𝓐) (m : ℕ) : @@ -615,14 +611,9 @@ lemma measurable_comap_indicator_stepsUntil_eq [MeasurableSingletonClass 𝓐] exact measurable_comp_comap _ (by fun_prop) lemma measurable_indicator_stepsUntil_eq [MeasurableSingletonClass 𝓐] - (h : IsAlgEnvSeq O A R' alg env P) (a : 𝓐) (m n : ℕ) : - Measurable ({ω : Ω | stepsUntil A a m ω = ↑n}.indicator fun _ ↦ 1) := by - refine (measurable_comap_indicator_stepsUntil_eq (m𝓞 := m𝓞) (mR := mR) O R' a m n).mono ?_ le_rfl - refine Measurable.comap_le ?_ - have hO := h.measurable_obs - have hA := h.measurable_action - have hR' := h.measurable_feedback - fun_prop + (hA : ∀ n, Measurable (A n)) (a : 𝓐) (m n : ℕ) : + Measurable ({ω : Ω | stepsUntil A a m ω = ↑n}.indicator fun _ ↦ 1) := + measurable_const.indicator (measurableSet_eq_fun (measurable_stepsUntil hA a m) measurable_const) lemma measurableSet_stepsUntil_eq [MeasurableSingletonClass 𝓐] (O : ℕ → Ω → 𝓞) (R' : ℕ → Ω → R) (a : 𝓐) (m n : ℕ) : @@ -636,7 +627,7 @@ lemma measurableSet_stepsUntil_eq [MeasurableSingletonClass 𝓐] exact measurable_comap_indicator_stepsUntil_eq O R' a m n /-- `stepsUntil a m` is a stopping time with respect to the filtration `filtrationAction`. -/ -lemma isStoppingTime_stepsUntil_filtrationAction [MeasurableSingletonClass 𝓐] +lemma IsAlgEnvSeq.isStoppingTime_stepsUntil_filtrationAction [MeasurableSingletonClass 𝓐] (h : IsAlgEnvSeq O A R' alg env P) (a : 𝓐) (m : ℕ) : IsStoppingTime h.filtrationAction (stepsUntil A a m) := by refine isStoppingTime_of_measurableSet_eq fun n ↦ ?_ @@ -651,7 +642,7 @@ section RewardByCount /-- Reward obtained when pulling action `a` for the `m`-th time. If it is never pulled `m` times, the reward is given by the second component of `ω`, which in -applications will be indepedent with same law. -/ +applications will be independent with the same law. -/ noncomputable def rewardByCount (A : ℕ → Ω → 𝓐) (R' : ℕ → Ω → R) (a : 𝓐) (m : ℕ) (ω : Ω × (ℕ → 𝓐 → R)) : R := match (stepsUntil A a m ω.1) with @@ -717,14 +708,8 @@ lemma measurable_rewardByCount [MeasurableSingletonClass 𝓐] refine Measurable.ite ?_ ?_ ?_ · exact (measurableSet_singleton _).preimage <| measurable_stepsUntil' hA a m · fun_prop - · change Measurable ((fun p : ℕ × Ω ↦ R' p.1 p.2) - ∘ (fun ω : Ω × (ℕ → 𝓐 → R) ↦ ((stepsUntil A a m ω.1).toNat, ω.1))) - have : Measurable fun ω : Ω × (ℕ → 𝓐 → R) ↦ ((stepsUntil A a m ω.1).toNat, ω.1) := - (measurable_stepsUntil' hA a m).toNat.prodMk (by fun_prop) - refine Measurable.comp ?_ this - refine measurable_from_prod_countable_right fun n ↦ ?_ - simp only - fun_prop + · exact (measurable_from_prod_countable_right (f := fun p : ℕ × Ω ↦ R' p.1 p.2) + hR').comp ((measurable_stepsUntil' hA a m).enat_toNat.prodMk (by fun_prop)) /-- Array of rewards by count, truncated at time `t`: the entry `(a, m)` is the reward received at the `(m + 1)`-th pull of action `a` if that pull happened before time `t`, and the entry @@ -852,7 +837,7 @@ lemma measurable_rewardByCountUntil [MeasurableEq 𝓐] end RewardByCount -lemma sum_pullCount_mul [Fintype 𝓐] [Semiring R] (ω : Ω) (f : 𝓐 → R) (t : ℕ) : +lemma sum_pullCount_mul [Fintype 𝓐] [NonAssocSemiring R] (ω : Ω) (f : 𝓐 → R) (t : ℕ) : ∑ a, pullCount A a t ω * f a = ∑ s ∈ range t, f (A s ω) := by unfold pullCount classical @@ -861,11 +846,8 @@ lemma sum_pullCount_mul [Fintype 𝓐] [Semiring R] (ω : Ω) (f : 𝓐 → R) ( simp_rw [sum_mul, one_mul] exact sum_fiberwise' (range t) (A · ω) f --- todo: only in ℝ for now lemma sum_pullCount [Fintype 𝓐] {ω : Ω} : ∑ a, pullCount A a t ω = t := by - suffices ∑ a, pullCount A a t ω * (1 : ℝ) = t by norm_cast at this; simpa - rw [sum_pullCount_mul] - simp + simpa using sum_pullCount_mul (R := ℕ) ω 1 t lemma sum_comp_pullCount [Fintype 𝓐] [AddCommMonoid R] (f : ℕ → R) (t : ℕ) (ω : Ω) : ∑ s ∈ range t, f (pullCount A (A s ω) s ω) = ∑ a, ∑ j ∈ range (pullCount A a t ω), f j := by @@ -880,7 +862,7 @@ lemma sum_comp_pullCount [Fintype 𝓐] [AddCommMonoid R] (f : ℕ → R) (t : · simp [sum_range_succ] · simp -lemma sum_pullCount' [Fintype 𝓐] (n : ℕ) (h : Hist 𝓞 𝓐 ℝ n) : ∑ a, pullCount' n h a = n := by +lemma sum_pullCount' [Fintype 𝓐] (n : ℕ) (h : Hist 𝓞 𝓐 R n) : ∑ a, pullCount' n h a = n := by simp_rw [pullCount'_eq_sum] rw [Finset.sum_comm] have hcol (s : Fin n) : ∑ a, (if (h s).action = a then (1 : ℕ) else 0) = 1 := by diff --git a/LeanMachineLearning/SequentialLearning/IdentificationAlg.lean b/LeanMachineLearning/SequentialLearning/IdentificationAlg.lean index 1962f2df..3073f95e 100644 --- a/LeanMachineLearning/SequentialLearning/IdentificationAlg.lean +++ b/LeanMachineLearning/SequentialLearning/IdentificationAlg.lean @@ -31,13 +31,20 @@ predicate `bad θ` if, for every `θ`, the output in `env θ` is `bad θ` with p ## Main definitions * `IdentAlg 𝓞 𝓐 𝓨 𝓓`: the structure. -* `IdentAlg.stoppingTime A O X Y : Ω → ℕ∞`: the number of rounds played, a hitting time. +* `IdentAlg.stoppingTime A O X Y : Ω → WithTop ℕ`: the number of rounds played, a hitting time. * `IdentAlg.stoppedHist A O X Y : Ω → Σ n, Hist 𝓞 𝓐 𝓨 n`: the history at the stopping time. * `IdentAlg.IsRun A env O X Y out P`: `(O, X, Y, out)` is a run of `A` in `env` on `(Ω, P)`. * `IdentAlg.outputMeasure A env : Measure 𝓓`: the law of the output of `A` in `env`. * `IdentAlg.IsPAC A env bad δ`: for every parameter `θ`, the output of `A` in `env θ` is `bad θ` with probability at most `δ`. +## Main statements + +* `IdentAlg.IsRun.hasLaw_output`: the output of any run of `A` in `env` has law + `A.outputMeasure env`. +* `IdentAlg.IsPAC.measureReal_bad_of_isRun`: for a PAC algorithm, the output of any run is bad with + probability at most `δ`. + Time is `0`-indexed: after `n` rounds the actions `a_0, …, a_{n-1}` have been played. -/ @@ -45,8 +52,6 @@ Time is `0`-indexed: after `n` rounds the actions `a_0, …, a_{n-1}` have been open MeasureTheory ProbabilityTheory -open scoped ENat - namespace Learning variable {𝓞 𝓐 𝓨 𝓓 Ω : Type*} {m𝓞 : MeasurableSpace 𝓞} {m𝓐 : MeasurableSpace 𝓐} @@ -82,7 +87,7 @@ number of rounds played, that is the first `n` such that the history of the firs belongs to the stopping rule `A.stopSet` (`⊤` if there is none). -/ noncomputable def stoppingTime (A : IdentAlg 𝓞 𝓐 𝓨 𝓓) (O : ℕ → Ω → 𝓞) (X : ℕ → Ω → 𝓐) (Y : ℕ → Ω → 𝓨) : - Ω → ℕ∞ := + Ω → WithTop ℕ := hittingAfter (sigmaHistory O X Y) A.stopSet 0 lemma stoppingTime_def : A.stoppingTime O X Y = hittingAfter (sigmaHistory O X Y) A.stopSet 0 := rfl @@ -109,7 +114,7 @@ an algorithm-environment sequence for the sampling rule `A.alg` and `env`, and t conditional law `A.output` given the history at the stopping time. -/ structure IsRun (A : IdentAlg 𝓞 𝓐 𝓨 𝓓) (env : Environment 𝓞 𝓐 𝓨) (O : ℕ → Ω → 𝓞) (X : ℕ → Ω → 𝓐) (Y : ℕ → Ω → 𝓨) (out : Ω → 𝓓) - (P : Measure Ω := by volume_tac) [IsFiniteMeasure P] : Prop where + (P : Measure Ω := by volume_tac) : Prop where /-- The actions and feedbacks are generated by the sampling rule in the environment. -/ isAlgEnvSeq : IsAlgEnvSeq O X Y A.alg env P /-- The output is drawn from the output rule applied to the history at the stopping time. -/ @@ -119,7 +124,7 @@ structure IsRun (A : IdentAlg 𝓞 𝓐 𝓨 𝓓) (env : Environment 𝓞 𝓐 filtration of any algorithm-environment sequence `O`, `X`, `Y`. Most often used with `alg = A.alg`. -/ lemma isStoppingTime_stoppingTime (A : IdentAlg 𝓞 𝓐 𝓨 𝓓) {alg : Algorithm 𝓞 𝓐 𝓨} - [IsFiniteMeasure P] (h : IsAlgEnvSeq O X Y alg env P) : + (h : IsAlgEnvSeq O X Y alg env P) : IsStoppingTime h.filtration (A.stoppingTime O X Y) := h.adapted_sigmaHistory.isStoppingTime_hittingAfter A.measurableSet_stopSet @@ -144,7 +149,7 @@ section IsPAC /-- `A` is *PAC at level `δ`* for the family of environments `env : Θ → Environment 𝓞 𝓐 𝓨` and the predicate `bad : Θ → 𝓓 → Prop` if, for every `θ`, the output of `A` in `env θ` is `bad θ` with probability at most `δ`. -See `IsPAC.measureReal_not_good_of_isRun` for the corresponding statement about any run of `A`. -/ +See `IsPAC.measureReal_bad_of_isRun` for the corresponding statement about any run of `A`. -/ def IsPAC {Θ : Type*} (A : IdentAlg 𝓞 𝓐 𝓨 𝓓) (env : Θ → Environment 𝓞 𝓐 𝓨) (bad : Θ → 𝓓 → Prop) (δ : ℝ) : Prop := ∀ θ, (A.outputMeasure (env θ)).real {d | bad θ d} ≤ δ diff --git a/LeanMachineLearning/SequentialLearning/IonescuTulceaSpace.lean b/LeanMachineLearning/SequentialLearning/IonescuTulceaSpace.lean index 9601a064..46194ecb 100644 --- a/LeanMachineLearning/SequentialLearning/IonescuTulceaSpace.lean +++ b/LeanMachineLearning/SequentialLearning/IonescuTulceaSpace.lean @@ -11,20 +11,32 @@ public import LeanMachineLearning.SequentialLearning.Algorithm # Probability space for algorithm-environment interactions For any algorithm and environment, we construct a probability space on which we can define -a sequence of random variables representing the actions and feedback generated by the interaction -of the algorithm and the environment. +a sequence of random variables representing the observations, actions and feedbacks generated by +the interaction of the algorithm and the environment. The main ingredient of the construction is the Ionescu-Tulcea theorem. +## Main definitions + +* `trajMeasure alg env`: the law of the sequence of rounds generated by the interaction of `alg` + and `env`, a probability measure on `ℕ → Round 𝓞 𝓐 𝓨`. +* `IT.obs`, `IT.action`, `IT.feedback`, `IT.step`, `IT.hist`: the coordinate processes on + `ℕ → Round 𝓞 𝓐 𝓨`. +* `IT.filtration`, `IT.filtrationAction`: filtrations on `ℕ → Round 𝓞 𝓐 𝓨` generated by the rounds + up to time `n`, and by the history before time `n` together with the observation and the action + at time `n`. + ## Main statements +* `IT.isAlgEnvSeq_trajMeasure`: the coordinate processes form an algorithm-environment sequence + under `trajMeasure alg env`. * `isAlgEnvSeq_unique`: the law of the sequence of rounds generated by an algorithm-environment pair is unique: it does not depend on the probability space used. - If `O₁`, `A₁`, `R₁` and `O₂`, `A₂`, `R₂` are two algorithm-environment sequences generated by the + If `O₁`, `A₁`, `Y₁` and `O₂`, `A₂`, `Y₂` are two algorithm-environment sequences generated by the same algorithm-environment pair on probability spaces `(Ω, P)` and `(Ω', P')`, then - `P.map (trajectory O₁ A₁ R₁) = P'.map (trajectory O₂ A₂ R₂)`. + `P.map (trajectory O₁ A₁ Y₁) = P'.map (trajectory O₂ A₂ Y₂)`. Both are equal to + `trajMeasure alg env` (`IsAlgEnvSeq.hasLaw_trajectory`). -/ - @[expose] public section open MeasureTheory ProbabilityTheory Filter Real Finset @@ -140,56 +152,67 @@ section ModelEquivalence variable {Ω Ω' : Type*} {mΩ : MeasurableSpace Ω} {mΩ' : MeasurableSpace Ω'} {alg : Algorithm 𝓞 𝓐 𝓨} {env : Environment 𝓞 𝓐 𝓨} {P : Measure Ω} [IsProbabilityMeasure P] {P' : Measure Ω'} [IsProbabilityMeasure P'] - {O₁ : ℕ → Ω → 𝓞} {A₁ : ℕ → Ω → 𝓐} {R₁ : ℕ → Ω → 𝓨} - {O₂ : ℕ → Ω' → 𝓞} {A₂ : ℕ → Ω' → 𝓐} {R₂ : ℕ → Ω' → 𝓨} {N : ℕ} - -lemma IsAlgEnvSeq.map_trajectory (h : IsAlgEnvSeq O₁ A₁ R₁ alg env P) : - P.map (trajectory O₁ A₁ R₁) = trajMeasure alg env := - (Kernel.hasLaw_trajMeasureFin (X := fun _ ↦ Round 𝓞 𝓐 𝓨) (Y := step O₁ A₁ R₁) (P := P) - (κ' := stepKernel alg env) h.measurable_step h.hasCondDistrib_step).map_eq - -lemma IsAlgEnvSeq.hasLaw_trajectory (h : IsAlgEnvSeq O₁ A₁ R₁ alg env P) : - HasLaw (trajectory O₁ A₁ R₁) (trajMeasure alg env) P where - aemeasurable := h.measurable_trajectory.aemeasurable - map_eq := h.map_trajectory - -lemma IsAlgEnvSeqUntil.map_history (h : IsAlgEnvSeqUntil O₁ A₁ R₁ alg env P N) : - P.map (history O₁ A₁ R₁ N) = (trajMeasure alg env).map (IT.hist N) := - Kernel.eq_trajMeasureFin_map (X := fun _ ↦ Round 𝓞 𝓐 𝓨) (Y := step O₁ A₁ R₁) (P := P) (N := N) + {O₁ : ℕ → Ω → 𝓞} {A₁ : ℕ → Ω → 𝓐} {Y₁ : ℕ → Ω → 𝓨} + {O₂ : ℕ → Ω' → 𝓞} {A₂ : ℕ → Ω' → 𝓐} {Y₂ : ℕ → Ω' → 𝓨} {N : ℕ} + +/-- The sequence of rounds of an algorithm-environment sequence has law `trajMeasure alg env`. -/ +lemma IsAlgEnvSeq.hasLaw_trajectory (h : IsAlgEnvSeq O₁ A₁ Y₁ alg env P) : + HasLaw (trajectory O₁ A₁ Y₁) (trajMeasure alg env) P := + Kernel.hasLaw_trajMeasureFin (X := fun _ ↦ Round 𝓞 𝓐 𝓨) (Y := step O₁ A₁ Y₁) (P := P) (κ' := stepKernel alg env) h.measurable_step h.hasCondDistrib_step -lemma IsAlgEnvSeq.map_history (h : IsAlgEnvSeq O₁ A₁ R₁ alg env P) (n : ℕ) : - P.map (history O₁ A₁ R₁ n) = (trajMeasure alg env).map (IT.hist n) := +lemma IsAlgEnvSeq.map_trajectory (h : IsAlgEnvSeq O₁ A₁ Y₁ alg env P) : + P.map (trajectory O₁ A₁ Y₁) = trajMeasure alg env := + h.hasLaw_trajectory.map_eq + +lemma IsAlgEnvSeqUntil.map_history (h : IsAlgEnvSeqUntil O₁ A₁ Y₁ alg env P N) : + P.map (history O₁ A₁ Y₁ N) = (trajMeasure alg env).map (IT.hist N) := + Kernel.eq_trajMeasureFin_map (X := fun _ ↦ Round 𝓞 𝓐 𝓨) (Y := step O₁ A₁ Y₁) (P := P) (N := N) + (κ' := stepKernel alg env) h.measurable_step h.hasCondDistrib_step + +lemma IsAlgEnvSeq.map_history (h : IsAlgEnvSeq O₁ A₁ Y₁ alg env P) (n : ℕ) : + P.map (history O₁ A₁ Y₁ n) = (trajMeasure alg env).map (IT.hist n) := (h.isAlgEnvSeqUntil n).map_history +/-- The history before time `N` of an algorithm-environment sequence until time `N` has the law of +the history before time `N` under `trajMeasure alg env`. -/ +lemma IsAlgEnvSeqUntil.hasLaw_history (h : IsAlgEnvSeqUntil O₁ A₁ Y₁ alg env P N) : + HasLaw (history O₁ A₁ Y₁ N) ((trajMeasure alg env).map (IT.hist N)) P where + aemeasurable := (h.measurable_history N).aemeasurable + map_eq := h.map_history + +lemma IsAlgEnvSeq.hasLaw_history (h : IsAlgEnvSeq O₁ A₁ Y₁ alg env P) (n : ℕ) : + HasLaw (history O₁ A₁ Y₁ n) ((trajMeasure alg env).map (IT.hist n)) P := + (h.isAlgEnvSeqUntil n).hasLaw_history + /-- The law of the sequence of rounds generated by an algorithm-environment pair is unique: it does not depend on the probability space used. -/ -lemma isAlgEnvSeq_unique (h1 : IsAlgEnvSeq O₁ A₁ R₁ alg env P) - (h2 : IsAlgEnvSeq O₂ A₂ R₂ alg env P') : - P.map (trajectory O₁ A₁ R₁) = P'.map (trajectory O₂ A₂ R₂) := by +lemma isAlgEnvSeq_unique (h1 : IsAlgEnvSeq O₁ A₁ Y₁ alg env P) + (h2 : IsAlgEnvSeq O₂ A₂ Y₂ alg env P') : + P.map (trajectory O₁ A₁ Y₁) = P'.map (trajectory O₂ A₂ Y₂) := by rw [h1.map_trajectory, h2.map_trajectory] /-- The law of the sequence of rounds generated by an algorithm-environment pair is unique: it does not depend on the probability space used. -/ -theorem IsAlgEnvSeq.identDistrib_trajectory (h1 : IsAlgEnvSeq O₁ A₁ R₁ alg env P) - (h2 : IsAlgEnvSeq O₂ A₂ R₂ alg env P') : - IdentDistrib (trajectory O₁ A₁ R₁) (trajectory O₂ A₂ R₂) P P' where +theorem IsAlgEnvSeq.identDistrib_trajectory (h1 : IsAlgEnvSeq O₁ A₁ Y₁ alg env P) + (h2 : IsAlgEnvSeq O₂ A₂ Y₂ alg env P') : + IdentDistrib (trajectory O₁ A₁ Y₁) (trajectory O₂ A₂ Y₂) P P' where aemeasurable_fst := h1.measurable_trajectory.aemeasurable aemeasurable_snd := h2.measurable_trajectory.aemeasurable map_eq := isAlgEnvSeq_unique h1 h2 /-- The law of the history before time `N` is determined by the algorithm-environment pair, provided that the sequence is an algorithm-environment sequence until time `N`. -/ -lemma isAlgEnvSeqUntil_unique (h1 : IsAlgEnvSeqUntil O₁ A₁ R₁ alg env P N) - (h2 : IsAlgEnvSeqUntil O₂ A₂ R₂ alg env P' N) : - P.map (history O₁ A₁ R₁ N) = P'.map (history O₂ A₂ R₂ N) := by +lemma isAlgEnvSeqUntil_unique (h1 : IsAlgEnvSeqUntil O₁ A₁ Y₁ alg env P N) + (h2 : IsAlgEnvSeqUntil O₂ A₂ Y₂ alg env P' N) : + P.map (history O₁ A₁ Y₁ N) = P'.map (history O₂ A₂ Y₂ N) := by rw [h1.map_history, h2.map_history] end ModelEquivalence namespace IT -/-- Filtration of the algorithm Seq: `IT.filtration 𝓞 𝓐 𝓨 n` is the σ-algebra generated by the +/-- Filtration generated by the rounds: `IT.filtration 𝓞 𝓐 𝓨 n` is the σ-algebra generated by the rounds at times `0, ..., n`, that is by `hist (n + 1)`. -/ protected def filtration (𝓞 𝓐 𝓨 : Type*) [MeasurableSpace 𝓞] [MeasurableSpace 𝓐] [MeasurableSpace 𝓨] : diff --git a/LeanMachineLearning/SequentialLearning/Means.lean b/LeanMachineLearning/SequentialLearning/Means.lean index 62460fcb..0c467023 100644 --- a/LeanMachineLearning/SequentialLearning/Means.lean +++ b/LeanMachineLearning/SequentialLearning/Means.lean @@ -6,6 +6,7 @@ Authors: Rémy Degenne module public import LeanMachineLearning.SequentialLearning.StationaryEnv +public import LeanMachineLearning.ForMathlib.Analysis.Convex.Integral public import LeanMachineLearning.ForMathlib.Probability.Kernel.Composition.IntegralCompProd /-! @@ -13,11 +14,17 @@ public import LeanMachineLearning.ForMathlib.Probability.Kernel.Composition.Inte ## Main definitions -* `Environment.means` +* `Environment.feedbackKernel env O A Y n ω`: the law of the feedback at time `n`, as a kernel + from the action chosen at time `n`, given the history and the observation of the run at `ω`. +* `Environment.means env O A Y k n ω`: the mean of that law at action `k`. -## Main results +## Main statements -* +* `IsAlgEnvSeq.condExp_feedback`: the conditional expectation of the feedback at time `n` given the + history, the observation and the action at time `n` is the mean of the feedback at the chosen + action. +* `IsAlgEnvSeq.integrable_means_action`, `IsAlgEnvSeq.memLp_means_action`: integrability of the + mean at the chosen action. -/ @[expose] public section @@ -26,56 +33,40 @@ open MeasureTheory ProbabilityTheory Filter Finset open scoped ENNReal -namespace ProbabilityTheory - -variable {Ω β 𝓨 : Type*} {mΩ : MeasurableSpace Ω} {mβ : MeasurableSpace β} - {m𝓨 : MeasurableSpace 𝓨} [StandardBorelSpace 𝓨] [Nonempty 𝓨] - {P : Measure Ω} [IsFiniteMeasure P] {X : Ω → β} {Y : Ω → 𝓨} - {κ : Kernel β 𝓨} [IsFiniteKernel κ] - -lemma HasCondDistrib.condExp_comp_eq {F : Type*} [NormedAddCommGroup F] [NormedSpace ℝ F] - [CompleteSpace F] (h : HasCondDistrib Y X κ P) (hX : Measurable X) - {g : 𝓨 → F} (hg : StronglyMeasurable g) (hint : Integrable (fun ω ↦ g (Y ω)) P) : - P[fun ω ↦ g (Y ω) | mβ.comap X] =ᵐ[P] fun ω ↦ ∫ y, g y ∂(κ (X ω)) := by - refine (condExp_ae_eq_integral_condDistrib hX h.aemeasurable_snd hg hint).trans ?_ - filter_upwards [ae_of_ae_map hX.aemeasurable h.condDistrib_eq] with ω hω - rw [hω] - -end ProbabilityTheory - namespace Learning variable {Ω 𝓞 𝓐 𝓨 : Type*} {mΩ : MeasurableSpace Ω} {m𝓞 : MeasurableSpace 𝓞} {m𝓐 : MeasurableSpace 𝓐} {m𝓨 : MeasurableSpace 𝓨} [NormedAddCommGroup 𝓨] [NormedSpace ℝ 𝓨] - {O : ℕ → Ω → 𝓞} {A : ℕ → Ω → 𝓐} {Y : ℕ → Ω → 𝓨} {P : Measure Ω} [IsFiniteMeasure P] + {O : ℕ → Ω → 𝓞} {A : ℕ → Ω → 𝓐} {Y : ℕ → Ω → 𝓨} {P : Measure Ω} {alg : Algorithm 𝓞 𝓐 𝓨} {env : Environment 𝓞 𝓐 𝓨} -/-- The kernel that gives the measure of the feedback distribution as a function of the action -chosen at time `n`. -/ -noncomputable def Environment.measure (env : Environment 𝓞 𝓐 𝓨) (O : ℕ → Ω → 𝓞) (A : ℕ → Ω → 𝓐) - (Y : ℕ → Ω → 𝓨) (n : ℕ) (ω : Ω) : Kernel 𝓐 𝓨 := +/-- The law of the feedback at time `n`, as a kernel from the action chosen at time `n`, given the +history and the observation of the run at `ω`: the feedback kernel `env.feedback n` applied to the +history and the observation at time `n`. -/ +noncomputable def Environment.feedbackKernel (env : Environment 𝓞 𝓐 𝓨) (O : ℕ → Ω → 𝓞) + (A : ℕ → Ω → 𝓐) (Y : ℕ → Ω → 𝓨) (n : ℕ) (ω : Ω) : Kernel 𝓐 𝓨 := (env.feedback n).sectR (history O A Y n ω, O n ω) /-- The means of the feedback distribution as a function of the action chosen at time `n`. -/ noncomputable def Environment.means (env : Environment 𝓞 𝓐 𝓨) (O : ℕ → Ω → 𝓞) (A : ℕ → Ω → 𝓐) (Y : ℕ → Ω → 𝓨) (k : 𝓐) (n : ℕ) (ω : Ω) : 𝓨 := - (env.measure O A Y n ω k)[id] + (env.feedbackKernel O A Y n ω k)[id] @[simp] -lemma means_zero (env : Environment 𝓞 𝓐 𝓨) (O : ℕ → Ω → 𝓞) (A : ℕ → Ω → 𝓐) (Y : ℕ → Ω → 𝓨) - (k : 𝓐) (ω : Ω) : +lemma Environment.means_zero (env : Environment 𝓞 𝓐 𝓨) (O : ℕ → Ω → 𝓞) (A : ℕ → Ω → 𝓐) + (Y : ℕ → Ω → 𝓨) (k : 𝓐) (ω : Ω) : env.means O A Y k 0 ω = (env.feedbackZero (O 0 ω, k))[id] := by - simp [Environment.means, Environment.measure, Environment.feedback_zero] + simp [Environment.means, Environment.feedbackKernel, Environment.feedback_zero] @[simp] -lemma means_of_isOblivious [env.IsOblivious] (O : ℕ → Ω → 𝓞) (A : ℕ → Ω → 𝓐) +lemma Environment.means_of_isOblivious [env.IsOblivious] (O : ℕ → Ω → 𝓞) (A : ℕ → Ω → 𝓐) (Y : ℕ → Ω → 𝓨) (k : 𝓐) (n : ℕ) (ω : Ω) : env.means O A Y k n ω = (env.feedbackCondObsAction n (O n ω, k))[id] := by - simp [Environment.means, Environment.measure, env.feedback_eq_comap_feedbackCondObsAction, + simp [Environment.means, Environment.feedbackKernel, env.feedback_eq_comap_feedbackCondObsAction, Kernel.comap_apply] -lemma means_of_isStationary [env.IsStationary] (O : ℕ → Ω → 𝓞) (A : ℕ → Ω → 𝓐) +lemma Environment.means_of_isStationary [env.IsStationary] (O : ℕ → Ω → 𝓞) (A : ℕ → Ω → 𝓐) (Y : ℕ → Ω → 𝓨) (k : 𝓐) (n : ℕ) (ω : Ω) : env.means O A Y k n ω = (env.feedbackZero (O n ω, k))[id] := by rw [means_of_isOblivious, env.feedbackCondObsAction_eq_feedbackZero] @@ -102,10 +93,10 @@ lemma IsAlgEnvSeq.stronglyMeasurable_means [SecondCountableTopology 𝓨] [Opens StronglyMeasurable (env.means O A Y k n) := by unfold Environment.means have hO := h.measurable_obs - have h_eq ω : env.measure O A Y n ω k = + have h_eq ω : env.feedbackKernel O A Y n ω k = (env.feedback n ∘ₖ Kernel.deterministic (fun ω ↦ ((history O A Y n ω, O n ω), k)) (((h.measurable_history n).prodMk (h.measurable_obs n)).prodMk (by fun_prop))) ω := by - simp [Environment.measure, Kernel.comp_deterministic_eq_comap] + simp [Environment.feedbackKernel, Kernel.comp_deterministic_eq_comap] simp_rw [h_eq] fun_prop @@ -119,11 +110,10 @@ lemma IsAlgEnvSeq.adapted_means_filtrationAction [SecondCountableTopology 𝓨] (h : IsAlgEnvSeq O A Y alg env P) : Adapted h.filtrationAction (fun n ω ↦ env.means O A Y (A n ω) n ω) := by intro n - simp only [Environment.means, Environment.measure, Kernel.sectR_apply, id_eq] - change Measurable[h.filtrationAction n] - ((fun ω ↦ ∫ x, x ∂(env.feedback n ω)) ∘ (fun ω ↦ ((history O A Y n ω, O n ω), A n ω))) + simp only [Environment.means, Environment.feedbackKernel, Kernel.sectR_apply, id_eq] rw [IsAlgEnvSeq.filtrationAction_eq_comap] - exact measurable_comp_comap _ stronglyMeasurable_id.integral_kernel.measurable + exact measurable_comp_comap (fun ω ↦ ((history O A Y n ω, O n ω), A n ω)) + (stronglyMeasurable_id.integral_kernel (κ := env.feedback n)).measurable lemma IsAlgEnvSeq.stronglyAdapted_means_filtrationAction [SecondCountableTopology 𝓨] [BorelSpace 𝓨] (h : IsAlgEnvSeq O A Y alg env P) : @@ -136,8 +126,8 @@ lemma IsAlgEnvSeq.adapted_means [SecondCountableTopology 𝓨] [BorelSpace 𝓨] fun n ↦ (h.adapted_means_filtrationAction n).mono (h.filtrationAction_le_filtration n) le_rfl omit [NormedSpace ℝ 𝓨] in -lemma IsAlgEnvSeq.condExp_feedback_comp {𝓩 : Type*} [NormedAddCommGroup 𝓩] [NormedSpace ℝ 𝓩] - [CompleteSpace 𝓩] [StandardBorelSpace 𝓨] +lemma IsAlgEnvSeq.condExp_feedback_comp [IsFiniteMeasure P] {𝓩 : Type*} [NormedAddCommGroup 𝓩] + [NormedSpace ℝ 𝓩] [CompleteSpace 𝓩] [StandardBorelSpace 𝓨] (h : IsAlgEnvSeq O A Y alg env P) (n : ℕ) {g : 𝓨 → 𝓩} (hg : StronglyMeasurable g) (hint : Integrable (fun ω ↦ g (Y n ω)) P) : P[fun ω ↦ g (Y n ω) | h.filtrationAction n] =ᵐ[P] @@ -145,15 +135,16 @@ lemma IsAlgEnvSeq.condExp_feedback_comp {𝓩 : Type*} [NormedAddCommGroup 𝓩] have hX : Measurable (fun ω ↦ ((history O A Y n ω, O n ω), A n ω)) := ((h.measurable_history n).prodMk (h.measurable_obs n)).prodMk (h.measurable_action n) rw [h.filtrationAction_eq_comap n] - exact (h.hasCondDistrib_feedback n).condExp_comp_eq hX hg hint + exact (h.hasCondDistrib_feedback n).condExp_comp_ae_eq hX hg hint -lemma IsAlgEnvSeq.condExp_feedback [BorelSpace 𝓨] [SecondCountableTopology 𝓨] [CompleteSpace 𝓨] +lemma IsAlgEnvSeq.condExp_feedback [IsFiniteMeasure P] [BorelSpace 𝓨] [SecondCountableTopology 𝓨] + [CompleteSpace 𝓨] (h : IsAlgEnvSeq O A Y alg env P) (n : ℕ) (hint : Integrable (Y n) P) : P[Y n | h.filtrationAction n] =ᵐ[P] fun ω ↦ env.means O A Y (A n ω) n ω := condExp_feedback_comp h n stronglyMeasurable_id hint -lemma IsAlgEnvSeq.memLp_means_action [SecondCountableTopology 𝓨] [BorelSpace 𝓨] +lemma IsAlgEnvSeq.memLp_means_action [SFinite P] [SecondCountableTopology 𝓨] [BorelSpace 𝓨] (h : IsAlgEnvSeq O A Y alg env P) {n : ℕ} {p : ℝ≥0∞} (hp1 : 1 ≤ p) (hp_top : p ≠ ∞) (hint : MemLp (Y n) p P) : MemLp (fun ω ↦ env.means O A Y (A n ω) n ω) p P := by @@ -163,7 +154,7 @@ lemma IsAlgEnvSeq.memLp_means_action [SecondCountableTopology 𝓨] [BorelSpace have h_hist := h.measurable_history have hint' : MemLp id p (P.map (Y n)) := by rwa [memLp_map_measure_iff (by fun_prop) (h.measurable_feedback _).aemeasurable] - unfold Environment.means Environment.measure + unfold Environment.means Environment.feedbackKernel simp only [id_eq] rw [(h.hasLaw_feedback_comp n).map_eq, Measure.memLp_comp_iff hp0 hp_top (by fun_prop)] at hint' have hint'' := hint'.2.comp_aemeasurable (by fun_prop) @@ -188,7 +179,8 @@ lemma IsAlgEnvSeq.memLp_means_action [SecondCountableTopology 𝓨] [BorelSpace rw [abs_of_nonneg (by positivity)] exact norm_integral_rpow_le_integral_norm_rpow hp1 hp_top hω -lemma IsAlgEnvSeq.integrable_means_action [SecondCountableTopology 𝓨] [OpensMeasurableSpace 𝓨] +lemma IsAlgEnvSeq.integrable_means_action [SFinite P] [SecondCountableTopology 𝓨] + [OpensMeasurableSpace 𝓨] (h : IsAlgEnvSeq O A Y alg env P) {n : ℕ} (hint : Integrable (Y n) P) : Integrable (fun ω ↦ env.means O A Y (A n ω) n ω) P := by have hO := h.measurable_obs @@ -196,7 +188,7 @@ lemma IsAlgEnvSeq.integrable_means_action [SecondCountableTopology 𝓨] [OpensM have h_hist := h.measurable_history have hint' : Integrable id (P.map (Y n)) := by rwa [integrable_map_measure (by fun_prop) (h.measurable_feedback _).aemeasurable] - unfold Environment.means Environment.measure + unfold Environment.means Environment.feedbackKernel simp only [id_eq] rw [(h.hasLaw_feedback_comp n).map_eq, Measure.integrable_comp_iff (by fun_prop)] at hint' have hint'' := hint'.2.comp_aemeasurable (by fun_prop) diff --git a/LeanMachineLearning/SequentialLearning/README.md b/LeanMachineLearning/SequentialLearning/README.md index eb0cecbf..d9dbb5c8 100644 --- a/LeanMachineLearning/SequentialLearning/README.md +++ b/LeanMachineLearning/SequentialLearning/README.md @@ -33,6 +33,7 @@ If you need one of them, treat the name here as a recommendation that you may wa Generic constructions live in the `Algorithm` and `Environment` namespaces. Predicates live in the `Algorithm` and `Environment` namespaces: they are classes when they carry an accessor, and `Prop` definitions otherwise. +`Environment.IsStationary` is also a class: it has no accessor of its own, since its laws are the time zero accessors `Environment.obsZero` and `Environment.feedbackZero`, but the class gives the instance `IsStationary → IsOblivious`. Accessors are namespaced so that dot notation works. All time zero accessors are `…Zero` definitions. Example: `Algorithm.policyZero`. @@ -41,17 +42,22 @@ All time zero accessors are `…Zero` definitions. Example: `Algorithm.policyZer The policy at round `n` can depend on `n`, on the history at `n` and the current observation. It can be deterministic or stochastic. -Not stochastic: `Algorithm.IsDeterministic`, `Algorithm.deterministic` +Not stochastic: `Algorithm.IsDeterministic`, `Algorithm.deterministic` (accessors `Algorithm.nextAction`, `Algorithm.actionZero`) No observation: `Algorithm.IgnoresObs` (MISSING), `Algorithm.comapObs fun _ ↦ ()` -No history: `Algorithm.IsMarkov`, `Algorithm.markov` +No history: `Algorithm.IsMarkov`, `Algorithm.markov` (accessor `Algorithm.policyCondObs`) -No history, no observation: `Algorithm.IsOpenLoop` (MISSING), `Algorithm.openLoop` (MISSING), `Algorithm.ofSeq` (MISSING) (det version) +No history, no observation: `Algorithm.IsOpenLoop` (MISSING), `Algorithm.openLoop` (MISSING), `Algorithm.ofSeq` (MISSING) (det version). +Example: `Algorithm.roundRobin K`, which plays action `n % K` at time `n` (defined with `Algorithm.deterministic` while `Algorithm.ofSeq` is missing). Not time-dependent, no history: `Algorithm.IsStationary` (MISSING), `Algorithm.stationary` (MISSING) -No time, no history, no observation: `Algorithm.const` +No time, no history, no observation: `Algorithm.const`. +Example: `Algorithm.uniform`, the constant algorithm with the uniform law on a finite action set. + +Algorithms from the literature are not generic constructions: they keep their own names, and their lemmas live in their own namespaces. +Examples: `Bandits.etcAlgorithm`, `Bandits.ucbAlgorithm`, `Bandits.tsAlgorithm`, with lemmas in `Bandits.ETC`, `Bandits.UCB`, `Bandits.TS`; `Learning.RoundRobin` for `Algorithm.roundRobin`. ## Environments @@ -64,13 +70,16 @@ In general, the dependence on history is the same for both kernels. All for obs, no action for feedback: `Environment.FeedbackIgnoresAction` (MISSING), `Environment.adversary` (MISSING). -No history for obs and feedback: `Environment.IsOblivious`, `Environment.oblivious`. +No history for obs and feedback: `Environment.IsOblivious`, `Environment.oblivious` (accessors `Environment.obsLaw`, `Environment.feedbackCondObsAction`). -No time, no history for obs and feedback: `Environment.IsStationary`, `Environment.stationary`. +No time, no history for obs and feedback: `Environment.IsStationary`, `Environment.stationary` (laws `Environment.obsZero`, `Environment.feedbackZero`). No time, last round of history for obs, not history for feedback: `Environment.IsMarkov` (MISSING), `Environment.markov` (MISSING). -Determinism: `Environment.HasDeterministicObs` (MISSING), `Environment.HasDeterministicFeedback`, `Environment.detFeedback` (any observation kernels, deterministic feedback). +Determinism: `Environment.HasDeterministicObs` (MISSING), `Environment.HasDeterministicFeedback`, `Environment.detFeedback` (any observation kernels, deterministic feedback) (accessors `Environment.feedbackFun`, `Environment.feedbackFunZero`). + +Bayesian: `Environment.bayesBandit Q κ` draws a parameter `e` from the prior `Q` before the first round and announces it as the observation of every round; the feedback to action `a` is drawn from `κ (e, a)`. +The algorithm ignores the announced parameter: it runs through `Algorithm.comapObs fun _ ↦ ()`. ### Obs = Unit @@ -87,6 +96,17 @@ No history, no action (only time): `Environment.indep` (MISSING) and `Environmen Nothing: `Environment.const` (MISSING) (stochastic). The deterministic version is probably not useful. +## Runs + +A run is `h : IsAlgEnvSeq O A Y alg env P` (or `IsAlgEnvSeqUntil` for the first rounds). + +Lemmas about runs of a generic construction or class use dot notation on `h`: `IsAlgEnvSeq._`. +Examples: `IsAlgEnvSeq.hasCondDistrib_feedback_banditSeq`, `IsAlgEnvSeq.hasCondDistrib_action_markov`, `IsAlgEnvSeq.hasLaw_action_const`, `IsAlgEnvSeq.hasLaw_obs_obsLaw`, `IsAlgEnvSeq.action_ae_eq_nextAction`. +Lemmas about algorithms from the literature stay in their own namespaces (see above). + +Quantities that depend on a run are namespaced by the environment or algorithm they read, so that dot notation works: +`Environment.feedbackKernel env O A Y n ω` is the feedback kernel at time `n` with the history and the observation of the run at `ω` plugged in, a kernel from actions to feedbacks; `Environment.means env O A Y k n ω` is its mean at action `k`. + ## Examples Oblivious adversarial bandit environment: Obs = Unit, feedback depends on time and action, deterministic. Use `Environment.evalSeq`. diff --git a/LeanMachineLearning/SequentialLearning/StationaryEnv.lean b/LeanMachineLearning/SequentialLearning/StationaryEnv.lean index dcd5571d..c8103ff8 100644 --- a/LeanMachineLearning/SequentialLearning/StationaryEnv.lean +++ b/LeanMachineLearning/SequentialLearning/StationaryEnv.lean @@ -5,6 +5,7 @@ Authors: Rémy Degenne, Paulo Rauber -/ module +public import LeanMachineLearning.ForMathlib.Probability.Independence.Conditional public import LeanMachineLearning.ForMathlib.Probability.Kernel.Composition.MapComap public import LeanMachineLearning.SequentialLearning.Algorithm @@ -141,23 +142,23 @@ lemma feedbackCondObsAction_eq_of_feedback_eq (env : Environment 𝓞 𝓐 𝓨) end Environment -namespace Environment.IsOblivious +section IsOblivious + +/-! ### Runs in an oblivious environment -/ variable {Ω : Type*} {mΩ : MeasurableSpace Ω} {alg : Algorithm 𝓞 𝓐 𝓨} {env : Environment 𝓞 𝓐 𝓨} {P : Measure Ω} {O : ℕ → Ω → 𝓞} {A : ℕ → Ω → 𝓐} {Y : ℕ → Ω → 𝓨} {n N : ℕ} /-- The observation at time `n` has law `env.obsLaw n`. -/ -lemma hasLaw_obs [IsProbabilityMeasure P] [env.IsOblivious] +lemma IsAlgEnvSeq.hasLaw_obs_obsLaw [IsProbabilityMeasure P] [env.IsOblivious] (h : IsAlgEnvSeq O A Y alg env P) (n : ℕ) : HasLaw (O n) (env.obsLaw n) P := by have h' := h.hasCondDistrib_obs n rw [env.obs_eq_const_obsLaw] at h' exact h'.hasLaw_of_const -variable [IsFiniteMeasure P] - -lemma hasCondDistrib_feedback_history_action [env.IsOblivious] +lemma IsAlgEnvSeq.hasCondDistrib_feedback_history_action_feedbackCondObsAction [env.IsOblivious] (h : IsAlgEnvSeq O A Y alg env P) (n : ℕ) : HasCondDistrib (Y n) (fun ω ↦ ((history O A Y n ω, O n ω), A n ω)) ((env.feedbackCondObsAction n).comap (fun p ↦ (p.1.2, p.2)) (by fun_prop) @@ -167,27 +168,29 @@ lemma hasCondDistrib_feedback_history_action [env.IsOblivious] /-- The conditional distribution of the feedback at time `n` given the observation and the action at time `n` is `env.feedbackCondObsAction n`. -/ -lemma hasCondDistrib_feedback [env.IsOblivious] (h : IsAlgEnvSeq O A Y alg env P) (n : ℕ) : +lemma IsAlgEnvSeq.hasCondDistrib_feedback_feedbackCondObsAction [SFinite P] [env.IsOblivious] + (h : IsAlgEnvSeq O A Y alg env P) (n : ℕ) : HasCondDistrib (Y n) (fun ω ↦ (O n ω, A n ω)) (env.feedbackCondObsAction n) P := - (hasCondDistrib_feedback_history_action h n).comp_right + (h.hasCondDistrib_feedback_history_action_feedbackCondObsAction n).comp_right /-- Conditionally on an event determined by the history before time `n`, the observation and the action at time `n`, on which the observation-action pair is equal to `b`, the feedback at time `n` has law `env.feedbackCondObsAction n b`. -/ -lemma hasLaw_feedback_cond [env.IsOblivious] (h : IsAlgEnvSeq O A Y alg env P) (n : ℕ) +lemma IsAlgEnvSeq.hasLaw_feedback_cond_feedbackCondObsAction [IsFiniteMeasure P] [env.IsOblivious] + (h : IsAlgEnvSeq O A Y alg env P) (n : ℕ) {s : Set ((Hist 𝓞 𝓐 𝓨 n × 𝓞) × 𝓐)} (hs : MeasurableSet s) {b : 𝓞 × 𝓐} (hsb : ∀ u ∈ s, (u.1.2, u.2) = b) (hP : P ((fun ω ↦ ((history O A Y n ω, O n ω), A n ω)) ⁻¹' s) ≠ 0) : HasLaw (Y n) (env.feedbackCondObsAction n b) P[|(fun ω ↦ ((history O A Y n ω, O n ω), A n ω)) ⁻¹' s] := by - refine (hasCondDistrib_feedback_history_action h n).hasLaw_cond (h.measurable_feedback _) hs + refine (h.hasCondDistrib_feedback_history_action_feedbackCondObsAction n).hasLaw_cond hs (fun u hu ↦ ?_) hP rw [Kernel.comap_apply, hsb u hu] /-- Conditionally on an event determined by the history before time `n`, the observation and the action at time `n`, on which the observation-action pair is constant, the feedback at time `n` is independent of the history before time `n`, the observation and the action at time `n`. -/ -lemma indepFun_history_action_feedback_cond [env.IsOblivious] +lemma IsAlgEnvSeq.indepFun_history_action_feedback_cond [IsFiniteMeasure P] [env.IsOblivious] (h : IsAlgEnvSeq O A Y alg env P) (n : ℕ) {s : Set ((Hist 𝓞 𝓐 𝓨 n × 𝓞) × 𝓐)} (hs : MeasurableSet s) {b : 𝓞 × 𝓐} (hsb : ∀ u ∈ s, (u.1.2, u.2) = b) : @@ -196,8 +199,8 @@ lemma indepFun_history_action_feedback_cond [env.IsOblivious] have hO := h.measurable_obs have hA := h.measurable_action have hY := h.measurable_feedback - refine (hasCondDistrib_feedback_history_action h n).indepFun_cond (by fun_prop) hs - (η := env.feedbackCondObsAction n b) fun u hu ↦ ?_ + refine (h.hasCondDistrib_feedback_history_action_feedbackCondObsAction n).indepFun_cond + (by fun_prop) hs (η := env.feedbackCondObsAction n b) fun u hu ↦ ?_ rw [Kernel.comap_apply, hsb u hu] variable [StandardBorelSpace 𝓞] [Nonempty 𝓞] [StandardBorelSpace 𝓐] [Nonempty 𝓐] @@ -205,7 +208,7 @@ variable [StandardBorelSpace 𝓞] [Nonempty 𝓞] [StandardBorelSpace 𝓐] [No /-- The feedback at time `n` is conditionally independent of the history before time `n`, given the observation and the action at time `n`. -/ -lemma condIndepFun_feedback_history [StandardBorelSpace Ω] +lemma IsAlgEnvSeq.condIndepFun_feedback_history [IsFiniteMeasure P] [StandardBorelSpace Ω] [env.IsOblivious] (h : IsAlgEnvSeq O A Y alg env P) (n : ℕ) : Y n ⟂ᵢ[fun ω ↦ (O n ω, A n ω), (h.measurable_obs n).prodMk (h.measurable_action n); P] history O A Y n := by @@ -214,8 +217,8 @@ lemma condIndepFun_feedback_history [StandardBorelSpace Ω] have hY := h.measurable_feedback refine condIndepFun_of_exists_condDistrib_prod_ae_eq_prodMkLeft (η := env.feedbackCondObsAction n) (by fun_prop) (by fun_prop) (by fun_prop) ?_ - refine HasCondDistrib.condDistrib_eq ?_ - have h' := hasCondDistrib_feedback_history_action h n + refine HasCondDistrib.condDistrib_ae_eq ?_ + have h' := h.hasCondDistrib_feedback_history_action_feedbackCondObsAction n have hκ : ((env.feedbackCondObsAction n).comap (fun p ↦ (p.1.2, p.2)) (by fun_prop) : Kernel ((Hist 𝓞 𝓐 𝓨 n × 𝓞) × 𝓐) 𝓨) = ((env.feedbackCondObsAction n).prodMkLeft (Hist 𝓞 𝓐 𝓨 n)).comap @@ -225,16 +228,16 @@ lemma condIndepFun_feedback_history [StandardBorelSpace Ω] /-- The feedback at time `n` is conditionally independent of the history before time `n`, the observation and the action at time `n`, given the observation and the action at time `n`. -/ -lemma condIndepFun_feedback_history_obs_action [StandardBorelSpace Ω] - [env.IsOblivious] (h : IsAlgEnvSeq O A Y alg env P) (n : ℕ) : +lemma IsAlgEnvSeq.condIndepFun_feedback_history_obs_action [IsFiniteMeasure P] + [StandardBorelSpace Ω] [env.IsOblivious] (h : IsAlgEnvSeq O A Y alg env P) (n : ℕ) : Y n ⟂ᵢ[fun ω ↦ (O n ω, A n ω), (h.measurable_obs n).prodMk (h.measurable_action n); P] (fun ω ↦ (history O A Y n ω, (O n ω, A n ω))) := by have hO := h.measurable_obs have hA := h.measurable_action have hY := h.measurable_feedback - exact (condIndepFun_feedback_history h n).prod_right (by fun_prop) (by fun_prop) (by fun_prop) + exact (h.condIndepFun_feedback_history n).prod_right (by fun_prop) (by fun_prop) (by fun_prop) -end Environment.IsOblivious +end IsOblivious /-- An environment is stationary if it is oblivious and its laws do not depend on time: the observations have a fixed law, and the feedback depends only on the current observation and action, @@ -282,23 +285,23 @@ lemma feedbackCondObsAction_eq_feedbackZero (env : Environment 𝓞 𝓐 𝓨) [ end Environment -namespace Environment.IsStationary +section IsStationary + +/-! ### Runs in a stationary environment -/ variable {Ω : Type*} {mΩ : MeasurableSpace Ω} {alg : Algorithm 𝓞 𝓐 𝓨} {env : Environment 𝓞 𝓐 𝓨} {P : Measure Ω} {O : ℕ → Ω → 𝓞} {A : ℕ → Ω → 𝓐} {Y : ℕ → Ω → 𝓨} /-- The observation at time `n` has law `env.obsZero`. -/ -lemma hasLaw_obs [IsProbabilityMeasure P] [env.IsStationary] +lemma IsAlgEnvSeq.hasLaw_obs_obsZero [IsProbabilityMeasure P] [env.IsStationary] (h : IsAlgEnvSeq O A Y alg env P) (n : ℕ) : HasLaw (O n) env.obsZero P := by have h' := h.hasCondDistrib_obs n rw [env.obs_eq_const_obsZero] at h' exact h'.hasLaw_of_const -variable [IsFiniteMeasure P] - -lemma hasCondDistrib_feedback_history_action [env.IsStationary] +lemma IsAlgEnvSeq.hasCondDistrib_feedback_history_action_feedbackZero [env.IsStationary] (h : IsAlgEnvSeq O A Y alg env P) (n : ℕ) : HasCondDistrib (Y n) (fun ω ↦ ((history O A Y n ω, O n ω), A n ω)) (env.feedbackZero.comap (fun p ↦ (p.1.2, p.2)) (by fun_prop) @@ -308,23 +311,25 @@ lemma hasCondDistrib_feedback_history_action [env.IsStationary] /-- The conditional distribution of the feedback at time `n` given the observation and the action at time `n` is `env.feedbackZero`. -/ -lemma hasCondDistrib_feedback [env.IsStationary] (h : IsAlgEnvSeq O A Y alg env P) (n : ℕ) : +lemma IsAlgEnvSeq.hasCondDistrib_feedback_feedbackZero [SFinite P] [env.IsStationary] + (h : IsAlgEnvSeq O A Y alg env P) (n : ℕ) : HasCondDistrib (Y n) (fun ω ↦ (O n ω, A n ω)) env.feedbackZero P := - (hasCondDistrib_feedback_history_action h n).comp_right + (h.hasCondDistrib_feedback_history_action_feedbackZero n).comp_right /-- Conditionally on an event determined by the history before time `n`, the observation and the action at time `n`, on which the observation-action pair is equal to `b`, the feedback at time `n` has law `env.feedbackZero b`. -/ -lemma hasLaw_feedback_cond [env.IsStationary] (h : IsAlgEnvSeq O A Y alg env P) (n : ℕ) +lemma IsAlgEnvSeq.hasLaw_feedback_cond_feedbackZero [IsFiniteMeasure P] [env.IsStationary] + (h : IsAlgEnvSeq O A Y alg env P) (n : ℕ) {s : Set ((Hist 𝓞 𝓐 𝓨 n × 𝓞) × 𝓐)} (hs : MeasurableSet s) {b : 𝓞 × 𝓐} (hsb : ∀ u ∈ s, (u.1.2, u.2) = b) (hP : P ((fun ω ↦ ((history O A Y n ω, O n ω), A n ω)) ⁻¹' s) ≠ 0) : HasLaw (Y n) (env.feedbackZero b) P[|(fun ω ↦ ((history O A Y n ω, O n ω), A n ω)) ⁻¹' s] := by rw [← env.feedbackCondObsAction_eq_feedbackZero n] - exact IsOblivious.hasLaw_feedback_cond h n hs hsb hP + exact h.hasLaw_feedback_cond_feedbackCondObsAction n hs hsb hP -end Environment.IsStationary +end IsStationary section Oblivious @@ -466,7 +471,7 @@ instance : (Environment.banditSeq ν).IsOblivious := @[simp] lemma obsLaw_banditSeq (n : ℕ) : (Environment.banditSeq ν).obsLaw n = Measure.dirac () := - Measure.eq_dirac_unit _ + Measure.eq_dirac_of_subsingleton _ () @[simp] lemma feedbackCondObsAction_banditSeq (n : ℕ) : @@ -517,7 +522,7 @@ instance : (Environment.bandit ν).IsOblivious := @[simp] lemma obsLaw_bandit (n : ℕ) : (Environment.bandit ν).obsLaw n = Measure.dirac () := - Measure.eq_dirac_unit _ + Measure.eq_dirac_of_subsingleton _ () @[simp] lemma feedbackCondObsAction_bandit (n : ℕ) : @@ -530,12 +535,12 @@ namespace IsAlgEnvSeq section General -variable {Ω : Type*} {mΩ : MeasurableSpace Ω} {alg : Algorithm 𝓞 𝓐 𝓨} - {P : Measure Ω} [IsProbabilityMeasure P] +variable {Ω : Type*} {mΩ : MeasurableSpace Ω} {alg : Algorithm 𝓞 𝓐 𝓨} {P : Measure Ω} {O : ℕ → Ω → 𝓞} {A : ℕ → Ω → 𝓐} {Y : ℕ → Ω → 𝓨} /-- The observation at time `n` has law `μ n`. -/ -lemma hasLaw_obs_oblivious {μ : ℕ → Measure 𝓞} [∀ n, IsProbabilityMeasure (μ n)] +lemma hasLaw_obs_oblivious [IsProbabilityMeasure P] + {μ : ℕ → Measure 𝓞} [∀ n, IsProbabilityMeasure (μ n)] {ν : ℕ → Kernel (𝓞 × 𝓐) 𝓨} [∀ n, IsMarkovKernel (ν n)] (h : IsAlgEnvSeq O A Y alg (Environment.oblivious μ ν) P) (n : ℕ) : HasLaw (O n) (μ n) P := by @@ -545,7 +550,8 @@ lemma hasLaw_obs_oblivious {μ : ℕ → Measure 𝓞} [∀ n, IsProbabilityMeas /-- The conditional distribution of the feedback at time `n` given the observation and the action at time `n` is `ν n`. -/ -lemma hasCondDistrib_feedback_oblivious {μ : ℕ → Measure 𝓞} [∀ n, IsProbabilityMeasure (μ n)] +lemma hasCondDistrib_feedback_oblivious [SFinite P] + {μ : ℕ → Measure 𝓞} [∀ n, IsProbabilityMeasure (μ n)] {ν : ℕ → Kernel (𝓞 × 𝓐) 𝓨} [∀ n, IsMarkovKernel (ν n)] (h : IsAlgEnvSeq O A Y alg (Environment.oblivious μ ν) P) (n : ℕ) : HasCondDistrib (Y n) (fun ω ↦ (O n ω, A n ω)) (ν n) P := by @@ -554,7 +560,7 @@ lemma hasCondDistrib_feedback_oblivious {μ : ℕ → Measure 𝓞} [∀ n, IsPr exact h'.comp_right /-- The observation at time `n` has law `μ`. -/ -lemma hasLaw_obs_stationary {μ : Measure 𝓞} [IsProbabilityMeasure μ] +lemma hasLaw_obs_stationary [IsProbabilityMeasure P] {μ : Measure 𝓞} [IsProbabilityMeasure μ] {ν : Kernel (𝓞 × 𝓐) 𝓨} [IsMarkovKernel ν] (h : IsAlgEnvSeq O A Y alg (Environment.stationary μ ν) P) (n : ℕ) : HasLaw (O n) μ P := @@ -562,7 +568,8 @@ lemma hasLaw_obs_stationary {μ : Measure 𝓞} [IsProbabilityMeasure μ] /-- The conditional distribution of the feedback at time `n` given the observation and the action at time `n` is `ν`. -/ -lemma hasCondDistrib_feedback_stationary {μ : Measure 𝓞} [IsProbabilityMeasure μ] +lemma hasCondDistrib_feedback_stationary [SFinite P] + {μ : Measure 𝓞} [IsProbabilityMeasure μ] {ν : Kernel (𝓞 × 𝓐) 𝓨} [IsMarkovKernel ν] (h : IsAlgEnvSeq O A Y alg (Environment.stationary μ ν) P) (n : ℕ) : HasCondDistrib (Y n) (fun ω ↦ (O n ω, A n ω)) ν P := @@ -574,12 +581,12 @@ section Bandit variable {Ω : Type*} {mΩ : MeasurableSpace Ω} {alg : Algorithm Unit 𝓐 𝓨} {ν : Kernel 𝓐 𝓨} [IsMarkovKernel ν] - {P : Measure Ω} [IsProbabilityMeasure P] + {P : Measure Ω} {O : ℕ → Ω → Unit} {A : ℕ → Ω → 𝓐} {Y : ℕ → Ω → 𝓨} /-- The conditional distribution of the feedback at time `n` given the action at time `n` is `ν n`. -/ -lemma hasCondDistrib_feedback_banditSeq {ν : ℕ → Kernel 𝓐 𝓨} [∀ n, IsMarkovKernel (ν n)] +lemma hasCondDistrib_feedback_banditSeq [SFinite P] {ν : ℕ → Kernel 𝓐 𝓨} [∀ n, IsMarkovKernel (ν n)] (h : IsAlgEnvSeq O A Y alg (Environment.banditSeq ν) P) (n : ℕ) : HasCondDistrib (Y n) (A n) (ν n) P := by have h' : HasCondDistrib (Y n) (fun ω ↦ (O n ω, A n ω)) ((ν n).prodMkLeft Unit) P := @@ -587,42 +594,43 @@ lemma hasCondDistrib_feedback_banditSeq {ν : ℕ → Kernel 𝓐 𝓨} [∀ n, exact h'.comp_right /-- The conditional distribution of the feedback at time `n` given the action at time `n` is `ν`. -/ -lemma hasCondDistrib_feedback_bandit +lemma hasCondDistrib_feedback_bandit [SFinite P] (h : IsAlgEnvSeq O A Y alg (Environment.bandit ν) P) (n : ℕ) : HasCondDistrib (Y n) (A n) ν P := hasCondDistrib_feedback_banditSeq h n /-- The conditional distribution of the feedback at time `n` given the action at time `n` is `ν`. -/ -lemma condDistrib_feedback_bandit [StandardBorelSpace 𝓨] [Nonempty 𝓨] +lemma condDistrib_feedback_bandit [IsFiniteMeasure P] [StandardBorelSpace 𝓨] [Nonempty 𝓨] (h : IsAlgEnvSeq O A Y alg (Environment.bandit ν) P) (n : ℕ) : condDistrib (Y n) (A n) P =ᵐ[P.map (A n)] ν := - (hasCondDistrib_feedback_bandit h n).condDistrib_eq + (hasCondDistrib_feedback_bandit h n).condDistrib_ae_eq /-- Conditionally on an event determined by the history before time `n` and the action at time `n`, on which that action is equal to `b`, the feedback at time `n` has law `ν b`. -/ -lemma hasLaw_feedback_cond_bandit (h : IsAlgEnvSeq O A Y alg (Environment.bandit ν) P) (n : ℕ) +lemma hasLaw_feedback_cond_bandit [IsFiniteMeasure P] + (h : IsAlgEnvSeq O A Y alg (Environment.bandit ν) P) (n : ℕ) {s : Set ((Hist Unit 𝓐 𝓨 n × Unit) × 𝓐)} (hs : MeasurableSet s) {b : 𝓐} (hsb : ∀ u ∈ s, u.2 = b) (hP : P ((fun ω ↦ ((history O A Y n ω, O n ω), A n ω)) ⁻¹' s) ≠ 0) : HasLaw (Y n) (ν b) P[|(fun ω ↦ ((history O A Y n ω, O n ω), A n ω)) ⁻¹' s] := by - simpa using Environment.IsOblivious.hasLaw_feedback_cond h n hs (b := ((), b)) + simpa using h.hasLaw_feedback_cond_feedbackCondObsAction n hs (b := ((), b)) (fun u hu ↦ by simp [hsb u hu]) hP /-- Conditionally on an event determined by the history before time `n` and the action at time `n`, on which that action is constant, the feedback at time `n` is independent of the history before time `n` and of the action at time `n`. -/ -lemma indepFun_history_action_feedback_cond_bandit +lemma indepFun_history_action_feedback_cond_bandit [IsFiniteMeasure P] (h : IsAlgEnvSeq O A Y alg (Environment.bandit ν) P) (n : ℕ) {s : Set ((Hist Unit 𝓐 𝓨 n × Unit) × 𝓐)} (hs : MeasurableSet s) {b : 𝓐} (hsb : ∀ u ∈ s, u.2 = b) : (fun ω ↦ ((history O A Y n ω, O n ω), A n ω)) ⟂ᵢ[P[|(fun ω ↦ ((history O A Y n ω, O n ω), A n ω)) ⁻¹' s]] Y n := - Environment.IsOblivious.indepFun_history_action_feedback_cond h n hs (b := ((), b)) + h.indepFun_history_action_feedback_cond n hs (b := ((), b)) fun u hu ↦ by simp [hsb u hu] /-- The feedback at time `n` is conditionally independent of the history before time `n` given the action at time `n`. -/ -lemma condIndepFun_feedback_history_action_bandit [StandardBorelSpace Ω] +lemma condIndepFun_feedback_history_action_bandit [IsFiniteMeasure P] [StandardBorelSpace Ω] [StandardBorelSpace 𝓐] [Nonempty 𝓐] [StandardBorelSpace 𝓨] [Nonempty 𝓨] (h : IsAlgEnvSeq O A Y alg (Environment.bandit ν) P) (n : ℕ) : Y n ⟂ᵢ[A n, h.measurable_action _ ; P] (fun ω ↦ (history O A Y n ω, O n ω)) := by @@ -631,11 +639,13 @@ lemma condIndepFun_feedback_history_action_bandit [StandardBorelSpace Ω] have hY := h.measurable_feedback refine condIndepFun_of_exists_condDistrib_prod_ae_eq_prodMkLeft (η := ν) (by fun_prop) (by fun_prop) (by fun_prop) ?_ - refine HasCondDistrib.condDistrib_eq ?_ + refine HasCondDistrib.condDistrib_ae_eq ?_ have h' := h.hasCondDistrib_feedback n rwa [feedback_bandit] at h' -lemma condIndepFun_feedback_history_action_action_bandit [StandardBorelSpace Ω] +/-- The feedback at time `n` is conditionally independent of the history before time `n` and the +action at time `n`, given the action at time `n`. -/ +lemma condIndepFun_feedback_history_action_action_bandit [IsFiniteMeasure P] [StandardBorelSpace Ω] [StandardBorelSpace 𝓐] [Nonempty 𝓐] [StandardBorelSpace 𝓨] [Nonempty 𝓨] (h : IsAlgEnvSeq O A Y alg (Environment.bandit ν) P) (n : ℕ) : Y n ⟂ᵢ[A n, h.measurable_action n; P] diff --git a/LeanMachineLearning/SequentialLearning/StoppedHistory.lean b/LeanMachineLearning/SequentialLearning/StoppedHistory.lean index 4a2c3dd8..b5e99d53 100644 --- a/LeanMachineLearning/SequentialLearning/StoppedHistory.lean +++ b/LeanMachineLearning/SequentialLearning/StoppedHistory.lean @@ -20,12 +20,12 @@ length: the interaction stops after `n` rounds if the history of these `n` round * `Learning.sigmaHistory O X Y n : Ω → Σ n, Hist 𝓞 𝓐 𝓨 n`: the history of the first `n` rounds, as a history of variable length; -* `stoppedHistMeasure alg env S`: the law of the history stopped by `S`. +* `Learning.stoppedHistMeasure alg env S`: the law of the history stopped by `S`. -## Main results +## Main statements -* `IsAlgEnvSeq.hasLaw_stoppedHist_stoppingTime`: the law of the - history stopped by `S` is determined by the algorithm and the environment. +* `IsAlgEnvSeq.hasLaw_stoppedValue_sigmaHistory`: the law of the history stopped by `S` is + `stoppedHistMeasure alg env S`, hence it is determined by the algorithm and the environment. -/ @[expose] public section @@ -38,7 +38,7 @@ variable {𝓞 𝓐 𝓨 Ω : Type*} {m𝓞 : MeasurableSpace 𝓞} {m𝓐 : Mea {m𝓨 : MeasurableSpace 𝓨} {mΩ : MeasurableSpace Ω} {alg : Algorithm 𝓞 𝓐 𝓨} {env : Environment 𝓞 𝓐 𝓨} {O : ℕ → Ω → 𝓞} {X : ℕ → Ω → 𝓐} {Y : ℕ → Ω → 𝓨} {S : Set (Σ n : ℕ, Hist 𝓞 𝓐 𝓨 n)} - {τ : Ω → WithTop ℕ} {ω : Ω} {n M : ℕ} + {τ : Ω → WithTop ℕ} /-- The history of the first `n` rounds, as a history of variable length in the sigma type `Σ n : ℕ, Hist 𝓞 𝓐 𝓨 n`. -/ @@ -57,7 +57,7 @@ include hO hX hY @[fun_prop] lemma measurable_sigmaHistory (n : ℕ) : Measurable (sigmaHistory O X Y n) := - (measurable_sigma_mk n).comp (measurable_history hO hX hY n) + (measurable_sigmaMk n).comp (measurable_history hO hX hY n) @[fun_prop] lemma measurable_hittingAfter_sigmaHistory (hS : MeasurableSet S) : @@ -70,18 +70,14 @@ lemma measurable_hittingAfter_sigmaHistory (hS : MeasurableSet S) : rw [this] exact MeasurableSet.iInter fun n ↦ measurable_sigmaHistory hO hX hY n hS.compl | coe n => - have : hittingAfter (sigmaHistory O X Y) S 0 ⁻¹' {((n : ℕ) : WithTop ℕ)} = + have : hittingAfter (sigmaHistory O X Y) S 0 ⁻¹' {WithTop.some n} = sigmaHistory O X Y n ⁻¹' S ∩ ⋂ j < n, sigmaHistory O X Y j ⁻¹' Sᶜ := by ext ω - simp only [Set.mem_preimage, Set.mem_singleton_iff, Set.preimage_compl, Set.mem_inter_iff, - Set.mem_iInter, Set.mem_compl_iff] - convert hittingAfter_eq_coe_iff using 1 - · simp only [Nat.cast_id, zero_le, Set.mem_Ico, true_and] - · infer_instance - simp only [ENat.some_eq_natCast, this, Set.preimage_compl] + rw [Set.mem_preimage, Set.mem_singleton_iff, hittingAfter_eq_coe_iff] + simp + rw [this] exact (measurable_sigmaHistory hO hX hY n hS).inter - (MeasurableSet.iInter fun j ↦ MeasurableSet.iInter fun _ ↦ - (measurable_sigmaHistory hO hX hY j hS).compl) + (.iInter fun j ↦ .iInter fun _ ↦ (measurable_sigmaHistory hO hX hY j hS).compl) @[fun_prop] lemma measurable_stoppedValue_sigmaHistory (hτ : Measurable τ) : @@ -92,12 +88,12 @@ end Measurability section Filtration -variable {alg : Algorithm 𝓞 𝓐 𝓨} {env : Environment 𝓞 𝓐 𝓨} {P : Measure Ω} [IsFiniteMeasure P] +variable {P : Measure Ω} -- TODO: it is also adapted for the filtration at the time before? lemma IsAlgEnvSeq.adapted_sigmaHistory (h : IsAlgEnvSeq O X Y alg env P) : Adapted h.filtration (sigmaHistory O X Y) := - fun n ↦ (measurable_sigma_mk n).comp (h.adapted_history n) + fun n ↦ (measurable_sigmaMk n).comp (h.adapted_history n) end Filtration @@ -128,10 +124,10 @@ lemma IsAlgEnvSeq.hasLaw_stoppedValue_sigmaHistory {P : Measure Ω} [IsProbabili (h : IsAlgEnvSeq O X Y alg env P) (hS : MeasurableSet S) : HasLaw (stoppedValue (sigmaHistory O X Y) (hittingAfter (sigmaHistory O X Y) S 0)) (stoppedHistMeasure alg env S) P := - ((measurable_stoppedValue_sigmaHistory IT.measurable_obs IT.measurable_action + (hasLaw_map (measurable_stoppedValue_sigmaHistory IT.measurable_obs IT.measurable_action IT.measurable_feedback (measurable_hittingAfter_sigmaHistory IT.measurable_obs IT.measurable_action - IT.measurable_feedback hS)).hasLaw_map _).comp h.hasLaw_trajectory + IT.measurable_feedback hS)).aemeasurable).comp h.hasLaw_trajectory end StoppedHistMeasure diff --git a/LeanMachineLearning/SequentialLearning/SumRewards.lean b/LeanMachineLearning/SequentialLearning/SumRewards.lean index 820cd4ef..dc842ba7 100644 --- a/LeanMachineLearning/SequentialLearning/SumRewards.lean +++ b/LeanMachineLearning/SequentialLearning/SumRewards.lean @@ -6,21 +6,37 @@ Authors: Rémy Degenne, Paulo Rauber module public import LeanMachineLearning.SequentialLearning.FiniteActions +public import LeanMachineLearning.SequentialLearning.IonescuTulceaSpace /-! -# Sums of rewards +# Sums of rewards and empirical means + +## Main definitions + +* `sumRewards A R a t ω`: sum of the rewards obtained when choosing action `a` before time `t`. + `sumRewards'` is the same quantity, as a function of the history. +* `empMean A R a t ω`: empirical mean of the rewards obtained when choosing action `a` before + time `t`. `empMean'` is the same quantity, as a function of the history. + +## Main statements + +* `sum_rewardByCount_eq_sumRewards`: the sum of rewards is the sum of the rewards by count. +* `IsAlgEnvSeq.isStronglyPredictable_sumRewards`, `IsAlgEnvSeq.isStronglyPredictable_empMean`: + the sums of rewards and the empirical means are predictable processes. +* `IsAlgEnvSeq.identDistrib_pullCount_sumRewards`: the joint law of the numbers of pulls and of the + sums of rewards does not depend on the probability space. -/ @[expose] public section -open MeasureTheory Finset Learning +open MeasureTheory ProbabilityTheory Finset Learning namespace Learning variable {𝓞 𝓐 𝓨 Ω : Type*} {m𝓞 : MeasurableSpace 𝓞} {m𝓐 : MeasurableSpace 𝓐} {m𝓨 : MeasurableSpace 𝓨} {mΩ : MeasurableSpace Ω} - [DecidableEq 𝓐] [AddCommGroup 𝓨] - {P : Measure Ω} [IsProbabilityMeasure P] + [DecidableEq 𝓐] [AddCommMonoid 𝓨] + {P : Measure Ω} {O : ℕ → Ω → 𝓞} {A : ℕ → Ω → 𝓐} {R : ℕ → Ω → 𝓨} {a : 𝓐} {m n t : ℕ} {ω : Ω} @@ -30,7 +46,7 @@ noncomputable def sumRewards (A : ℕ → Ω → 𝓐) (R : ℕ → Ω → 𝓨) /-- Sum of rewards of arm `a` in the history before time `n`. -/ noncomputable -def sumRewards' (n : ℕ) (h : Hist 𝓞 𝓐 𝓨 n) (a : 𝓐) := +def sumRewards' (n : ℕ) (h : Hist 𝓞 𝓐 𝓨 n) (a : 𝓐) : 𝓨 := ∑ s, if (h s).action = a then (h s).feedback else 0 /-- Empirical mean reward obtained when pulling action `a` up to time `t` (exclusive). -/ @@ -40,7 +56,7 @@ def empMean (A : ℕ → Ω → 𝓐) (R : ℕ → Ω → ℝ) (a : 𝓐) (t : /-- Empirical mean of arm `a` in the history before time `n`. -/ noncomputable -def empMean' (n : ℕ) (h : Hist 𝓞 𝓐 ℝ n) (a : 𝓐) := +def empMean' (n : ℕ) (h : Hist 𝓞 𝓐 ℝ n) (a : 𝓐) : ℝ := sumRewards' n h a / pullCount' n h a @[simp] @@ -96,6 +112,13 @@ lemma sumRewards_eq_comp_history {R : ℕ → Ω → 𝓨} (a : 𝓐) (n : ℕ) ext ω exact sumRewards_eq_sumRewards' +/-- `sumRewards A R a n` is a function of the trajectory. -/ +lemma sumRewards_eq_comp_trajectory {R : ℕ → Ω → 𝓨} (a : 𝓐) (n : ℕ) : + sumRewards A R a n = + (fun p : ℕ → Round 𝓞 𝓐 𝓨 ↦ ∑ i ∈ range n, if (p i).action = a then (p i).feedback else 0) ∘ + trajectory O A R := + rfl + lemma empMean_eq_empMean' {R : ℕ → Ω → ℝ} {n : ℕ} {ω : Ω} : empMean A R a n ω = empMean' n (history O A R n ω) a := by unfold empMean empMean' @@ -107,7 +130,8 @@ lemma empMean_eq_comp_history {R : ℕ → Ω → ℝ} (a : 𝓐) (n : ℕ) : ext ω exact empMean_eq_empMean' -lemma sumRewards_sub_pullCount_smul_eq_sum {R : ℕ → Ω → 𝓨} (c : 𝓐 → 𝓨) : +lemma sumRewards_sub_pullCount_smul_eq_sum {𝓨 : Type*} [AddCommGroup 𝓨] {R : ℕ → Ω → 𝓨} + (c : 𝓐 → 𝓨) : sumRewards A R a (n + 1) ω - pullCount A a (n + 1) ω • c a = ∑ i ∈ range (n + 1), (if A i ω = a then R i ω - c a else 0) := by induction n with @@ -139,12 +163,11 @@ lemma measurable_uncurry_sumRewards_comp [Countable 𝓐] [MeasurableSingletonCl {R : ℕ → Ω → 𝓨} (hA : ∀ n, Measurable (A n)) (hR : ∀ n, Measurable (R n)) {f : Ω → 𝓐} (hf : Measurable f) {g : Ω → ℕ} (hg : Measurable g) : Measurable (fun ω ↦ sumRewards A R (f ω) (g ω) ω) := by - change Measurable ((fun aω ↦ sumRewards A R aω.1 (g aω.2) aω.2) ∘ fun ω ↦ (f ω, ω)) - apply Measurable.comp _ (by fun_prop) - refine measurable_from_prod_countable_right fun a ↦ ?_ - change Measurable ((fun tω ↦ sumRewards A R a tω.1 tω.2) ∘ fun ω ↦ (g ω, ω)) - apply Measurable.comp _ (by fun_prop) - exact measurable_from_prod_countable_right (fun t ↦ measurable_sumRewards hA hR a t) + have h_meas a : Measurable (fun ω ↦ sumRewards A R a (g ω) ω) := + (measurable_from_prod_countable_right (f := fun p : ℕ × Ω ↦ sumRewards A R a p.1 p.2) + (measurable_sumRewards hA hR a)).comp (hg.prodMk measurable_id) + exact (measurable_from_prod_countable_right + (f := fun p : 𝓐 × Ω ↦ sumRewards A R p.1 (g p.2) p.2) h_meas).comp (hf.prodMk measurable_id) @[fun_prop] lemma measurable_empMean [MeasurableSingletonClass 𝓐] {R : ℕ → Ω → ℝ} (hA : ∀ n, Measurable (A n)) @@ -215,13 +238,14 @@ lemma IsAlgEnvSeq.stronglyAdapted_sumRewards_add_one {𝓨 : Type*} {_ : Measura rw [IsStronglyPredictable.iff_measurable_add_one] at h_predictable exact h_predictable.2 --- TODO: give a direct proof, without a topology -lemma IsAlgEnvSeq.adapted_sumRewards_add_one {𝓨 : Type*} {_ : MeasurableSpace 𝓨} - [NormedAddCommGroup 𝓨] [BorelSpace 𝓨] [SecondCountableTopology 𝓨] +lemma IsAlgEnvSeq.adapted_sumRewards_add_one [MeasurableAdd₂ 𝓨] {R : ℕ → Ω → 𝓨} {alg : Algorithm 𝓞 𝓐 𝓨} {env : Environment 𝓞 𝓐 𝓨} (h : IsAlgEnvSeq O A R alg env P) (a : 𝓐) : - Adapted h.filtration (fun n ↦ sumRewards A R a (n + 1)) := - (h.stronglyAdapted_sumRewards_add_one a).adapted + Adapted h.filtration (fun n ↦ sumRewards A R a (n + 1)) := by + intro n + beta_reduce + rw [h.filtration_eq_comap, sumRewards_eq_comp_history (O := O)] + exact measurable_comp_comap _ (measurable_sumRewards' (n + 1) a) lemma IsAlgEnvSeq.isStronglyPredictable_empMean {R' : ℕ → Ω → ℝ} {alg : Algorithm 𝓞 𝓐 ℝ} {env : Environment 𝓞 𝓐 ℝ} @@ -230,7 +254,7 @@ lemma IsAlgEnvSeq.isStronglyPredictable_empMean {R' : ℕ → Ω → ℝ} unfold empMean refine StronglyMeasurable.div ?_ ?_ · exact h.isStronglyPredictable_sumRewards a - · have h_meas := (isStronglyPredictable_pullCount h a).measurable + · have h_meas := (h.isStronglyPredictable_pullCount a).measurable fun_prop lemma IsAlgEnvSeq.stronglyAdapted_empMean_add_one @@ -248,3 +272,68 @@ lemma IsAlgEnvSeq.adapted_empMean_add_one {R' : ℕ → Ω → ℝ} (h.stronglyAdapted_empMean_add_one a).adapted end Learning + +/-! ### Uniqueness of the laws of the numbers of pulls and of the sums of rewards -/ + +namespace Learning.IsAlgEnvSeq + +variable {𝓞 𝓐 Ω Ω' : Type*} {m𝓞 : MeasurableSpace 𝓞} {m𝓐 : MeasurableSpace 𝓐} + {mΩ : MeasurableSpace Ω} {mΩ' : MeasurableSpace Ω'} [DecidableEq 𝓐] [MeasurableSingletonClass 𝓐] + {alg : Algorithm 𝓞 𝓐 ℝ} {env : Environment 𝓞 𝓐 ℝ} + {P : Measure Ω} [IsProbabilityMeasure P] {P' : Measure Ω'} [IsProbabilityMeasure P'] + {O : ℕ → Ω → 𝓞} {A : ℕ → Ω → 𝓐} {R : ℕ → Ω → ℝ} + {O₂ : ℕ → Ω' → 𝓞} {A₂ : ℕ → Ω' → 𝓐} {R₂ : ℕ → Ω' → ℝ} + +/-- The joint law of the numbers of pulls and of the sums of rewards of all actions at all times is +the same for all algorithm-environment sequences with the same algorithm and environment. -/ +lemma identDistrib_pullCount_sumRewards + (h1 : IsAlgEnvSeq O A R alg env P) (h2 : IsAlgEnvSeq O₂ A₂ R₂ alg env P') : + IdentDistrib (fun ω n a ↦ (pullCount A a n ω, sumRewards A R a n ω)) + (fun ω' n a ↦ (pullCount A₂ a n ω', sumRewards A₂ R₂ a n ω')) P P' := by + let f (τ : ℕ → Round 𝓞 𝓐 ℝ) (n : ℕ) (a : 𝓐) : ℕ × ℝ := + (∑ i ∈ range n, if (τ i).action = a then 1 else 0, + ∑ i ∈ range n, if (τ i).action = a then (τ i).feedback else 0) + have hc1 : (fun ω n a ↦ (pullCount A a n ω, sumRewards A R a n ω)) = + f ∘ (trajectory O A R) := by + ext ω n a : 3 + simp_rw [Function.comp, f, pullCount, card_filter, sumRewards, trajectory] + rfl + have hc2 : (fun ω' n a ↦ (pullCount A₂ a n ω', sumRewards A₂ R₂ a n ω')) = + f ∘ (trajectory O₂ A₂ R₂) := by + ext ω' n a : 3 + simp_rw [Function.comp, f, pullCount, card_filter, sumRewards, trajectory] + rfl + have hf : Measurable f := by + simp_rw [f, measurable_pi_iff] + intro n a + apply Measurable.prod + · dsimp only + exact measurable_sum _ + (fun _ _ ↦ Measurable.ite (by measurability) (by fun_prop) (by fun_prop)) + · dsimp only + exact measurable_sum _ + (fun _ _ ↦ Measurable.ite (by measurability) (by fun_prop) (by fun_prop)) + rw [hc1, hc2] + exact (h1.identDistrib_trajectory h2).comp hf + +lemma identDistrib_pi_pullCount_sumRewards + (h1 : IsAlgEnvSeq O A R alg env P) (h2 : IsAlgEnvSeq O₂ A₂ R₂ alg env P') (n : ℕ) : + IdentDistrib (fun ω a ↦ (pullCount A a n ω, sumRewards A R a n ω)) + (fun ω a ↦ (pullCount A₂ a n ω, sumRewards A₂ R₂ a n ω)) P P' := + (h1.identDistrib_pullCount_sumRewards h2).comp (u := fun f : ℕ → 𝓐 → ℕ × ℝ ↦ f n) + (by fun_prop) + +lemma identDistrib_prodMk_pullCount_sumRewards + (h1 : IsAlgEnvSeq O A R alg env P) (h2 : IsAlgEnvSeq O₂ A₂ R₂ alg env P') (a : 𝓐) (n : ℕ) : + IdentDistrib (fun ω ↦ (pullCount A a n ω, sumRewards A R a n ω)) + (fun ω ↦ (pullCount A₂ a n ω, sumRewards A₂ R₂ a n ω)) P P' := + (h1.identDistrib_pullCount_sumRewards h2).comp (u := fun f : ℕ → 𝓐 → ℕ × ℝ ↦ f n a) + (by fun_prop) + +lemma identDistrib_sumRewards + (h1 : IsAlgEnvSeq O A R alg env P) (h2 : IsAlgEnvSeq O₂ A₂ R₂ alg env P') (a : 𝓐) (n : ℕ) : + IdentDistrib (sumRewards A R a n) (sumRewards A₂ R₂ a n) P P' := + (h1.identDistrib_pullCount_sumRewards h2).comp (u := fun f : ℕ → 𝓐 → ℕ × ℝ ↦ (f n a).2) + (by fun_prop) + +end Learning.IsAlgEnvSeq